blob: d9e501e3bde473af92bd328cde3927a053244b52 [file] [log] [blame]
/*
* ASR SLIC Application
*
* Copyright (C) 2018 ASR Microelectronic Ltd.
*
* Author: Jackie Fan <yuanchunfan@asrmicro.com>
*
* This file contains proprietary information.
* No dissemination allowed without prior written permission from
* ASR Microelectronic Ltd.
*
* File Description:
*
* This file implements SLIC Application, including SLIC interrupt handler and telephony functions
*/
#include <pthread.h>
#include <time.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <mqueue.h>
#include "audio_stub.h"
#include "SLICApp_ubus.h"
#include "SLICApp.h"
#include "si_voice_datatypes.h"
#include "si_voice_ctrl.h"
#include "si_voice_timer_intf.h"
#include "proslic.h"
#include "api_demo.h"
#include "macro.h"
#include "slic_ctrl_server.h"
#include "voice_control.h"
#ifdef SLIC_TONE_FROM_WAV_FILE
#include "SLICApp_tone_wav.h"
#endif
/*****************************************************\
* Monitor PCM clock(PLL, FS, PCLK) for SLIC
\*****************************************************/
#define SLICAPP_MonitorPCM 0 //0: Disable; 1: Enable
#if SLICAPP_MonitorPCM
FILE *fp;
int PCM_ErrCnt = 0;
#define SLICAPP_PCMFILE_NAME "PCMClockLog.txt"
#endif
/*****************************************************\
* Power Management
\*****************************************************/
#define SLICAPP_NAME "proslic" //Used by wake lock
int SLICAPP_PMConstraintWorks;
int modem_is_wb = 0, modem_is_master = 0;
//Used by macro.h
demo_state_t *SLICAPP_pState;
//Used by SLICApp_ubus.c
pthread_mutex_t SLICAPP_mutex;
mqd_t SLICAPP_MSGQueue_ID;
volatile uInt8 SLICAPP_FlashPressed = FALSE;
static SLICAPP_CID_msg_t SLICAPP_CID_msg;
//Used by slic_ctrl_server.c
volatile int g_SLICAPP_Dump_Registers = FALSE;
volatile int g_SLICAPP_Read_Register = FALSE;
volatile int g_SLICAPP_Write_Register = FALSE;
volatile int g_SLICAPP_Cycle_Read_Registers = FALSE;
volatile int g_SLICAPP_Cycle_Write_Register = FALSE;
uInt8 g_SLICAPP_reg_addr = 0;
uInt8 g_SLICAPP_reg_value = 0;
SLICAPP_CS SLICAPP_CallStatus = SLICAPP_CS_IDLE;
static char SLICAPP_call_number[SLICAPP_CALL_NUMBER_MAX_LEN] = {0};
static char SLICAPP_lastcall_number[SLICAPP_CALL_NUMBER_MAX_LEN] = {0};
static int SLICAPP_call_length = 0;
static int SLICAPP_lastcall_length = 0;
static int SLICAPP_Ring_cnt = 0; //Ringing count
static pthread_t SLICAPP_MainLoopTask;
static struct timeval SLICAPP_HookDetectorTimer;
static void SLICAPP_HandleInterrupts(int IRQ_number);
/*****************************************************\
* Call State
* 0: idle
* 1: active
* 2: hold
\*****************************************************/
int SLICAPP_CallIndexState[SLICAPP_CALLMAX];
/*****************************************************\
* SLIC APP max active time(in second), MUST obey:
* 1) SLICAPP_TIMEOUT_MAX > SLICAPP_WAITING_TIMER
* 2) SLICAPP_TIMEOUT_MAX > SLICAPP_DIAL_TIMER
* 3) SLICAPP_TIMEOUT_MAX > SLICAPP_HOWLING_TIMER
\*****************************************************/
#define SLICAPP_TIMEOUT_MAX ((SLICAPP_RING_MAX)*5 + 2)
/*****************************************************\
* Call waiting related definitions
\*****************************************************/
#define SLICAPP_WAITING_TIMER ((SLICAPP_RING_MAX)*5) //hangup waiting call if {SLICAPP_WAITING_TIMER} seconds no key pressed
static timer_t SLICAPP_waiting_timer_id;
/*****************************************************\
* Dial timer related definitions
\*****************************************************/
#define SLICAPP_DIAL_TIMER 5 //dial if no more key pressed within {SLICAPP_DIAL_TIMER} seconds
static timer_t SLICAPP_timer_id;
/*****************************************************\
* Howling related definitions
\*****************************************************/
#define SLICAPP_HOWLING_TIMER ((SLICAPP_RING_MAX)*5) //start howling tone if {SLICAPP_HOWLING_TIMER} seconds after dial tone (no key pressed)
static timer_t SLICAPP_howling_timer_id;
/*****************************************************\
* Choose call waiting tone type
\*****************************************************/
/* Support two types of waiting tone:
* 1) Simple waiting tone:loop as ["du" 0.3s, silent 4s]
* 2) Normal waiting tone:loop as ["du" 0.2s, silent 0.2s-->"du" 0.2s, silent 0.2s--> silent 5s]
*/
//#define SLICAPP_WAITINGTONE_SIMPLE
/*****************************************************\
* Choose call waiting tone generator: SLIC or Modem
\*****************************************************/
/* Support two generators for waiting tone:
* 1) SLIC generate waiting tone
* If SLIC generate waiting tone, there is side effect: due to 2/4 line hybrid echo, far-end could hear waiting tone
* 2) Modem generate waiting tone (Recommended)
* If modem generate waiting tone, modem EC(Echo Cancellor) can remove 2/4 line hybrid echo.
*/
#define MODEM_DTMF_CONTROL_WAITING_TONE
#ifdef MODEM_DTMF_CONTROL_WAITING_TONE
// MODEM generate DTMF tone
#ifdef SLICAPP_WAITINGTONE_SIMPLE
#define SLICAPP_DTMFControl_WaitingTone_interval 300000000 /* 0.3 second interval */
#define SLICAPP_DTMFControl_WaitingTone_PERIOD 14 /* Simple waiting tone[14 times 0.3s]:loop as ["du" 0.3s, silent 4s] */
#else
#define SLICAPP_DTMFControl_WaitingTone_interval 200000000 /* 0.2 second interval */
#define SLICAPP_DTMFControl_WaitingTone_PERIOD 28 /* Normal waiting tone[28 times 0.2s]:loop as ["du" 0.2s, silent 0.2s-->"du" 0.2s, silent 0.2s--> silent 5s] */
#endif
static timer_t SLICAPP_DTMFControl_WaitingTone_timer_id;
static unsigned int SLICAPP_DTMFControl_WaitingTone_count = 0;
static unsigned int SLICAPP_DTMFControl_WaitingTone_Timer_Starting = 0;
static unsigned int tone1_index_used = 0;
static unsigned int tone2_index_used = 0;
#else
// SLIC generate DTMF tone
#ifdef SLICAPP_WAITINGTONE_SIMPLE
#define SLICAPP_WAITINGTONE_ACTIVE 300 // "du" 0.3s
#define SLICAPP_WAITINGTONE_INACTIVE 4000 // silent 4s
#else
#define SLICAPP_WAITINGTONE_TIMER 400000000 // 0.4 second interval
#define SLICAPP_WAITINGTONE_PERIOD 14 // loop period
static timer_t SLICAPP_waitingtone_timer_id;
static unsigned int SLICAPP_waitingtone_count = 0;
#endif //SLICAPP_WAITINGTONE_SIMPLE
#endif //MODEM_DTMF_CONTROL_WAITING_TONE
/*****************************************************\
* Fast dial feature
\*****************************************************/
/* Fast dial: if dial end with '#', SLIC app will dial out immediately(without waiting for timeout)
* 1) 0: diasble fast dial feature
* 2) 1: enable fast dial feature
*/
#define SLICAPP_FAST_DIAL 1
/*****************************************************\
* Refer to External functions
\*****************************************************/
extern char *intMapStrings[];
extern hookChange_Cfg hook_change_cfg;
extern void set_tonegen_osc_timers(demo_state_t *pState, int ton, int toff);
extern void fskSetup(demo_state_t *pState);
extern void sendFSKData(demo_state_t *pState, uInt8 *stream, int preamble_enable);
extern void sendDTMFData(demo_state_t *pState, uInt8 *cptr);
extern void demo_shutdown(demo_port_t *port);
extern demo_port_t *demo_ports;
/*****************************************************\
* CID type setting
*
* Notes:
* DTMF type could not display date & time.
\*****************************************************/
int SLICAPP_CID_Type = SLICAPP_CID_FSK;
/*****************************************************\
* Parameters for dial pulse, flash, and on-hook
*
* Notes:
* 1. minOnHook < maxOnHook < minHookFlash < maxHookFlash < minHook
* 2. minOffHook < maxOffHook < minInterDigit
\*****************************************************/
static hookChange_Cfg SLICAPP_Pulse_Cfg = {
.minOnHook = 20, /**< Min mSec for onhook/break time */
.maxOnHook = 80, /**< Max mSec for onhook/break time */
.minOffHook = 20, /**< Min mSec for offhook/make time */
.maxOffHook = 80, /**< Max mSec for offhook/make time */
.minInterDigit = 90, /**< Minimum interdigit time */
.minHookFlash = 100, /**< minimum hook flash time */
.maxHookFlash = 1100, /**< maximum hook flash time */
.minHook = 1200 /**< Minimum hook time, which should be >> than maxHookFlash */
};
static hookChangeType HookChange_Data =
{
0, //uInt8 currentPulseDigit;
5, //uInt8 last_hook_state;
0, //uInt8 lookingForTimeout;
SI_HC_NO_ACTIVITY, //uInt8 last_state_reported;
0 //void *hookTime; /**< Timestamp for when the onhook detection occurred */
};
const char *SLICAPP_StatusMap[] =
{
"SLICAPP_CS_IDLE", //0,
"SLICAPP_CS_MO_DIALING", //1, /* MO call only */
"SLICAPP_CS_MO_RINGING", //2, /* MO call only */
"SLICAPP_CS_MT_RINGING", //3, /* MT call only */
"SLICAPP_CS_CONNECTED", //4, /* MT/MO call */
"SLICAPP_CS_CONNECTED_DIALING", //5, /* dial in connected */
"SLICAPP_CS_CONNECTED_WAITING", //6, /* call waiting */
"SLICAPP_CS_CONNECTED_CONFERENCE", //7, /* call conference */
};
const char *SLICAPP_ToneMap[] =
{
"TONEGEN_FCC_DIAL", // dial tone
"TONEGEN_FCC_BUSY", // all calls hangup
"TONEGEN_FCC_RINGBACK",
"TONEGEN_FCC_REORDER",
"TONEGEN_FCC_CONGESTION", // howling tone, waiting tone
"TONEGEN_FCC_CAS",
"TONEGEN_FCC_SAS",
"TONEGEN_ETSI_DTAS",
"TONEGEN_1004",
"TONE_LAST_ENUM"
};
const char *SLICAPP_LinefeedMap[] =
{
"LF_OPEN", /**< Open circuit */
"LF_FWD_ACTIVE", /**< Forward active */
"LF_FWD_OHT", /**< Forward active, onhook transmission (used for CID/VMWI) */
"LF_TIP_OPEN", /**< Tip open */
"LF_RINGING", /**< Ringing */
"LF_REV_ACTIVE", /**< Reverse battery/polarity reversed, active */
"LF_REV_OHT", /**< Reverse battery/polarity reversed, active, onhook transmission (used for CID/VMWI) */
"LF_RING_OPEN" /**< Ring open */
};
const char SLICAPP_DTMFMap[16]=
{
'D',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'0',
'*',
'#',
'A',
'B',
'C'
};
/*******************************************************************************\
* Function: SLICAPP_CallActiveCount
* Description: Return active call count.
* Returns: active call count
\*******************************************************************************/
static int SLICAPP_CallActiveCount(void)
{
int i, cnt = 0;
for(i=0; i<SLICAPP_CALLMAX; i++)
{
if(SLICAPP_CallIndexState[i] == SLICAPP_CALLINDEX_ACTIVE)
{
LOG_OUT("%s, active call index=%d\n", __FUNCTION__, i);
cnt++;
}
}
LOG_OUT("%s, active call count=%d\n", __FUNCTION__, cnt);
return cnt;
}
/*******************************************************************************\
* Function: SLICAPP_CallHoldCount
* Description: Return hold call count.
* Returns: hold call count
\*******************************************************************************/
static int SLICAPP_CallHoldCount(void)
{
int i, cnt = 0;
for(i=0; i<SLICAPP_CALLMAX; i++)
{
if(SLICAPP_CallIndexState[i] == SLICAPP_CALLINDEX_HOLD)
{
LOG_OUT("%s, hold call index=%d\n", __FUNCTION__, i);
cnt++;
}
}
LOG_OUT("%s, hold call count=%d\n", __FUNCTION__, cnt);
return cnt;
}
/*******************************************************************************\
* Function: SLICAPP_CallAlertingCount
* Description: Return alerting call count.
* Returns: alerting call count
\*******************************************************************************/
static int SLICAPP_CallAlertingCount(void)
{
int i, cnt = 0;
for(i=0; i<SLICAPP_CALLMAX; i++)
{
if(SLICAPP_CallIndexState[i] == SLICAPP_CALLINDEX_ALERTING)
{
LOG_OUT("%s, alerting call index=%d\n", __FUNCTION__, i);
cnt++;
}
}
LOG_OUT("%s, alerting call count=%d\n", __FUNCTION__, cnt);
return cnt;
}
/*******************************************************************************\
* Function: SLICAPP_CallWaitingCount
* Description: Return waiting call count.
* Returns: waiting call count
\*******************************************************************************/
static int SLICAPP_CallWaitingCount(void)
{
int i, cnt = 0;
for(i=0; i<SLICAPP_CALLMAX; i++)
{
if(SLICAPP_CallIndexState[i] == SLICAPP_CALLINDEX_WAITING)
{
LOG_OUT("%s, waiting call index=%d\n", __FUNCTION__, i);
cnt++;
}
}
LOG_OUT("%s, waiting call count=%d\n", __FUNCTION__, cnt);
return cnt;
}
/*******************************************************************************\
* Function: SLICAPP_CallWaitingIndex
* Description: Return waiting call index.
* Returns: waiting call index
\*******************************************************************************/
static int SLICAPP_CallWaitingIndex(void)
{
int i, index = 0;
for(i=0; i<SLICAPP_CALLMAX; i++)
{
if(SLICAPP_CallIndexState[i] == SLICAPP_CALLINDEX_WAITING)
{
LOG_OUT("%s, waiting call index=%d\n", __FUNCTION__, i);
index = i;
}
}
return index;
}
/*******************************************************************************\
* Function: SLICAPP_HangupAllHoldcalls
* Description: Hangup all hold calls
* Returns: hold call count
\*******************************************************************************/
static int SLICAPP_HangupAllHoldcalls(void)
{
int i, cnt = 0;
for(i=0; i<SLICAPP_CALLMAX; i++)
{
if(SLICAPP_CallIndexState[i] == SLICAPP_CALLINDEX_HOLD)
{
LOG_OUT("%s, Hangup hold call, index=%d\n", __FUNCTION__, i);
SLICAPP_RIL_ATCHLD(i);
cnt++;
}
}
return cnt;
}
/*******************************************************************************\
* Function: SLICAPP_HangupAllActivecalls
* Description: Hangup all active calls
* Returns: active call count
\*******************************************************************************/
static int SLICAPP_HangupAllActivecalls(void)
{
int i, cnt = 0;
for(i=0; i<SLICAPP_CALLMAX; i++)
{
if(SLICAPP_CallIndexState[i] == SLICAPP_CALLINDEX_ACTIVE)
{
LOG_OUT("%s, Hangup active call, index=%d\n", __FUNCTION__, i);
SLICAPP_RIL_ATCHLD(i);
cnt++;
}
}
return cnt;
}
/*******************************************************************************\
* Function: SLICAPP_StartTone
* Description: Start tone.
* mode: tone mode
* enum
* {
* TONEGEN_FCC_DIAL,
* TONEGEN_FCC_BUSY,
* TONEGEN_FCC_RINGBACK,
* TONEGEN_FCC_REORDER,
* TONEGEN_FCC_CONGESTION,
* TONEGEN_FCC_CAS,
* TONEGEN_FCC_SAS,
* TONEGEN_ETSI_DTAS,
* TONEGEN_1004,
* TONE_LAST_ENUM
* };
* timerEn: enable/disable timer
* Returns:
\*******************************************************************************/
static void SLICAPP_StartTone(int mode, int timerEn)
{
LOG_OUT("%s, tone mode=%s\n", __FUNCTION__, SLICAPP_ToneMap[mode]);
#ifdef SLIC_TONE_FROM_WAV_FILE
SLICApp_tone_play_wav_stop();
SLICApp_tone_play_wav_start(mode, 1);
#else
//Setup Tone parameters
ProSLIC_ToneGenSetup(SLICAPP_pState->currentChanPtr, mode);
ProSLIC_ToneGenStart(SLICAPP_pState->currentChanPtr, timerEn);
#endif
}
/*******************************************************************************\
* Function: SLICAPP_StopTone
* Description: Stop tone.
* Returns:
\*******************************************************************************/
static void SLICAPP_StopTone(void)
{
LOG_OUT("%s\n", __FUNCTION__);
#ifdef SLIC_TONE_FROM_WAV_FILE
SLICApp_tone_play_wav_stop();
#else
ProSLIC_ToneGenStop(SLICAPP_pState->currentChanPtr);
#endif
}
/*******************************************************************************\
* Function: SLICAPP_WaitingTimer_Start
* Description: Start waiting timer.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_WaitingTimer_Start(void)
{
int rc = 0;
struct itimerspec ts;
LOG_OUT("%s\n", __FUNCTION__ );
memset (&ts, 0x00, sizeof (struct itimerspec));
ts.it_value.tv_sec = SLICAPP_WAITING_TIMER;
ts.it_value.tv_nsec = 0;
ts.it_interval.tv_sec = 0; //No repeat
ts.it_interval.tv_nsec = 0;
rc = timer_settime(SLICAPP_waiting_timer_id, 0, &ts, NULL);
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_WaitingTimer_Stop
* Description: Stop waiting timer.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_WaitingTimer_Stop(void)
{
int rc = 0;
struct itimerspec ts;
LOG_OUT("%s\n", __FUNCTION__ );
memset (&ts, 0x00, sizeof (struct itimerspec));
ts.it_value.tv_sec = 0;
ts.it_value.tv_nsec = 0;
ts.it_interval.tv_sec = 0; //No repeat
ts.it_interval.tv_nsec = 0;
rc = timer_settime(SLICAPP_waiting_timer_id, 0, &ts, NULL);
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_WaitingTimer_Handler
* Description: Hangup waiting call while waiting timer expired.
* Returns:
\*******************************************************************************/
static void SLICAPP_WaitingTimer_Handler(__attribute__( (unused)) union sigval sv)
{
LOG_OUT("%s,waiting call is time out, hang up call\n", __FUNCTION__);
//hang up waiting call
SLICAPP_RIL_HangupWaitingCall();
//do below steps in RIL callback(SLICAPP_NotifyCallState)
#if 0
SLICAPP_WaitingTimer_Stop();
SLICAPP_StopTone();
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED;
#endif
}
/*******************************************************************************\
* Function: SLICAPP_WaitingTimer_Init
* Description: Init call-waiting timer.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_WaitingTimer_Init(void)
{
int rc = 0;
struct sigevent sigev;
LOG_OUT("%s\n", __FUNCTION__ );
memset (&sigev, 0, sizeof (struct sigevent));
sigev.sigev_value.sival_ptr = &SLICAPP_waiting_timer_id;
sigev.sigev_notify = SIGEV_THREAD;
sigev.sigev_notify_attributes = NULL;
sigev.sigev_notify_function = SLICAPP_WaitingTimer_Handler;
rc = timer_create(CLOCK_REALTIME, &sigev, &SLICAPP_waiting_timer_id);
if (rc == -1)
{
LOG_OUT_E ("Create timer error, exiting service.....");
}
return rc;
}
#ifdef MODEM_DTMF_CONTROL_WAITING_TONE
////////// MODEM generate DTMF tone //////////
/*******************************************************************************\
* Function: SLICAPP_DTMFControl_WaitingTone_Start
* Description: Start DTMF Control timer.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_DTMFControl_WaitingTone_Start(void)
{
int rc = 0;
struct itimerspec ts;
LOG_OUT("%s\n", __FUNCTION__);
SLICAPP_DTMFControl_WaitingTone_count = 0;
SLICAPP_DTMFControl_WaitingTone_Timer_Starting = 1;
memset (&ts, 0x00, sizeof (struct itimerspec));
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = SLICAPP_DTMFControl_WaitingTone_interval;
ts.it_value.tv_sec = 0;
ts.it_value.tv_nsec = 1;/* countdown to invoke callback function */
rc = timer_settime(SLICAPP_DTMFControl_WaitingTone_timer_id, 0, &ts, NULL);
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_DTMFControl_WaitingTone_Stop
* Description: Stop DTMF Control timer.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_DTMFControl_WaitingTone_Stop(void)
{
int rc = 0;
int OnOff = 0;
struct itimerspec ts;
LOG_OUT("%s\n", __FUNCTION__);
//clear the count for timer
SLICAPP_DTMFControl_WaitingTone_count = 0;
SLICAPP_DTMFControl_WaitingTone_Timer_Starting = 0;
memset (&ts, 0x00, sizeof (struct itimerspec));
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 0;
ts.it_value.tv_sec = 0;
ts.it_value.tv_nsec = 0;/* countdown to invoke callback function */
rc = timer_settime(SLICAPP_DTMFControl_WaitingTone_timer_id, 0, &ts, NULL);
SLICAPP_Audio_SwitchDTMFControl(OnOff, tone1_index_used, tone2_index_used);
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_DTMFControl_WaitingTone_Handler
* Description: loop as ["du" 0.2s, silent 0.2s-->"du" 0.2s, silent 0.2s--> silent 5s]
* Returns:
\*******************************************************************************/
static void SLICAPP_DTMFControl_WaitingTone_Handler(__attribute__( (unused)) union sigval sv)
{
LOG_OUT("%s\n", __FUNCTION__);
tone1_index_used = F450;
tone2_index_used = F450;
LOG_OUT("%s,SLICAPP_DTMFControl_WaitingTone_count= %d\n", __FUNCTION__, SLICAPP_DTMFControl_WaitingTone_count);
/* prevent from the handler function is invoked again, after the timer has been stopped */
if(SLICAPP_DTMFControl_WaitingTone_Timer_Starting == 0)
{
LOG_OUT("%s:The timer has been stopped.\n", __FUNCTION__);
return;
}
#ifdef SLICAPP_WAITINGTONE_SIMPLE
switch(SLICAPP_DTMFControl_WaitingTone_count)
{
case 0:
//bit0 for on/off, bit1 for combine(1)/override(0), bit8~15 for gain in db
SLICAPP_Audio_SwitchDTMFControl(3, tone1_index_used, tone2_index_used);/* 'Du' for 0.3s in one loop */
break;
case 1:
SLICAPP_Audio_SwitchDTMFControl(0, tone1_index_used, tone2_index_used);/* No 'Du' for 0.3s in one loop */
break;
default:
/* No 'Du' for 4s in one loop */
break;
}
#else
switch(SLICAPP_DTMFControl_WaitingTone_count)
{
case 0:
case 2:
//bit0 for on/off, bit1 for combine(1)/override(0), bit8~15 for gain in db
SLICAPP_Audio_SwitchDTMFControl(3, tone1_index_used, tone2_index_used);/* 'Du' for 0.2s in one loop */
break;
case 1:
case 3:
SLICAPP_Audio_SwitchDTMFControl(0, tone1_index_used, tone2_index_used);/* No 'Du' for 0.2s in one loop */
break;
default:
/* No 'Du' for 5s in one loop */
break;
}
#endif
SLICAPP_DTMFControl_WaitingTone_count ++;
if (SLICAPP_DTMFControl_WaitingTone_count > SLICAPP_DTMFControl_WaitingTone_PERIOD)
SLICAPP_DTMFControl_WaitingTone_count = 0;
return;
}
/*******************************************************************************\
* Function: SLICAPP_DTMFControl_WaitingTone_Init
* Description: Init DTMFControl timer.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_DTMFControl_WaitingTone_Init(void)
{
int rc = 0;
struct sigevent WaitingTone_sigev;
LOG_OUT("%s\n", __FUNCTION__);
memset (&WaitingTone_sigev, 0x00, sizeof (struct sigevent));
//WaitingTone_sigev.sigev_value.sival_ptr = &SLICAPP_DTMFControl_WaitingTone_timer_id;
WaitingTone_sigev.sigev_notify = SIGEV_THREAD;
//WaitingTone_sigev.sigev_notify_attributes = NULL;
WaitingTone_sigev.sigev_notify_function = SLICAPP_DTMFControl_WaitingTone_Handler;
rc = timer_create(CLOCK_REALTIME, &WaitingTone_sigev, &SLICAPP_DTMFControl_WaitingTone_timer_id);
if (rc == -1)
{
LOG_OUT("Create timer error, exiting service.....");
}
return rc;
}
#else
////////// SLIC generate DTMF tone //////////
#ifndef SLICAPP_WAITINGTONE_SIMPLE
// Only normal tone need timer
/*******************************************************************************\
* Function: SLICAPP_WaitingTone_Handler
* Description: Generate waiting tone.
* Tone sequence: loop as ["du" 0.2s, silent 0.2s-->"du" 0.2s, silent 0.2s--> silent 5s]
* Returns:
\*******************************************************************************/
static void SLICAPP_WaitingTone_Handler(__attribute__( (unused)) union sigval sv)
{
pthread_mutex_lock(&SLICAPP_mutex);
LOG_OUT("%s,SLICAPP_waitingtone_count= %d\n", __FUNCTION__, SLICAPP_waitingtone_count);
switch(SLICAPP_waitingtone_count)
{
case 0:
SLICAPP_StartTone(TONEGEN_FCC_CONGESTION, 1); //call waiting tone
#ifndef SLIC_TONE_FROM_WAV_FILE
set_tonegen_osc_timers(SLICAPP_pState, SLICAPP_WAITINGTONE_TIMER/2000000, SLICAPP_WAITINGTONE_TIMER/2000000);
#endif
break;
case 2:
SLICAPP_StopTone();
break;
default:
break;
}
SLICAPP_waitingtone_count ++;
if (SLICAPP_waitingtone_count > SLICAPP_WAITINGTONE_PERIOD)
SLICAPP_waitingtone_count = 0;
pthread_mutex_unlock(&SLICAPP_mutex);
}
/*******************************************************************************\
* Function: SLICAPP_WaitingTone_Init
* Description: Init call-waiting tone timer.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_WaitingTone_Init(void)
{
int rc = 0;
struct sigevent sigev;
LOG_OUT("%s\n", __FUNCTION__ );
memset (&sigev, 0, sizeof (struct sigevent));
sigev.sigev_value.sival_ptr = &SLICAPP_waitingtone_timer_id;
sigev.sigev_notify = SIGEV_THREAD;
sigev.sigev_notify_attributes = NULL;
sigev.sigev_notify_function = SLICAPP_WaitingTone_Handler;
rc = timer_create(CLOCK_REALTIME, &sigev, &SLICAPP_waitingtone_timer_id);
if (rc == -1)
{
LOG_OUT_E ("Create timer error, exiting service.....");
}
return rc;
}
#endif //#ifndef SLICAPP_WAITINGTONE_SIMPLE
#endif //#ifdef MODEM_DTMF_CONTROL_WAITING_TONE
/*******************************************************************************\
* Function: SLICAPP_WaitingTone_Start
* Description: Start waiting tone.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_WaitingTone_Start(void)
{
int rc = 0;
struct itimerspec ts;
LOG_OUT("%s\n", __FUNCTION__ );
#ifdef MODEM_DTMF_CONTROL_WAITING_TONE
SLICAPP_DTMFControl_WaitingTone_Start();
#else
#ifdef SLICAPP_WAITINGTONE_SIMPLE
// Simple tone
SLICAPP_StartTone(TONEGEN_FCC_CONGESTION, 1);
#ifndef SLIC_TONE_FROM_WAV_FILE
set_tonegen_osc_timers(SLICAPP_pState, SLICAPP_WAITINGTONE_ACTIVE, SLICAPP_WAITINGTONE_INACTIVE);
#endif
#else
// Only normal tone need timer
SLICAPP_waitingtone_count = 0;
ts.it_value.tv_sec = 0;
ts.it_value.tv_nsec = 1; //start tone
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = SLICAPP_WAITINGTONE_TIMER;
rc = timer_settime(SLICAPP_waitingtone_timer_id, 0, &ts, NULL);
#endif
#endif
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_WaitingTone_Stop
* Description: Stop waiting tone.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_WaitingTone_Stop(void)
{
int rc = 0;
struct itimerspec ts;
LOG_OUT("%s\n", __FUNCTION__ );
#ifdef MODEM_DTMF_CONTROL_WAITING_TONE
SLICAPP_DTMFControl_WaitingTone_Stop();
#else
//stop tone
SLICAPP_StopTone();
#ifndef SLICAPP_WAITINGTONE_SIMPLE
//stop timer for waiting tone
ts.it_value.tv_sec = 0;
ts.it_value.tv_nsec = 0;
ts.it_interval.tv_sec = 0; //No repeat
ts.it_interval.tv_nsec = 0;
rc = timer_settime(SLICAPP_waitingtone_timer_id, 0, &ts, NULL);
#endif
#endif
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_RememberCallInfo
* Description: Reset call information.
* Returns:
\*******************************************************************************/
static void SLICAPP_RememberCallInfo(void)
{
//remember as last call number
memcpy(SLICAPP_lastcall_number, SLICAPP_call_number, SLICAPP_call_length);
SLICAPP_lastcall_length = SLICAPP_call_length;
//clear call info
memset(SLICAPP_call_number, 0, SLICAPP_CALL_NUMBER_MAX_LEN);
SLICAPP_call_length = 0;
LOG_OUT("%s\n", __FUNCTION__);
}
/*******************************************************************************\
* Function: SLICAPP_DialTimer_Handler
* Description: Dial phone while dial timer expire.
* Returns:
\*******************************************************************************/
static void SLICAPP_DialTimer_Handler(__attribute__( (unused)) union sigval sv)
{
LOG_OUT("%s, phone number=%s, length=%d\n", __FUNCTION__, SLICAPP_call_number, SLICAPP_call_length );
if(0 != SLICAPP_call_length)
{//Stored DTMF digits
SLICAPP_RIL_ATD(SLICAPP_call_number);
SLICAPP_RememberCallInfo();
if(SLICAPP_CS_CONNECTED_DIALING == SLICAPP_CallStatus)
{
LOG_OUT("%s, SLICAPP_CS_CONNECTED_CONFERENCE\n", __FUNCTION__);
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED_CONFERENCE;
}
}
}
/*******************************************************************************\
* Function: SLICAPP_DialTimer_Start
* Description: Start dial timer.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_DialTimer_Start(void)
{
int rc = 0;
struct itimerspec ts;
LOG_OUT("%s\n", __FUNCTION__ );
memset (&ts, 0x00, sizeof (struct itimerspec));
ts.it_value.tv_sec = SLICAPP_DIAL_TIMER;
ts.it_value.tv_nsec = 0;
ts.it_interval.tv_sec = 0; //No repeat
ts.it_interval.tv_nsec = 0;
rc = timer_settime(SLICAPP_timer_id, 0, &ts, NULL);
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_DialTimer_Stop
* Description: Stop dial timer.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_DialTimer_Stop(void)
{
int rc = 0;
struct itimerspec ts;
LOG_OUT("%s\n", __FUNCTION__ );
memset (&ts, 0x00, sizeof (struct itimerspec));
ts.it_value.tv_sec = 0;
ts.it_value.tv_nsec = 0;
ts.it_interval.tv_sec = 0; //No repeat
ts.it_interval.tv_nsec = 0;
rc = timer_settime(SLICAPP_timer_id, 0, &ts, NULL);
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_DialTimer_Init
* Description: Init dial timer.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_DialTimer_Init(void)
{
int rc = 0;
struct sigevent sigev;
LOG_OUT("%s\n", __FUNCTION__ );
memset (&sigev, 0, sizeof (struct sigevent));
sigev.sigev_value.sival_ptr = &SLICAPP_timer_id;
sigev.sigev_notify = SIGEV_THREAD;
sigev.sigev_notify_attributes = NULL;
sigev.sigev_notify_function = SLICAPP_DialTimer_Handler;
rc = timer_create(CLOCK_REALTIME, &sigev, &SLICAPP_timer_id);
if (rc == -1)
{
LOG_OUT_E ("Create timer error, exiting service.....");
}
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_HowlingTimer_Start
* Description: Start howling timer.
* In dial state, after SLICAPP_HOWLING_TIMER seconds, app will
* 1) if not in call, start howling tone
* 2) if in conference state, stop dial tone
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_HowlingTimer_Start(void)
{
int rc = 0;
struct itimerspec ts;
LOG_OUT("%s\n", __FUNCTION__ );
memset (&ts, 0x00, sizeof (struct itimerspec));
ts.it_value.tv_sec = SLICAPP_HOWLING_TIMER;
ts.it_value.tv_nsec = 0;
ts.it_interval.tv_sec = 0; //No repeat
ts.it_interval.tv_nsec = 0;
rc = timer_settime(SLICAPP_howling_timer_id, 0, &ts, NULL);
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_HowlingTimer_Stop
* Description: Stop howling timer.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_HowlingTimer_Stop(void)
{
int rc = 0;
struct itimerspec ts;
LOG_OUT("%s\n", __FUNCTION__ );
memset (&ts, 0x00, sizeof (struct itimerspec));
ts.it_value.tv_sec = 0;
ts.it_value.tv_nsec = 0;
ts.it_interval.tv_sec = 0; //No repeat
ts.it_interval.tv_nsec = 0;
rc = timer_settime(SLICAPP_howling_timer_id, 0, &ts, NULL);
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_HowlingTimer_Handler
* Description: Handle call status while howling timer expire.
* 1) if not in call, start howling tone, set to idle state
* 2) if in CONNECTED_DIALING state, stop dial tone, resume held call
* Returns:
\*******************************************************************************/
static void SLICAPP_HowlingTimer_Handler(__attribute__( (unused)) union sigval sv)
{
pthread_mutex_lock(&SLICAPP_mutex);
SLICAPP_HowlingTimer_Stop();
if(SLICAPP_CS_MO_DIALING == SLICAPP_CallStatus)
{
LOG_OUT("%s, howling time out, start howling tone\n", __FUNCTION__);
//start howling tone
SLICAPP_StartTone(TONEGEN_FCC_CONGESTION, 1);
SLICAPP_CallStatus = SLICAPP_CS_IDLE;
}
else if(SLICAPP_CS_CONNECTED_DIALING == SLICAPP_CallStatus)
{
LOG_OUT("%s, howling time out, stop dialing new call and resume held call\n", __FUNCTION__);
SLICAPP_StopTone();
//resume held call
SLICAPP_RIL_AcceptWaitingCall();
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED;
}
pthread_mutex_unlock(&SLICAPP_mutex);
}
/*******************************************************************************\
* Function: SLICAPP_Howling Timer_Init
* Description: Init howling timer.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_HowlingTimer_Init(void)
{
int rc = 0;
struct sigevent sigev;
LOG_OUT("%s\n", __FUNCTION__ );
memset (&sigev, 0, sizeof (struct sigevent));
sigev.sigev_value.sival_ptr = &SLICAPP_howling_timer_id;
sigev.sigev_notify = SIGEV_THREAD;
sigev.sigev_notify_attributes = NULL;
sigev.sigev_notify_function = SLICAPP_HowlingTimer_Handler;
rc = timer_create(CLOCK_REALTIME, &sigev, &SLICAPP_howling_timer_id);
if (rc == -1)
{
LOG_OUT_E ("Create timer error, exiting service.....");
}
return rc;
}
/***************************************************************************\
* Free-Run Mode
*
* ProSLIC support low-power mode named as Free-Run mode
* In this mode, PCM bus could be shut down, and ProSLIC PLL will continue to generate
* a nominal internal clock during the absence of PCLK and FSYNC.
* ProSLIC will still generate interrupt like off-hook event.
* This means modem could enter low-power mode when there is no active voice call.
\***************************************************************************/
/*******************************************************************************\
* Function: SLICAPP_FreeRun
* Description: Start/stop SLIC free-run mode.
* SLICAPP_OFF: stop free-run
* SLICAPP_ON: start free-run
* Returns:
\*******************************************************************************/
void SLICAPP_FreeRun(SLICAPP_ONOFF on_off)
{
#ifdef PROSLIC_ENABLEFREERUN
if(SLICAPP_ON == on_off)
{
ProSLIC_PLLFreeRunStart(SLICAPP_pState->currentChanPtr);
}
else
{
ProSLIC_PLLFreeRunStop(SLICAPP_pState->currentChanPtr);
}
LOG_OUT("%s, %s\n", __FUNCTION__, on_off?"on":"off");
#else
LOG_OUT_D("%s, %s, Free-Run Not enabled!!\n", __FUNCTION__, on_off?"on":"off");
#endif
}
/*******************************************************************************\
* Function: SLICAPP_SetPCM
* Description: Turn on/off PCM clock of modem.
* NOTES:
* SLICAPP_OFF/SLICAPP_ON is used to off/on NB PCM, and is used to off/on TX DTMF Detection
* in SLICAPP_SetPCM()
* Returns:
\*******************************************************************************/
void SLICAPP_SetPCM(SLICAPP_ONOFF on_off)
{
#ifdef PROSLIC_ENABLEFREERUN
#if SLICAPP_MonitorPCM
time_t t;
struct tm local;
char DateTime[64] = {0};
//Fill date & time
t = time(NULL);
localtime_r(&t, &local);
snprintf(DateTime, sizeof(DateTime), " PCM clock %s:%4d-%02d-%02d-%02d-%02d\n",on_off?" on":"off",
local.tm_year + 1900, //20XX year
local.tm_mon + 1,
local.tm_mday,
local.tm_hour,
local.tm_min
);
if(fp != NULL)
{
fputs(DateTime, fp);
fflush(fp);
}
#endif
LOG_OUT("%s, %s\n", __FUNCTION__, on_off?"on":"off");
SLICAPP_Audio_SwitchPCM(on_off);
#else
LOG_OUT_D("%s, %s, Free-Run Not enabled!!\n", __FUNCTION__, on_off?"on":"off");
#ifdef SOFTWARE_DTMF_DETECTION
//Enable DSP voice path to detect DTMF
if(on_off)
SLICAPP_Audio_SwitchPCM(on_off);
#endif
#endif
//From MSA 2.157.020, MSA needs {DTMF detection on} to enable GSSP interrupt
SLICAPP_Audio_SwitchDTMFDetection(on_off, 50, 4, 3);
}
/*******************************************************************************\
* Function: SLICAPP_PMConstraintInit
* Description: Init global variable SLICAPP_pmConstraintWorks.
* Returns:
\*******************************************************************************/
static void SLICAPP_PMConstraintInit(void)
{
SLICAPP_PMConstraintWorks = access("/sys/power/wake_lock", R_OK | W_OK);
}
/*******************************************************************************\
* Function: SLICAPP_PMConstraint
* Description: Lock/unlock system power management.
* 0: unlock
* 1: lock
* Returns:
\*******************************************************************************/
static void SLICAPP_PMConstraint(int set)
{
FILE *flk;
char data[64] = {0};
if(SLICAPP_PMConstraintWorks != 0)
return; //wake_lock unavailable or not exist. Do nothing
#ifdef PROSLIC_ENABLEFREERUN
if(set)
{
LOG_OUT_D("%s(%d): no sleep\n", __FUNCTION__, set);
}
else
{
LOG_OUT_D("%s(%d): sleep after %d seconds\n", __FUNCTION__, set, SLICAPP_TIMEOUT_MAX);
}
#else
LOG_OUT_D("%s(%d): free-run is disabled, no sleep\n", __FUNCTION__, set);
#endif
/* Do Not check fopen success. It must be ok, if failed
** (for any reason) better to crash for logging and recovery
*/
flk = fopen("/sys/power/wake_lock", "w");
if(set)
{
fprintf(flk, SLICAPP_NAME);
}
else
{
sprintf(data, "%s %d000000000", SLICAPP_NAME, SLICAPP_TIMEOUT_MAX);
#ifdef PROSLIC_ENABLEFREERUN
/* Clear constraint but with TimeOut enough
** Stay awake for SLICAPP_TIMEOUT_MAX seconds
*/
fprintf(flk, "%s", data/*nsec*/);
#endif
}
fclose(flk);
}
/*****************************************************\
* CID transmission
\*****************************************************/
static void SLICAPP_ConstructCID(uInt8 *dst, SLICAPP_CID_msg_t *src)
{
uInt8 len = 0;
char cid_party_name[] = "CALLING";
dst[len++] = '\x80' ; /* MDMF Type */
dst[len++] = '\x27' ; /* Message Length */
dst[len++] = '\x01' ; /* Date/Time Param */
dst[len++] = '\x08' ; /* 8-byte Date/Time */
LOG_OUT_D("%s: src->DateTime=%s\n", __FUNCTION__, src->DateTime);
memcpy(dst+len, src->DateTime + 4, 8); //Month-Day-Hour-Minute,Do not copy last '\0'
len += 8 ;
dst[len++] = '\x02' ; /* Calling Number Param */
if (0 == strncmp(src->CallerNumber, "86", 2)) {
/* filter "86" from the string of incoming call number */
dst[len++] = src->CallerNumber_Length -2; /* CallerNumber_Length */
memcpy(dst+len, src->CallerNumber+2, src->CallerNumber_Length-2); /* Phone Number */
len += src->CallerNumber_Length-2;
} else {
dst[len++] = src->CallerNumber_Length; /* CallerNumber_Length */
memcpy(dst+len, src->CallerNumber, src->CallerNumber_Length); /* Phone Number */
len += src->CallerNumber_Length;
}
LOG_OUT_D("%s: src->CallerNumber_Length=%d, src->CallerNumber=%s\n", __FUNCTION__, src->CallerNumber_Length, src->CallerNumber);
dst[len++] = '\x07' ; /* Calling Name Param */
dst[len++] = '\x0F' ; /* 15-byte Calling Name */
LOG_OUT_D("%s: src->Name_Length=%d, src->Name=%s\n", __FUNCTION__, src->Name_Length, src->Name);
if (src->Name_Length) {
memcpy(dst+len, src->Name, 0xf);
}
else {
memcpy(dst+len, cid_party_name, sizeof(cid_party_name));
}
len += 0xf;
dst[len++] = '\x00' ; /* Placeholder for Checksum */
dst[len] = '\x00' ; /* Markout */
dst[1] = len-3 ;
LOG_OUT_D("%s done: len = %d\n", __FUNCTION__, len);
}
/*******************************************************************************\
* Function: SLICAPP_SendCID
* Description: Send CID into telephone.
* Returns: 0 on success, -1 means OFFHOOK happened
\*******************************************************************************/
static int SLICAPP_SendCID(demo_state_t *pState, SLICAPP_CID_msg_t *msg)
{
uInt8 cid_msg[100] = {0};
uInt8 reg_tmp, HookStat = PROSLIC_ONHOOK;
int delay_cnt = 0, rc = -1; //default:-1 means OFFHOOK happened
if(SLICAPP_CID_FSK == SLICAPP_CID_Type)
{
/* FSK type */
SLICAPP_ConstructCID(cid_msg, msg);
fskSetup(pState);
}
else
{
/* DTMF type:
** The start code of DTMF caller ID should be 'D' or 'A'.
** The end of it should be 'C'
*/
cid_msg[0]='A';
memcpy(cid_msg + 1, msg->CallerNumber, msg->CallerNumber_Length);
cid_msg[1 + SLICAPP_CID_msg.CallerNumber_Length] = 'C';
}
ProSLIC_RingSetup(pState->currentChanPtr, 0);
/* Disable inactive timer */
reg_tmp=ProSLIC_ReadReg(pState->currentChanPtr, PROSLIC_REG_RINGCON);
ProSLIC_WriteReg(pState->currentChanPtr, PROSLIC_REG_RINGCON, reg_tmp&0xF0);
/* Ensure OFFHOOK Active */
ProSLIC_SetLinefeedStatus(pState->currentChanPtr, LF_FWD_ACTIVE);
Delay(pProTimer, 500);
/*
** User does not know incoming call until 1st Ring.
** So, no need to check hook status here.
*/
/* 1st Ring Burst */
ProSLIC_SetLinefeedStatus(pState->currentChanPtr, LF_RINGING);
//Delay(pProTimer,1000);
for(delay_cnt = 0; delay_cnt < 20; delay_cnt++)
{
Delay(pProTimer, 50);
ProSLIC_ReadHookStatus(pState->currentChanPtr,&HookStat);
if(PROSLIC_OFFHOOK == HookStat)
{
LOG_OUT_D("%s, exit in 1st Ring\n", __FUNCTION__);
goto EXITCID01;
}
}
/* OHT */
ProSLIC_SetLinefeedStatus(pState->currentChanPtr, LF_FWD_OHT);
/*
** CID spec requires delay 500~1500ms.
** But for some telephone models, delay 1500ms will lead to about 1/30 possibility no CID displayed.
*/
//Delay(pProTimer,1000);
for(delay_cnt = 0; delay_cnt < 20; delay_cnt++)
{
Delay(pProTimer, 50);
ProSLIC_ReadHookStatus(pState->currentChanPtr,&HookStat);
if(PROSLIC_OFFHOOK == HookStat)
{
LOG_OUT_D("%s, exit in OHT\n", __FUNCTION__);
goto EXITCID01;
}
}
/* SEND CID HERE */
if(SLICAPP_CID_FSK == SLICAPP_CID_Type)
{
sendFSKData(pState, cid_msg, 1);
}
else
{
sendDTMFData(pState, cid_msg);
}
/*
** 4 seconds no ringing, including:
** 1) Delay 1000ms
** 2) Send CID 1000ms
** 3) Delay 2000ms
*/
//Delay(pProTimer,2000);
for(delay_cnt = 0; delay_cnt < 40; delay_cnt++)
{
Delay(pProTimer, 50);
ProSLIC_ReadHookStatus(pState->currentChanPtr,&HookStat);
if(PROSLIC_OFFHOOK == HookStat)
{
LOG_OUT_D("%s, exit before 2nd Ring\n", __FUNCTION__);
goto EXITCID01;
}
}
/*If reach here, means no OFFHOOK happened */
rc = 0;
EXITCID01:
/* Restore to normal operational mode */
ProSLIC_SetLinefeedStatus(pState->currentChanPtr, LF_FWD_ACTIVE);
/* Enable active Timer, inactive timer */
ProSLIC_WriteReg(pState->currentChanPtr, PROSLIC_REG_RINGCON, reg_tmp|0x18);
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_SendCID_Type2
* Description: Send CID into telephone.
* Returns: 0 on success, -1 on fail
\*******************************************************************************/
static int SLICAPP_SendCID_Type2(demo_state_t *pState, SLICAPP_CID_msg_t *msg)
{
uInt8 cid_msg[100] = {0};
if(SLICAPP_CID_FSK == SLICAPP_CID_Type)
{
/* FSK type */
SLICAPP_ConstructCID(cid_msg, msg);
fskSetup(pState);
}
else
{
LOG_OUT_D("%s, CID type 2 just for FSK\n", __FUNCTION__);
return -1;
}
/* OHT */
ProSLIC_SetLinefeedStatus(pState->currentChanPtr, LF_FWD_OHT);
/* SEND CID HERE */
sendFSKData(pState, cid_msg, 1);
return 0;
}
/*******************************************************************************\
* Function: SLICAPP_SendCIDInterrupt
* Description: Handle off-hook in SLICAPP_SendCID.
* Returns:
\*******************************************************************************/
static void SLICAPP_SendCIDInterrupt(void)
{
int i;
proslicIntType irqs = {0};
ProslicInt arrayIrqs[MAX_PROSLIC_IRQS] = {0};
int intStatus;
//Clear IRQs
irqs.number = 0;
irqs.irqs = arrayIrqs;
for(i = 0; i < MAX_PROSLIC_IRQS; i++)
{
arrayIrqs[i] = 0;
}
intStatus = ProSLIC_GetInterrupts(SLICAPP_pState->currentChanPtr, &irqs);
if(intStatus > 0) /* one or more interrupts are pending */
{
LOG_OUT("-------------------------------------------------------------------------------\n");
SLICAPP_PMConstraint(1);
if(intStatus == RC_REINIT_REQUIRED) /* fatal error due to power/thermal alarm */
{
LOG_OUT("\n\n**** REINIT REQUIRED!!!! ****\n");
ProSLIC_Reinit(&(SLICAPP_pState->currentChanPtr), 1);
/*
** After soft reset, need to
** - reload desired Presets
** - set desired linefeed state
** - reload IRQEN (set as part of general parameters)
*/
ProSLIC_DCFeedSetup(SLICAPP_pState->currentChanPtr, 0);
ProSLIC_RingSetup(SLICAPP_pState->currentChanPtr, 0);
if (modem_is_wb)
ProSLIC_PCMSetup(SLICAPP_pState->currentChanPtr, PCM_16LIN_WB);
else
ProSLIC_PCMSetup(SLICAPP_pState->currentChanPtr, PCM_16LIN);
ProSLIC_ZsynthSetup(SLICAPP_pState->currentChanPtr, 0);
ProSLIC_EnableInterrupts(SLICAPP_pState->currentChanPtr);
}
else /* handle interrupts normally */
{
if(irqs.number > 0)
{
for(i = 0; i < irqs.number; i++)
{
LOG_OUT("No.%d : Interrupt Code -> %d = %s\n", i, irqs.irqs[i], intMapStrings[irqs.irqs[i]]);
SLICAPP_HandleInterrupts(irqs.irqs[i] );
}//for(i...
}//if(irq...
}
}
LOG_OUT("%s, SLICAPP_CallStatus=%s\n", __FUNCTION__, SLICAPP_StatusMap[SLICAPP_CallStatus]);
}
/*******************************************************************************\
* Function: SLICAPP_Ringing
* Description: Handle ringing event(called in main loop).
* Returns:
\*******************************************************************************/
void SLICAPP_Ringing(void)
{
int i = 0, val = 0;
uInt8 data;
/*
In howling state(SLICAPP_CS_IDLE and offhook, should ignore incoming call
*/
if((SLICAPP_CS_IDLE == SLICAPP_CallStatus) && (PROSLIC_ONHOOK == SLICAPP_pState->is_offhook) )
{
//Reset ring count
SLICAPP_Ring_cnt = 0;
//Should not set PCM here, since modem already enable PCM for ringing case
//From MSA 2.157.020, MSA needs {DTMF detection on} to enable GSSP interrupt
SLICAPP_SetPCM(SLICAPP_ON); //call VCM to enable PCM
//wait until PCLK stable
for(i=0; ; i++)
{
data = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_MSTRSTAT);
LOG_OUT_D("%s, PROSLIC_REG_MSTRSTAT=0x%x\n", __FUNCTION__, data);
if(0xb == (data & 0xb))
{//This means PCM bus got stable input from modem
SLICAPP_FreeRun(SLICAPP_OFF);
Delay(pProTimer,20); //Sometimes ProSLIC_RingStart will fail if no delay
//send CID
if(TRUE == SLICAPP_CID_msg.valid)
{
val = SLICAPP_SendCID(SLICAPP_pState, &SLICAPP_CID_msg);
SLICAPP_CID_msg.valid = FALSE; //prevent re-send CID
}
SLICAPP_CallStatus = SLICAPP_CS_MT_RINGING;
if(val == 0)
ProSLIC_RingStart(SLICAPP_pState->currentChanPtr);
else
SLICAPP_SendCIDInterrupt();
break;
}
LOG_OUT_E("%s wait until PCLK stable\n", __FUNCTION__);
/* Delay 1ms */
Delay(pProTimer,1);
}
}
LOG_OUT("%s, SLICAPP_CallStatus=%s\n", __FUNCTION__, SLICAPP_StatusMap[SLICAPP_CallStatus]);
}
/*******************************************************************************\
* Function: SLICAPP_Waiting
* Description: Handle call waiting event(called in main loop).
* Returns:
\*******************************************************************************/
void SLICAPP_Waiting(void)
{
if((SLICAPP_CallStatus == SLICAPP_CS_CONNECTED) || (SLICAPP_CallStatus == SLICAPP_CS_CONNECTED_CONFERENCE) || (SLICAPP_CallStatus == SLICAPP_CS_CONNECTED_WAITING))
{
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED_WAITING;
SLICAPP_StartTone(TONEGEN_FCC_SAS, 0);
Delay(pProTimer, 250);
SLICAPP_StopTone();
Delay(pProTimer, 50);
SLICAPP_StartTone(TONEGEN_FCC_CAS, 0);
Delay(pProTimer, 85);
SLICAPP_StopTone();
Delay(pProTimer, 10);
SLICAPP_WaitingTone_Start();
//Start expire timer for waiting tone
SLICAPP_WaitingTimer_Start();
}
LOG_OUT("%s, SLICAPP_CallStatus=%d(%s)\n", __FUNCTION__, SLICAPP_CallStatus, SLICAPP_StatusMap[SLICAPP_CallStatus]);
}
/*******************************************************************************\
* Function: SLICAPP_Alerting
* Description: Handle RIL alerting notification(called in SLICAPP_uBusInd_RIL).
* Returns:
\*******************************************************************************/
void SLICAPP_Alerting(void)
{
//RIL_CALL_ALERTING may be sent twice by RIL
if(SLICAPP_CS_MO_DIALING == SLICAPP_CallStatus)
{
SLICAPP_CallStatus = SLICAPP_CS_MO_RINGING;
}
LOG_OUT("%s, SLICAPP_CallStatus=%s\n", __FUNCTION__, SLICAPP_StatusMap[SLICAPP_CallStatus]);
}
/*******************************************************************************\
* Function: SLICAPP_Shutdown_PCMBus
* Description: Shut down PCM bus & enter to free-run mode
* Returns:
\*******************************************************************************/
static void SLICAPP_Shutdown_PCMBus(void)
{
int i = 0;
uInt8 data = 0;
LOG_OUT("%s start: %s, SLICAPP_CallStatus=%s\n", __FUNCTION__, SLICAPP_pState->is_offhook?"off-hook":"on-hook", SLICAPP_StatusMap[SLICAPP_CallStatus]);
//Only in idle & on-hook status, could shut down PCM bus
if((1 == SLICAPP_pState->is_offhook)||(SLICAPP_CS_IDLE != SLICAPP_CallStatus))
return;
//wait until PCLK stable
for(i=0; ; i++)
{
data = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_MSTRSTAT);
LOG_OUT_D("%s, PROSLIC_REG_MSTRSTAT=0x%x\n", __FUNCTION__, data);
if(0xb == (data & 0xb))
{//This means PCM bus got stable input from modem
SLICAPP_FreeRun(SLICAPP_ON);
usleep(100000); //delay 100ms to settle down
SLICAPP_SetPCM(SLICAPP_OFF);
break;
}
LOG_OUT_E("%s wait until PCLK stable\n", __FUNCTION__);
/* Delay 1ms */
Delay(pProTimer,1);
}
LOG_OUT("%s done!\n", __FUNCTION__);
}
/*******************************************************************************\
* Function: SLICAPP_ResetCallStatus
* Description: Reset global variables and SLIC linefeed.
* Returns:
\*******************************************************************************/
static void SLICAPP_ResetCallStatus(void)
{
int i;
for(i=0; i<SLICAPP_CALLMAX; i++)
SLICAPP_CallIndexState[i] = SLICAPP_CALLINDEX_IDLE;
SLICAPP_CallStatus = SLICAPP_CS_IDLE;
SLICAPP_Ring_cnt = 0;
SLICAPP_call_length = 0;
memset(&SLICAPP_CID_msg, 0, sizeof(SLICAPP_CID_msg_t));
memset(SLICAPP_call_number, 0, SLICAPP_CALL_NUMBER_MAX_LEN);
SLICAPP_FlashPressed = FALSE;
//Should do this outside
//ProSLIC_SetLinefeedStatus(SLICAPP_pState->currentChanPtr, LF_FWD_ACTIVE);
SLICAPP_DialTimer_Stop();
LOG_OUT("%s done!\n", __FUNCTION__);
}
/*******************************************************************************\
* Function: SLICAPP_DumpStatus
* Description: Dump global variables.
* Returns:
\*******************************************************************************/
void SLICAPP_DumpStatus(void)
{
/*
* Here should not operate SPI(like ProSLIC_ReadReg).
*
* SLICAPP_MainLoop() will access SPI;
* SLICAPP_DumpStatus() may be called in RIL uBus notifications
*
* If here access SPI, may cause SPI access conflict(access SPI at same time)
*/
#if 1
LOG_OUT("~~~~~~~~~~~~~~~~%s, begin~~~~~~~~~~~~~~~~\n", __FUNCTION__);
LOG_OUT("SLICAPP_CallStatus=%s, SLICAPP_Ring_cnt=%d\n", SLICAPP_StatusMap[SLICAPP_CallStatus], SLICAPP_Ring_cnt);
LOG_OUT("~~~~~~~~~~~~~~~~%s, end~~~~~~~~~~~~~~~~\n", __FUNCTION__);
#else
uInt8 lf = 0;
lf = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_LINEFEED);
LOG_OUT("~~~~~~~~~~~~~~~~%s, begin~~~~~~~~~~~~~~~~\n", __FUNCTION__);
LOG_OUT("SLICAPP_CallStatus=%s, SLICAPP_Ring_cnt=%d\n", SLICAPP_StatusMap[SLICAPP_CallStatus], SLICAPP_Ring_cnt);
LOG_OUT("SLICAPP_Linefeed:0x%x(%s), SLICAPP_CallStatus=%d(%s)\n", lf, SLICAPP_LinefeedMap[(lf & 0x70)>>4], SLICAPP_CallStatus, SLICAPP_StatusMap[SLICAPP_CallStatus]);
LOG_OUT("~~~~~~~~~~~~~~~~%s, end~~~~~~~~~~~~~~~~\n", __FUNCTION__);
#endif
}
/*******************************************************************************\
* Function: SLICAPP_NotifyCallState
* Description: Handle RIL notification about call state(called in main loop).
* 0: call disconnected
* 1: call connected
* Returns:
\*******************************************************************************/
void SLICAPP_NotifyCallState (uInt8 State)
{
int active_cnt = 0, hold_cnt = 0, alerting_cnt = 0, waiting_cnt = 0;
LOG_OUT("%s, State=%d, SLICAPP_CallStatus=%s, %s\n", __FUNCTION__, State, SLICAPP_StatusMap[SLICAPP_CallStatus], SLICAPP_pState->is_offhook?"off-hook":"on-hook");
if((SLICAPP_pState->is_offhook == PROSLIC_ONHOOK) && (SLICAPP_CallStatus == SLICAPP_CS_IDLE))
{
LOG_OUT("%s, do nothing due to on-hook & SLICAPP_CS_IDLE!!\n", __FUNCTION__);
return;
}
active_cnt = SLICAPP_CallActiveCount();
hold_cnt = SLICAPP_CallHoldCount();
alerting_cnt = SLICAPP_CallAlertingCount();
waiting_cnt = SLICAPP_CallWaitingCount();
LOG_OUT("%s, active_cnt=%d, hold_cnt=%d, alerting_cnt=%d, waiting_cnt=%d\n", __FUNCTION__, active_cnt, hold_cnt, alerting_cnt, waiting_cnt);
if(1 == State)
{
if((SLICAPP_CS_MO_DIALING == SLICAPP_CallStatus)||(SLICAPP_CS_MO_RINGING == SLICAPP_CallStatus))
{
LOG_OUT("%s, SLICAPP_CS_CONNECTED\n", __FUNCTION__);
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED;
}
}
else
{
if(SLICAPP_CS_MT_RINGING == SLICAPP_CallStatus)
{//Far-end hangup while local is ringing
SLICAPP_ResetCallStatus();
ProSLIC_RingStop(SLICAPP_pState->currentChanPtr);
SLICAPP_Shutdown_PCMBus();
}
/* Comment below code,2020-0323
else if(SLICAPP_CS_CONNECTED >= SLICAPP_CallStatus)
Reason: avoid TONEGEN_FCC_BUSY in howling tone state
*/
else if((SLICAPP_CS_CONNECTED >= SLICAPP_CallStatus) && (SLICAPP_CS_IDLE < SLICAPP_CallStatus))
{//Far-end hangup while call is connected or in dialing phase(network in busy,pls dial later...)
if((active_cnt == 0) && (hold_cnt == 0) && (waiting_cnt == 0))
{//All calls hangup
SLICAPP_ResetCallStatus();
SLICAPP_StartTone(TONEGEN_FCC_BUSY, 1);
}
}
else if(SLICAPP_CS_CONNECTED_WAITING == SLICAPP_CallStatus)
{//Far-end hangup in call waiting state, or flash+0 to reject incoming 2nd call
if((hold_cnt == 0) && (waiting_cnt != 0))
{//case: 1st call(in active) drop while 2nd call is waiting==>do nothing
}
else if((hold_cnt > 0) && (active_cnt == 0))
{//case: 2nd call(incoming call) drop while 1st call is hold==>auto restore 1st call
SLICAPP_WaitingTone_Stop(); //stop waiting tone
SLICAPP_WaitingTimer_Stop(); //stop timer
SLICAPP_RIL_AcceptWaitingCall();
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED;
}
else if((hold_cnt == 0) && (active_cnt > 0))
{//case: reject incoming call while 1st call is active==>just set to SLICAPP_CS_CONNECTED
SLICAPP_WaitingTone_Stop(); //stop waiting tone
SLICAPP_WaitingTimer_Stop(); //stop timer
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED;
}
else if((hold_cnt == 0) && (active_cnt == 0) && (waiting_cnt == 0))
{//All calls hangup
SLICAPP_WaitingTone_Stop(); //stop waiting tone
SLICAPP_WaitingTimer_Stop(); //stop timer
SLICAPP_ResetCallStatus();
SLICAPP_StartTone(TONEGEN_FCC_BUSY, 1);
}
}
else if(SLICAPP_CS_CONNECTED_DIALING == SLICAPP_CallStatus)
{//Far-end hangup before dialing 2nd number
//Actually in SLICAPP_CS_CONNECTED_DIALING state, alerting_cnt MUST be 0
if(alerting_cnt == 0)
{
if((hold_cnt == 0) && (active_cnt == 0))
{
//Just left this dialing, no more other calls
SLICAPP_CallStatus = SLICAPP_CS_MO_DIALING;
}
}
}
else if(SLICAPP_CS_CONNECTED_CONFERENCE == SLICAPP_CallStatus)
{//Far-end hangup after dialing 2nd number
if(alerting_cnt == 0)
{
/* If 2nd number drops(Alerting voice:is busy, pls dial later),
the alerting will last 1 minute.
If SLIC does not hookflash in this 1 minute and 2nd disconnected notification comes here,
we should resume the call on hold.
*/
if(hold_cnt > 0)
{
SLICAPP_RIL_AcceptWaitingCall();
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED;
}
else if(active_cnt > 0)
{//Active call(s)
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED;
}
else
{
//All calls hangup
SLICAPP_ResetCallStatus();
SLICAPP_StartTone(TONEGEN_FCC_BUSY, 1);
}
}
else
{
if((hold_cnt == 0) && (active_cnt == 0))
{
//Just left this alerting, no more other calls
SLICAPP_CallStatus = SLICAPP_CS_MO_RINGING;
}
}
}
}
}
/*******************************************************************************\
* Function: SLICAPP_Dump_IRQEN
* Description: Dump IRQEN registers.
* Returns:
\*******************************************************************************/
static void SLICAPP_Dump_IRQEN(void)
{
uInt8 IRQEN1 = 0, IRQEN2 = 0, IRQEN3 = 0, IRQEN4 = 0;
IRQEN1 = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_IRQEN1);
IRQEN2 = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_IRQEN2);
IRQEN3 = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_IRQEN3);
IRQEN4 = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_IRQEN4);
LOG_OUT_D("%s,IRQEN1=0x%x, IRQEN2=0x%x, IRQEN3=0x%x, IRQEN4=0x%x\n", __FUNCTION__, IRQEN1, IRQEN2, IRQEN3, IRQEN4);
}
/*******************************************************************************\
* Function: SLICAPP_IRQ_LOOP
* Description: Handle on-hook/off-hook detected.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_IRQ_LOOP(void)
{
int i = 0, rc = 0;
uInt8 reg = 0;
uInt8 HookStat = PROSLIC_ONHOOK;
LOG_OUT("Enter %s, Old:%s, SLICAPP_CallStatus=%s\n", __FUNCTION__, SLICAPP_pState->is_offhook?"off-hook":"on-hook", SLICAPP_StatusMap[SLICAPP_CallStatus]);
if(SLICAPP_CS_MT_RINGING == SLICAPP_CallStatus)
{//MT starting
ProSLIC_RingStop(SLICAPP_pState->currentChanPtr);
}
#if 1
ProSLIC_ReadHookStatus(SLICAPP_pState->currentChanPtr,&HookStat);
if((PROSLIC_OFFHOOK == HookStat) && (PROSLIC_ONHOOK == SLICAPP_pState->is_offhook))
{//Fast set as offhook event, to avoid polling in ProSLIC_HookChangeDetect()
rc = SI_HC_OFFHOOK_TIMEOUT;
LOG_OUT("%s, Fast set as SI_HC_OFFHOOK_TIMEOUT\n ", __FUNCTION__);
}
else
{
MORE_POLLs:
rc = ProSLIC_HookChangeDetect(SLICAPP_pState->currentChanPtr, &SLICAPP_Pulse_Cfg, &HookChange_Data);
}
if( SI_HC_NEED_MORE_POLLS == rc)
{
goto MORE_POLLs;
}
else
{
switch(rc)
{
case SI_HC_HOOKFLASH:
LOG_OUT("%s, SI_HC_HOOKFLASH\n ", __FUNCTION__);
break;
case SI_HC_ONHOOK_TIMEOUT:
LOG_OUT("%s, SI_HC_ONHOOK_TIMEOUT\n ", __FUNCTION__);
break;
case SI_HC_OFFHOOK_TIMEOUT:
LOG_OUT("%s, SI_HC_OFFHOOK_TIMEOUT\n ", __FUNCTION__);
break;
case SI_HC_NO_ACTIVITY:
LOG_OUT("%s, SI_HC_NO_ACTIVITY\n ", __FUNCTION__);
break;
default:
LOG_OUT("%s, Unsupported event:0x%x\n ", __FUNCTION__, rc);
break;
}
}
#endif
if(SI_HC_HOOKFLASH == rc)
{//hook-flash handler
if(SLICAPP_CS_CONNECTED == SLICAPP_CallStatus)
{//Phase 4: Press hook-flash during call
LOG_OUT("%s, flash , start dialing new call\n", __FUNCTION__);
//place current call into hold
SLICAPP_RIL_SwitchWaitingcall();
//start dial tone
SLICAPP_StartTone(TONEGEN_FCC_DIAL, 0);
/* start howling timer:
If no key pressed after SLICAPP_HOWLING_TIMER seconds:
stop dial tone, and resume held call
*/
SLICAPP_HowlingTimer_Start();
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED_DIALING;
}
else if(SLICAPP_CS_CONNECTED_DIALING == SLICAPP_CallStatus)
{
LOG_OUT("%s, flash again, stop dialing new call\n", __FUNCTION__);
//resume held call
SLICAPP_RIL_AcceptWaitingCall();
//stop dialing
SLICAPP_StopTone();
SLICAPP_DialTimer_Stop();
SLICAPP_HowlingTimer_Stop();
memset(SLICAPP_call_number, 0, SLICAPP_CALL_NUMBER_MAX_LEN);
SLICAPP_call_length = 0;
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED;
}
else if((SLICAPP_CS_CONNECTED_WAITING == SLICAPP_CallStatus)||(SLICAPP_CS_CONNECTED_CONFERENCE == SLICAPP_CallStatus))
{
SLICAPP_FlashPressed = TRUE; //could press '1' or '3' key to choose switch/conference operation
LOG_OUT("%s: Set SLICAPP_FlashPressed=TRUE while in call waiting or conference state\n", __FUNCTION__);
}
else if(SLICAPP_CS_MO_DIALING == SLICAPP_CallStatus)
{
/* For some telephone type:
In SLICAPP_CS_MO_DIALING state, fast onhook+offhook will trigger flash+offhook interrupt.
Here just reset call number,start dial tone,reset howling timer.
*/
SLICAPP_call_length = 0;
memset(SLICAPP_call_number, 0, SLICAPP_CALL_NUMBER_MAX_LEN);
SLICAPP_StartTone(TONEGEN_FCC_DIAL, 0); //Start dial tone
SLICAPP_HowlingTimer_Start(); //Reset howling timer
}
}
else if(SI_HC_ONHOOK_TIMEOUT == rc)
{//On-hook
SLICAPP_pState->is_offhook = PROSLIC_ONHOOK;
switch(SLICAPP_CallStatus)
{
case SLICAPP_CS_IDLE:
SLICAPP_StopTone();
break;
case SLICAPP_CS_CONNECTED_WAITING:
LOG_OUT("%s, on-hook detected, stop waiting tone and send ATCHLD to RIL\n", __FUNCTION__);
SLICAPP_WaitingTone_Stop(); //stop waiting tone
SLICAPP_WaitingTimer_Stop(); //stop timer
SLICAPP_RIL_HangupAll();
break;
case SLICAPP_CS_CONNECTED:
case SLICAPP_CS_CONNECTED_DIALING:
case SLICAPP_CS_CONNECTED_CONFERENCE:
LOG_OUT("%s, on-hook detected, send ATCHLD to RIL\n", __FUNCTION__);
SLICAPP_RIL_HangupAll();
break;
case SLICAPP_CS_MO_RINGING:
LOG_OUT("%s, on-hook detected, send ATCHLD to RIL\n", __FUNCTION__);
SLICAPP_RIL_HangupAll();
SLICAPP_StopTone(); //stop ringing tone
break;
case SLICAPP_CS_MO_DIALING:
LOG_OUT("%s, on-hook detected, send ATCHLD to RIL\n", __FUNCTION__);
SLICAPP_RIL_HangupAll();
SLICAPP_StopTone(); //stop dial tone
/* Sometimes on-hook when ril postpone to send alerting,
but at this time, moden voice path is already turned on;
So, here should shut down PCM clock.
*/
usleep(600000); //delay 600ms to wait modem voice path stopped.
break;
default:
break;
}
SLICAPP_ResetCallStatus();
ProSLIC_SetLinefeedStatus(SLICAPP_pState->currentChanPtr, LF_FWD_ACTIVE);
SLICAPP_Shutdown_PCMBus();
}
else if(SI_HC_OFFHOOK_TIMEOUT == rc)
{//Off-hook
SLICAPP_pState->is_offhook = PROSLIC_OFFHOOK;
if(SLICAPP_CS_MT_RINGING == SLICAPP_CallStatus)
{//MT starting
ProSLIC_RingStop(SLICAPP_pState->currentChanPtr);
SLICAPP_RIL_ATA();
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED;
}
else if(SLICAPP_CS_IDLE == SLICAPP_CallStatus)
{//Ready for MO
SLICAPP_SetPCM(SLICAPP_ON); //call VCM to enable PCM
/* Delay 200ms, ensure PCM clock stable */
usleep(200000);
//wait until PCLK stable
for(i=0; ; i++)
{
reg = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_MSTRSTAT);
if(0xb == (reg & 0xb))
{//This means PCM bus got stable input from modem
SLICAPP_FreeRun(SLICAPP_OFF);
usleep(20000); /* settle */
ProSLIC_SetLinefeedStatus(SLICAPP_pState->currentChanPtr, LF_FWD_ACTIVE);
usleep(20000); /* settle */
break;
}
LOG_OUT_E("%s wait until PCLK stable\n", __FUNCTION__);
/* Delay 1ms */
Delay(pProTimer,1);
}
SLICAPP_StartTone(TONEGEN_FCC_DIAL, 0); //start dial tone
SLICAPP_CallStatus = SLICAPP_CS_MO_DIALING;
/* start howling timer:
If no key pressed after SLICAPP_HOWLING_TIMER seconds:
stop dial tone & start howling tone
*/
SLICAPP_HowlingTimer_Start();
}
}//off-hook
LOG_OUT("Leave %s, New:%s, SLICAPP_CallStatus=%s\n", __FUNCTION__, SLICAPP_pState->is_offhook?"off-hook":"on-hook", SLICAPP_StatusMap[SLICAPP_CallStatus]);
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_IRQ_RING_TRIP
* Description: Handle ring trip detected.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_IRQ_RING_TRIP(void)
{
int rc = 0;
uInt8 bRTP = 0;
LOG_OUT("%s\n", __FUNCTION__);
bRTP = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_LCRRTP) & 1;
if(0x1 == bRTP)
{//Ring-Trip detected
//ProSLIC_DisableCID(SLICAPP_pState->currentChanPtr);
}
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_Handle_DTMF
* Description: Handle DTMF code.
*
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_Handle_DTMF(char DTMFchar)
{
int rc = 0, active_cnt = 0, hold_cnt = 0, waiting_cnt = 0;
active_cnt = SLICAPP_CallActiveCount();
hold_cnt = SLICAPP_CallHoldCount();
waiting_cnt = SLICAPP_CallWaitingCount();
LOG_OUT("%s, DTMFchar=%c, SLICAPP_CallStatus=%s, active_cnt=%d, hold_cnt=%d, waiting_cnt=%d\n", __FUNCTION__, DTMFchar, SLICAPP_StatusMap[SLICAPP_CallStatus], active_cnt, hold_cnt, waiting_cnt);
if(TRUE == SLICAPP_FlashPressed)
{//hook-flash handler
/* After flash is pressed, three further operations supported:
* 1) press 0
* reject incoming call(if there is incoming call), or
* hangup active call & accept hold call
* 2) press 1
* switch to incoming/hold call
* 3) press 3
* conference all calls
*/
/* Press 0: reject incoming call/hangup active call
*
*/
if(DTMFchar == '0')
{
if((waiting_cnt != 0) && (SLICAPP_CS_CONNECTED_WAITING == SLICAPP_CallStatus))
{ //reject incoming call
SLICAPP_WaitingTone_Stop(); //stop waiting tone
SLICAPP_WaitingTimer_Stop(); //stop timer
SLICAPP_RIL_ATCHLD(SLICAPP_CallWaitingIndex());
}
else if((hold_cnt != 0) && ((SLICAPP_CS_CONNECTED_WAITING == SLICAPP_CallStatus)||(SLICAPP_CS_CONNECTED_CONFERENCE == SLICAPP_CallStatus)))
{ //hangup active call & accept hold call
SLICAPP_HangupAllActivecalls();
SLICAPP_RIL_SwitchWaitingcall();
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED;
}
}
/* Press 1: switch to incoming/hold call
*
* switch to incoming call
* or, switch to on-hold call(SLICAPP_CS_CONNECTED_CONFERENCE)
*/
if((DTMFchar == '1') && ((SLICAPP_CS_CONNECTED_CONFERENCE == SLICAPP_CallStatus)||(SLICAPP_CS_CONNECTED_WAITING == SLICAPP_CallStatus)))
{
if(SLICAPP_CS_CONNECTED_WAITING == SLICAPP_CallStatus)
{
SLICAPP_WaitingTone_Stop(); //stop waiting tone
SLICAPP_WaitingTimer_Stop(); //stop timer
}
if((hold_cnt != 0) && (waiting_cnt != 0))
{
/* If there is an incoming call, while already exist 1 held call and 1 active call:
* Press 1 will:
* 1) hangup held call {AT+CHLD=1x}
* 2) accept incoming call and place active call into held {AT+CHLD=2}
*/
SLICAPP_HangupAllHoldcalls();
SLICAPP_RIL_SwitchWaitingcall();
}
else
{
SLICAPP_RIL_SwitchWaitingcall();
}
if(active_cnt == 0)
{
/* Special Case: call 1st drop while call 2nd is waiting
*
* If we hookflash to accept call 2nd at this time, should reset status into SLICAPP_CS_CONNECTED
*/
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED;
}
}
/* Press 3: conference all calls, only valid when press '3' with hold call exists
*
* 1) Pick up phone handset (causing the line to be off-hook).
* 2) Hear a dial tone
* 3) Dial the first number and greet the first party
* 4) Press the hook flash button (or quickly tap the on-hook sensor on the phone)
* 5) Hear a stutter dial tone (a series of beeps followed by another dial tone)
* 6) Dial the second number and greet the second party
* 7) Press the hook flash button again.
*/
if((DTMFchar == '3') && (hold_cnt != 0) && ((SLICAPP_CS_CONNECTED_CONFERENCE == SLICAPP_CallStatus)||(SLICAPP_CS_CONNECTED_WAITING == SLICAPP_CallStatus)))
{//Phase 7
if(SLICAPP_CS_CONNECTED_WAITING == SLICAPP_CallStatus)
{
SLICAPP_WaitingTone_Stop(); //stop waiting tone
SLICAPP_WaitingTimer_Stop(); //stop timer
}
SLICAPP_RIL_ConferenceCall();
if(active_cnt == 0)
{
/* If 2nd number drops(Alerting voice:is busy, pls dial later),the alerting will last 1 minute.
If SLIC want to switch to 1st number, hookflash here, try to accept 1st number,
but {AT+CHLD=1} will be rejected in SAC, so actually SLICAPP_RIL_AcceptWaitingCall() could not work.
*/
//SLICAPP_RIL_AcceptWaitingCall();
}
else
{
/* If active_cnt!=0 , it means 2nd number is connected,
If hookflash here, will conference the calls.
*/
SLICAPP_CallStatus = SLICAPP_CS_CONNECTED;
}
}
SLICAPP_FlashPressed = FALSE;
return rc; /* MUST return here */
}
if((DTMFchar == 'D' || DTMFchar == 'A') && (SLICAPP_CS_CONNECTED_WAITING == SLICAPP_CallStatus))
{
//Send type 2 CID
if(TRUE == SLICAPP_CID_msg.valid)
{
SLICAPP_SendCID_Type2(SLICAPP_pState, &SLICAPP_CID_msg);
SLICAPP_CID_msg.valid = FALSE; //prevent re-send CID
return 0;
}
}
if((SLICAPP_CS_CONNECTED == SLICAPP_CallStatus)||(SLICAPP_CS_CONNECTED_WAITING == SLICAPP_CallStatus))
{//Press button during call
SLICAPP_RIL_ATDTMF(DTMFchar); //send AT+VTS=<DTMFchar>
}
else if((SLICAPP_CS_MO_DIALING == SLICAPP_CallStatus)||(SLICAPP_CS_CONNECTED_DIALING == SLICAPP_CallStatus))
{
if(SLICAPP_CALL_NUMBER_MAX_LEN-1 > SLICAPP_call_length)
{
if (DTMFchar >= '0' && DTMFchar <= '9')
{
SLICAPP_call_number[SLICAPP_call_length] = DTMFchar;
SLICAPP_call_length++;
LOG_OUT("%s, SLICAPP_CallStatus=%s, SLICAPP_call_length=%d\n", __FUNCTION__, SLICAPP_StatusMap[SLICAPP_CallStatus], SLICAPP_call_length);
if(1 == SLICAPP_call_length)
{
SLICAPP_StopTone(); //stop dial tone
SLICAPP_HowlingTimer_Stop(); //stop howling timer once key pressed
}
SLICAPP_DialTimer_Start(); //When button pressed, re-start dial timer every time
}
#if SLICAPP_FAST_DIAL
else if (DTMFchar == '#')
{
if (SLICAPP_call_length >= 1)
{
SLICAPP_DialTimer_Stop();
SLICAPP_DialTimer_Handler((union sigval)0);
}
}
#endif
}
}
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_IRQ_DTMF
* Description: Handle DTMF code detected by SLIC.
*
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_IRQ_DTMF(void)
{
uInt8 rawcode = 0;
char DTMFchar;
ProSLIC_DTMFReadDigit(SLICAPP_pState->currentChanPtr, &rawcode);
DTMFchar = SLICAPP_DTMFMap[rawcode];
SLICAPP_Handle_DTMF(DTMFchar);
return 0;
}
/*******************************************************************************\
* Function: SLICAPP_IRQ_RING_T1
* Description: Handle ringing active timer expired.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_IRQ_RING_T1(void)
{
int rc = 0;
uInt8 lf = 0;
SLICAPP_Ring_cnt++;
lf = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_LINEFEED);
LOG_OUT("%s, SLICAPP_Ring_cnt=%d, lf=%s\n", __FUNCTION__, SLICAPP_Ring_cnt, SLICAPP_LinefeedMap[(lf & 0x70)>>4]);
//if reach SLICAPP_RING_MAX, means should hang up call
if(SLICAPP_RING_MAX == SLICAPP_Ring_cnt)
{
//send ATCHLD to RIL
SLICAPP_RIL_HangupAll();
SLICAPP_ResetCallStatus();
ProSLIC_SetLinefeedStatus(SLICAPP_pState->currentChanPtr, LF_FWD_ACTIVE);
SLICAPP_Shutdown_PCMBus();
}
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_IRQ_RING_T2
* Description: Handle ringing inactive timer expired.
* Returns: 0 on success
\*******************************************************************************/
static int SLICAPP_IRQ_RING_T2(void)
{
int rc = 0;
uInt8 lf = 0;
lf = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_LINEFEED);
LOG_OUT_D("%s,lf=%s, nothing is done here!\n", __FUNCTION__, SLICAPP_LinefeedMap[(lf & 0x70)>>4]);
return rc;
}
/*******************************************************************************\
* Function: SLICAPP_HandleInterrupts
* Description: Handled SLIC interrupts.
* IRQ_number: IRQ number to be handled
* Returns:
\*******************************************************************************/
static void SLICAPP_HandleInterrupts(int IRQ_number)
{
int rc = 0;
uInt8 lf = 0;
lf = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_LINEFEED);
LOG_OUT_D("%s, linefeed=0x%x(%s)\n", __FUNCTION__, lf, SLICAPP_LinefeedMap[(lf & 0x70)>>4]);
switch(IRQ_number)
{
case IRQ_LOOP_STATUS:
rc=SLICAPP_IRQ_LOOP();
SLICAPP_DumpStatus();
break;
case IRQ_RING_TRIP:
rc=SLICAPP_IRQ_RING_TRIP();
break;
case IRQ_DTMF:
#ifdef SOFTWARE_DTMF_DETECTION
LOG_OUT("SOFTWARE_DTMF_DETECTION is defined, bypass DTMF detected by SLIC\n");
#else
rc=SLICAPP_IRQ_DTMF();
#endif
break;
case IRQ_RING_T1:
rc=SLICAPP_IRQ_RING_T1();
break;
case IRQ_RING_T2:
rc=SLICAPP_IRQ_RING_T2();
break;
default:
LOG_OUT_D("Unsupported IRQ:%s\n", intMapStrings[IRQ_number]);
SLICAPP_Dump_IRQEN();
break;
}
LOG_OUT("IRQ Handled , rc=0x%x\n", rc);
}
static void SLICAPP_Dump_Registers(void)
{
uInt8 reg = 0;
int i = 0;
for (i=0; i<128; i++)
{
reg = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, i);
LOG_OUT("%s: [%d]=0x%02x!\n", __FUNCTION__, i, reg);
}
return;
}
static void SLICAPP_Read_Register(void)
{
uInt8 reg = 0;
reg = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, g_SLICAPP_reg_addr);
LOG_OUT("%s: [%d]=0x%02x!\n", __FUNCTION__, g_SLICAPP_reg_addr, reg);
return;
}
static void SLICAPP_Write_Register(void)
{
ProSLIC_WriteReg(SLICAPP_pState->currentChanPtr, g_SLICAPP_reg_addr, g_SLICAPP_reg_value);
LOG_OUT("%s: [%d]=0x%02x!\n", __FUNCTION__, g_SLICAPP_reg_addr, g_SLICAPP_reg_value);
return;
}
/*******************************************************************************\
* Function: SLICAPP_MainLoop
* Description: Main loop of SLICAPP.
* Returns:
\*******************************************************************************/
static void SLICAPP_MainLoop(void)
{
int rc = 0, i = 0, poll_interval = 20; /* decrease to 20ms, due to no conflict in SPI access */
proslicIntType irqs = {0};
ProslicInt arrayIrqs[MAX_PROSLIC_IRQS] = {0};
int intStatus;
SLICAPP_MSG_t message = {0};
#if SLICAPP_MonitorPCM
uInt8 data;
time_t t;
struct tm local;
char DateTime[64] = {0};
#endif
irqs.irqs = arrayIrqs;
while(1)
{
Delay(pProTimer,poll_interval);
if(g_SLICAPP_Dump_Registers == TRUE)
{
//control from marvell/lte-telephony/apps/diag/slic_ctrl_client.c
pthread_mutex_lock(&SLICAPP_mutex);
LOG_OUT("----------------------------------Dump_Registers----------------------------------\n");
SLICAPP_Dump_Registers();
g_SLICAPP_Dump_Registers = FALSE;
LOG_OUT("-------------------------------------------------------------------------------\n\n");
pthread_mutex_unlock(&SLICAPP_mutex);
}
if(g_SLICAPP_Read_Register == TRUE)
{
//control from marvell/lte-telephony/apps/diag/slic_ctrl_client.c
pthread_mutex_lock(&SLICAPP_mutex);
LOG_OUT("----------------------------------Read_Register----------------------------------\n");
SLICAPP_Read_Register();
g_SLICAPP_Read_Register = FALSE;
LOG_OUT("-------------------------------------------------------------------------------\n\n");
pthread_mutex_unlock(&SLICAPP_mutex);
}
if(g_SLICAPP_Write_Register == TRUE)
{
//control from marvell/lte-telephony/apps/diag/slic_ctrl_client.c
pthread_mutex_lock(&SLICAPP_mutex);
LOG_OUT("----------------------------------Write_Register----------------------------------\n");
SLICAPP_Write_Register();
g_SLICAPP_Write_Register = FALSE;
LOG_OUT("-------------------------------------------------------------------------------\n\n");
pthread_mutex_unlock(&SLICAPP_mutex);
}
if(g_SLICAPP_Cycle_Read_Registers == TRUE)
{
//control from marvell/lte-telephony/apps/diag/slic_ctrl_client.c
pthread_mutex_lock(&SLICAPP_mutex);
LOG_OUT("----------------------------------Cycle_Read_Register----------------------------------\n");
SLICAPP_Read_Register();
LOG_OUT("-------------------------------------------------------------------------------\n\n");
pthread_mutex_unlock(&SLICAPP_mutex);
}
if(g_SLICAPP_Cycle_Write_Register == TRUE)
{
//control from marvell/lte-telephony/apps/diag/slic_ctrl_client.c
pthread_mutex_lock(&SLICAPP_mutex);
LOG_OUT("----------------------------------Cycle_Write_Register----------------------------------\n");
SLICAPP_Write_Register();
LOG_OUT("-------------------------------------------------------------------------------\n\n");
pthread_mutex_unlock(&SLICAPP_mutex);
}
//Handle RIL & audio_if message queue, created in NONBLOCK style
rc = mq_receive(SLICAPP_MSGQueue_ID, (char *)&message, sizeof(message), 0);
if (rc >= 0) {
//Lock from Ril handler (SLICAPP_uBusInd_RIL)
pthread_mutex_lock(&SLICAPP_mutex);
SLICAPP_PMConstraint(1);
switch(message.id) {
case SLICAPP_AUDIOIF_DTMF:
LOG_OUT("----------------------------------SLICAPP_Handle_DTMF : Begin----------------------------------");
SLICAPP_Handle_DTMF(message.data[0]);
LOG_OUT("----------------------------------SLICAPP_Handle_DTMF : End----------------------------------");
break;
case SLICAPP_RIL_STARTRINGING:
LOG_OUT("----------------------------------SLICAPP_Ringing : Begin----------------------------------");
memcpy(&SLICAPP_CID_msg, message.data, SLICAPP_MSGSIZE);
SLICAPP_Ringing();
LOG_OUT("----------------------------------SLICAPP_Ringing : End----------------------------------");
break;
case SLICAPP_RIL_CALLWAITING:
LOG_OUT("----------------------------------SLICAPP_Waiting : Begin----------------------------------");
memcpy(&SLICAPP_CID_msg, message.data, SLICAPP_MSGSIZE);
SLICAPP_Waiting();
LOG_OUT("----------------------------------SLICAPP_Waiting : End----------------------------------");
break;
case SLICAPP_RIL_CALLNOTIFY:
LOG_OUT("----------------------------------SLICAPP_NotifyCallState : Begin----------------------------------");
SLICAPP_NotifyCallState(message.data[0]);
LOG_OUT("----------------------------------SLICAPP_NotifyCallState : End----------------------------------");
break;
default:
LOG_OUT_D("%s: Unsupported message id=%d.\n", __FUNCTION__, message.id);
break;
}
//Unlock from Ril handler (SLICAPP_uBusInd_RIL)
SLICAPP_PMConstraint(0);
pthread_mutex_unlock(&SLICAPP_mutex);
}
#if SLICAPP_MonitorPCM
//Read PLL, FS, PCLK status
data = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_MSTRSTAT);
if((data & 0xE0) != 0)
{
LOG_OUT_D("%s, PROSLIC_REG_MSTRSTAT=0x%x, PROSLIC_REG_MSTREN=0x%x\n", __FUNCTION__, data, ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_MSTREN));
ProSLIC_WriteReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_MSTRSTAT, data&0xE0);
//Fill date & time
t = time(NULL);
localtime_r(&t, &local);
snprintf(DateTime, sizeof(DateTime), " PCM clock log:%4d-%02d-%02d-%02d-%02d, MSTRSTAT=0x%x\n",
local.tm_year + 1900, //20XX year
local.tm_mon + 1,
local.tm_mday,
local.tm_hour,
local.tm_min,
data
);
if(fp != NULL)
{
fputs(DateTime, fp);
fflush(fp);
}
}
#endif
//Lock from Ril handler (SLICAPP_uBusInd_RIL)
pthread_mutex_lock(&SLICAPP_mutex);
//Clear IRQs
irqs.number = 0;
irqs.irqs = arrayIrqs;
for(i = 0; i < MAX_PROSLIC_IRQS; i++)
{
arrayIrqs[i] = 0;
}
intStatus = ProSLIC_GetInterrupts(SLICAPP_pState->currentChanPtr, &irqs);
if(intStatus > 0) /* one or more interrupts are pending */
{
SLICAPP_PMConstraint(1);
LOG_OUT("----------------------------------SLICAPP_HandleInterrupts : Begin----------------------------------");
if(intStatus == RC_REINIT_REQUIRED) /* fatal error due to power/thermal alarm */
{
LOG_OUT("\n\n**** REINIT REQUIRED!!!! ****\n");
ProSLIC_Reinit(&(SLICAPP_pState->currentChanPtr), 1);
/*
** After soft reset, need to
** - reload desired Presets
** - set desired linefeed state
** - reload IRQEN (set as part of general parameters)
*/
ProSLIC_DCFeedSetup(SLICAPP_pState->currentChanPtr, 0);
ProSLIC_RingSetup(SLICAPP_pState->currentChanPtr, 0);
if (modem_is_wb)
ProSLIC_PCMSetup(SLICAPP_pState->currentChanPtr, PCM_16LIN_WB);
else
ProSLIC_PCMSetup(SLICAPP_pState->currentChanPtr, PCM_16LIN);
ProSLIC_ZsynthSetup(SLICAPP_pState->currentChanPtr, 0);
ProSLIC_EnableInterrupts(SLICAPP_pState->currentChanPtr);
}
else /* handle interrupts normally */
{
if(irqs.number > 0)
{
for(i = 0; i < irqs.number; i++)
{
LOG_OUT("No.%d : Interrupt Code -> %d = %s\n", i, irqs.irqs[i], intMapStrings[irqs.irqs[i]]);
SLICAPP_HandleInterrupts(irqs.irqs[i] );
}//for(i...
}//if(irq...
}
LOG_OUT("----------------------------------SLICAPP_HandleInterrupts : End----------------------------------");
SLICAPP_PMConstraint(0);
}
//Unlock from Ril handler (SLICAPP_uBusInd_RIL)
pthread_mutex_unlock(&SLICAPP_mutex);
}//While(1)
}
/*******************************************************************************\
* Function: SLICAPP_ConfigSLIC
* Description: Setup SLIC parameters besides SLIC demo code.
* It will be called in SLICAPP_Main()
* Returns:
\*******************************************************************************/
static void SLICAPP_ConfigSLIC(void)
{
uInt8 data;
#if SLICAPP_MonitorPCM
time_t t;
struct tm local;
char DateTime[64] = {0};
#endif
//Init hook-detect timer
ProSLIC_InitializeHookChangeDetect(&HookChange_Data, &SLICAPP_HookDetectorTimer);
LOG_OUT("MSTREN=0x%x\n", ProSLIC_ReadReg( SLICAPP_pState->currentChanPtr, PROSLIC_REG_MSTREN));
LOG_OUT("MSTRSTAT=0x%x\n", ProSLIC_ReadReg( SLICAPP_pState->currentChanPtr, PROSLIC_REG_MSTRSTAT));
#if SLICAPP_MonitorPCM
//Fill date & time
t = time(NULL);
localtime_r(&t, &local);
snprintf(DateTime, sizeof(DateTime), "Proslic boot time:%4d-%02d-%02d-%02d-%02d\n",
local.tm_year + 1900, //20XX year
local.tm_mon + 1,
local.tm_mday,
local.tm_hour,
local.tm_min
);
fp = fopen(SLICAPP_PCMFILE_NAME, "w");
if(fp == NULL)
{
LOG_OUT_D("%s, Error in create %s!\n", __FUNCTION__, SLICAPP_PCMFILE_NAME);
}
else
{
fputs("\n\n----------------------------------------\n", fp);
fputs("Proslic PCM clock log\n----------------------------------------\n", fp);
fputs(DateTime, fp);
fflush(fp);
}
//Enable PLL, FS, PCLK interrupts
data = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_MSTREN);
ProSLIC_WriteReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_MSTREN, data|0xE0);
LOG_OUT_D("%s, PROSLIC_REG_MSTREN: old=0x%x, new=0x%x\n", __FUNCTION__, data, ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_MSTREN));
#endif
//Enable Active Timer, inactive timer
data = ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_RINGCON);
ProSLIC_WriteReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_RINGCON, data|0x18);
LOG_OUT_D("%s, PROSLIC_REG_RINGCON: old=0x%x, new=0x%x\n", __FUNCTION__, data, ProSLIC_ReadReg(SLICAPP_pState->currentChanPtr, PROSLIC_REG_RINGCON));
/*
** Jackie Fan, 2018-05-16
**
** If enable below code: after reboot, sometimes(about 1/10 possibility) SLIC
** could not detect key-press(key 1,4,7,*)
*/
#if 0
//Configure PCM
ProSLIC_PCMSetup(SLICAPP_pState->currentChanPtr, PCM_16LIN);
ProSLIC_PCMTimeSlotSetup(SLICAPP_pState->currentChanPtr, 1, 1); //1826 MSA use 1 bit offset for both Rx & Tx PCM data
#endif
ProSLIC_PCMStart(SLICAPP_pState->currentChanPtr);
}
/*******************************************************************************\
* Function: SLICAPP_Main
* Description: Main entry of SLICAPP.
* It will be called in API_Demo(), api_demo.c
* Returns:
\*******************************************************************************/
void SLICAPP_Main()
{
pthread_attr_t tattr;
//Configure time zone, needed by localtime_r()
tzset();
SLICAPP_ConfigSLIC();
//Init timers
if(SLICAPP_DialTimer_Init() == -1) return;
if(SLICAPP_WaitingTimer_Init() == -1) return;
if(SLICAPP_HowlingTimer_Init() == -1) return;
#ifdef MODEM_DTMF_CONTROL_WAITING_TONE
if(SLICAPP_DTMFControl_WaitingTone_Init() == -1) return;
#else
#ifndef SLICAPP_WAITINGTONE_SIMPLE
// Only normal tone need timer
if(SLICAPP_WaitingTone_Init() == -1) return;
#endif
#endif
SLICAPP_ResetCallStatus();
SLICAPP_Shutdown_PCMBus();
/*Create mutex for Ril and interrupt handlers */
pthread_mutex_init(&SLICAPP_mutex, NULL);
/*Create thread to poll interrupts*/
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
pthread_create(&SLICAPP_MainLoopTask, &tattr, (void *)SLICAPP_MainLoop, NULL);
slic_ctrl_server_IPC();
SLICAPP_uBusRun();
/* It will get here only if uloop stopped in SLICAPP_uBusRun()*/
//Destroy mutex
pthread_mutex_destroy(&SLICAPP_mutex);
//Cancel pooling thread
pthread_cancel(SLICAPP_MainLoopTask);
//Delete timers
timer_delete(SLICAPP_timer_id);
timer_delete(SLICAPP_waiting_timer_id);
timer_delete(SLICAPP_howling_timer_id);
}
void SLICAPP_GetPCMCfg(void)
{
int ret = 0;
int err, ioctl_fd, status = 0;
/*
* From audio_stub, get the properties of nb/wb, master/slave
*/
ioctl_fd = open("/dev/audiostub_ctl", O_RDONLY);
if (ioctl_fd < 0) {
err = errno;
LOG_OUT("failed to open audiostub_ctl:%s\n", strerror(err));
return;
}
ret = ioctl(ioctl_fd, AUDIOSTUB_GET_STATUS, &status);
if (ret < 0) {
LOG_OUT( "Warning, audio_stub ioctl error: %s", strerror(errno));
}
modem_is_wb = IS_WB(status);
modem_is_master = IS_PCM_MASTER(status);
LOG_OUT("%s/L%d: modem_is_wb=%d, modem_is_master=%d", __FUNCTION__, __LINE__, modem_is_wb, modem_is_master);
if (!modem_is_master) {
LOG_OUT_E( "Warning, Modem should be Master, Please check it!!!");
}
//close the file after got status report
close(ioctl_fd);
return;
}
static void SLICAPP_Signal_Handler(int signal)
{
int i, ret = 0;
LOG_OUT("stopping proslic, signal=%d\n", signal);
#if SLICAPP_MonitorPCM
if(fp != NULL)
fclose(fp);
#endif
ret = mq_close(SLICAPP_MSGQueue_ID);
if (ret < 0) {
LOG_OUT_E("%s: mq_close fail, rc = 0x%x\n", __FUNCTION__, ret);
}
for(i = 0; i < DEMO_PORT_COUNT; i++)
{
if(NULL != &demo_ports[i])
demo_shutdown(&demo_ports[i]);
}
/* Call VCM to turn off PCM clock */
SLICAPP_Audio_SwitchPCM(SLICAPP_OFF_WITHOUT_SLIC);
SLICAPP_Audio_SwitchDTMFDetection(DTMF_DETECTION_TX_OFF, 50, 4, 3);
LOG_OUT("close PCM.\n");
/* Delay 1s, ensure that above messages are transmitted to CP */
usleep(1000000);
exit(0);
}
/*******************************************************************************\
* Function: main
* Description: Main function of this APP.
* It will call API_Demo() which init SLIC chip and call SLICAPP_Main()
* Returns: 0 on success
\*******************************************************************************/
int main (int argc ,char *argv[])
{
int ret = 0;
UNUSEDPARAM(argc);
UNUSEDPARAM(argv);
set_service_log_tag("proslic");
LOG_OUT("starting proslic\n");
/* Install signal handler */
signal(SIGINT, SLICAPP_Signal_Handler);
signal(SIGTERM, SLICAPP_Signal_Handler);
SLICAPP_PMConstraintInit();
/* SLICAPP_uBusInit might need much time */
SLICAPP_PMConstraint(1);
/*Init ubus server*/
if(SLICAPP_uBusInit())
return -1;
SLICAPP_PMConstraint(0);
SLICAPP_GetPCMCfg();
/* Boot phase:
* 1) Turn on PCM clock
* 2) Don't turn on DSP voice path(SLICAPP_Audio_SwitchDTMFDetection)
*/
SLICAPP_Audio_SwitchPCM(SLICAPP_ON);
/* Delay 200ms, ensure PCM clock stable */
usleep(200000);
LOG_OUT("open PCM.\n");
ret = API_Demo();
LOG_OUT("API_Demo():%d\n", ret);
/* Exit app */
SLICAPP_Signal_Handler(0);
return 0;
}