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