2012-12-17 20:15:23 -05:00

577 lines
16 KiB
C
Executable File

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "cpr.h"
#include "cpr_in.h"
#include "cpr_stdlib.h"
#include "cpr_ipc.h"
#include "phntask.h"
#include <stdarg.h>
#include "configmgr.h"
#include "debug.h"
#include "config.h"
#include "vcm.h"
#include "dialplan.h"
#include "debug.h"
#include "phone_debug.h"
#include "CCProvider.h"
#include "ccsip_task.h"
#include "gsm.h"
#include "misc_apps_task.h"
#include "plat_api.h"
#include "ccapp_task.h"
#include "phone_platform_constants.h"
/** The following defines are used to tune the total memory that pSIPCC
* allocates and uses. */
/** Block size for emulated heap space, i.e. 1kB */
#define BLK_SZ 1024
/** 5 MB Heap Based on 0.5 MB initial use + 4 MB for calls (20K * 200) + 0.5 MB misc */
/** The number of supported blocks for the emulated heap space */
#define MEM_BASE_BLK 500 //500 blocks, ~ 0.5M
#define MEM_MISC_BLK 500 //500 blocks, ~ 0.5M
/** Size of the emulated heap space. This is the value passed to the memory
* management pre-init procedure. The total memory allocated is
* "PRIVATE_SYS_MEM_SIZE + 2*64" where the additional numbers are for a gaurd
* band. */
#define MEM_PER_CALL_BLK 20 //20 block, ~20k
#define PRIVATE_SYS_MEM_SIZE ((MEM_BASE_BLK + MEM_MISC_BLK + (MEM_PER_CALL_BLK) * MAX_CALLS) * BLK_SZ)
// used in early init code where config has not been setup
const boolean gHardCodeSDPMode = TRUE;
boolean gStopTickTask = FALSE;
/*--------------------------------------------------------------------------
* Local definitions
*--------------------------------------------------------------------------
*/
#define GSMSTKSZ 61440
/*
* CNU thread queue sizes.
*
* On CNU, the message queue size can hold up to 31 entries only.
* This is too small for a phone that can support the MAX_CALLS that
* is close to or higher than 31 calls simultaneously. In a scenario when
* the number of active calls on the phone reaches its MAC_CALLS then
* there can be a potential MAX_CALLS that is great ther than 31 events on
* a queue to GSM or SIP thread.
*
* One known scenario is a 7970 phone having 50 held calls where all
* calls are not from the same CCM that this phone registers with but
* still within the same cluster. If that CCM is restarted, the CCM that
* this phone registers with will terminate these calls on the phone by
* sending BYEs, SUBSCRIBE (to terminate) DTMF digi collection and etc. to
* all these calls very quickly together. Handling these SIP messages
* can generate many internal events between SIP and GSM threads including
* events that are sent to self (such as GSM which includes applications
* that runs as part of GSM). The amount of the events posted on the queues
* during this time can be far exceeding than 31 and MAX_CALLS entries.
*
* The followings define queue sizes for GSM, SIP and the other threads.
* The GSM's queue size is defined to be larger than SIP's queue size to
* account for self sending event. The formular below is based on the
* testing with the above scenario and with 8-3-x phone load. The maximum
* queue depth observed for GSM under
* this condition is 129 entries and the maximum queue depth of
* SIP under the same condition is about 67 entries. Therefore, the queue
* depth of GSM thread is given to 3 times MAX_CALLS (or 153) and
* 2 times (or 102) for SIP thread for 7970 case.
*
*/
#define GSMQSZ (MAX_CALLS*3) /* GSM message queue size */
#define SIPQSZ (MAX_CALLS*2) /* SIP message queue size */
#define DEFQSZ 0 /* default message queue size */
#define DEFAPPQSZ MAX_REG_LINES
/*--------------------------------------------------------------------------
* Global data
*--------------------------------------------------------------------------
*/
cprMsgQueue_t ccapp_msgq;
cprThread_t ccapp_thread;
cprMsgQueue_t sip_msgq;
cprThread_t sip_thread;
#ifdef NO_SOCKET_POLLING
cprThread_t sip_msgqwait_thread;
#endif
cprMsgQueue_t gsm_msgq;
cprThread_t gsm_thread;
cprMsgQueue_t misc_app_msgq;
cprThread_t misc_app_thread;
#ifdef JINDO_DEBUG_SUPPORTED
cprMsgQueue_t debug_msgq;
cprThread_t debug_thread;
#endif
#ifdef EXTERNAL_TICK_REQUIRED
cprMsgQueue_t ticker_msgq;
cprThread_t ticker_thread;
#endif
/* Platform initialized flag */
boolean platform_initialized = FALSE;
static int thread_init(void);
/*--------------------------------------------------------------------------
* External data references
* -------------------------------------------------------------------------
*/
/*--------------------------------------------------------------------------
* External function prototypes
*--------------------------------------------------------------------------
*/
extern void gsm_set_initialized(void);
extern void vcm_init(void);
extern void dp_init(void *);
extern cprBuffer_t SIPTaskGetBuffer(uint16_t size);
extern void sip_platform_task_loop(void *arg);
#ifdef NO_SOCKET_POLLING
extern void sip_platform_task_msgqwait(void *arg);
#endif
extern void GSMTask(void *);
#ifndef VENDOR_BUILD
extern void debug_task(void *);
#endif
extern void MiscAppTask(void *);
extern void cpr_timer_tick(void);
extern void cprTimerSystemInit(void);
extern int32_t ui_clear_mwi(int32_t argc, const char *argv[]);
void gsm_shutdown(void);
void dp_shutdown(void);
void MiscAppTaskShutdown(void);
void CCAppShutdown(void);
cprBuffer_t gsm_get_buffer (uint16_t size);
/*--------------------------------------------------------------------------
* Local scope function prototypes
*--------------------------------------------------------------------------
*/
#ifdef EXTERNAL_TICK_REQUIRED
int TickerTask(void *);
#endif
void send_protocol_config_msg(void);
/**
* ccMemInit()
*/
extern
int ccMemInit(size_t size) {
return CPR_SUCCESS;
}
/**
* ccPreInit
*
* Initialization routine to call before any application level
* code initializes.
*
* Parameters: None
*
* Return Value: CPR_SUCCESS or CPR_FAILURE
*/
int
ccPreInit ()
{
static boolean ccPreInit_called = FALSE;
if (ccPreInit_called == FALSE) {
ccPreInit_called = TRUE;
//Initializes the memory first
ccMemInit(PRIVATE_SYS_MEM_SIZE);
cprPreInit();
}
return CPR_SUCCESS;
}
int
ccInit ()
{
TNP_DEBUG(DEB_F_PREFIX"started init of SIP call control\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, "ccInit"));
platInit();
strlib_init();
/*
* below should move to cprPreInit. keep it here until then
*/
#ifdef _WIN32
cprTimerSystemInit();
#endif
/* Initialize threads, queues etc. */
(void) thread_init();
platform_initialized = TRUE;
return 0;
}
static int
thread_init ()
{
gStopTickTask = FALSE;
/*
* This will have already been called for CPR CNU code,
* but may be called here for Windows emulation.
*/
(void) cprPreInit();
PHNChangeState(STATE_FILE_CFG);
/* initialize message queues */
sip_msgq = cprCreateMessageQueue("SIPQ", SIPQSZ);
gsm_msgq = cprCreateMessageQueue("GSMQ", GSMQSZ);
if (FALSE == gHardCodeSDPMode) {
misc_app_msgq = cprCreateMessageQueue("MISCAPPQ", DEFQSZ);
}
ccapp_msgq = cprCreateMessageQueue("CCAPPQ", DEFQSZ);
#ifdef JINDO_DEBUG_SUPPORTED
debug_msgq = cprCreateMessageQueue("DEBUGAPPQ", DEFQSZ);
#endif
#ifdef EXTERNAL_TICK_REQUIRED
ticker_msgq = cprCreateMessageQueue("Ticker", DEFQSZ);
#endif
/*
* Initialize the command parser and debug infrastructure
*/
debugInit();
/* create threads */
ccapp_thread = cprCreateThread("CCAPP Task",
(cprThreadStartRoutine) CCApp_task,
GSMSTKSZ, CCPROVIDER_THREAD_RELATIVE_PRIORITY /* pri */, ccapp_msgq);
if (ccapp_thread == NULL) {
err_msg("failed to create CCAPP task \n");
}
#ifdef JINDO_DEBUG_SUPPORTED
#ifndef VENDOR_BUILD
debug_thread = cprCreateThread("Debug Task",
(cprThreadStartRoutine) debug_task, STKSZ,
0 /*pri */ , debug_msgq);
if (debug_thread == NULL) {
err_msg("failed to create debug task\n");
}
#endif
#endif
/* SIP main thread */
sip_thread = cprCreateThread("SIPStack task",
(cprThreadStartRoutine) sip_platform_task_loop,
STKSZ, SIP_THREAD_RELATIVE_PRIORITY /* pri */, sip_msgq);
if (sip_thread == NULL) {
err_msg("failed to create sip task \n");
}
#ifdef NO_SOCKET_POLLING
/* SIP message wait queue task */
sip_msgqwait_thread = cprCreateThread("SIP MsgQueueWait task",
(cprThreadStartRoutine)
sip_platform_task_msgqwait,
STKSZ, SIP_THREAD_RELATIVE_PRIORITY /* pri */, sip_msgq);
if (sip_msgqwait_thread == NULL) {
err_msg("failed to create sip message queue wait task\n");
}
#endif
gsm_thread = cprCreateThread("GSM Task",
(cprThreadStartRoutine) GSMTask,
GSMSTKSZ, GSM_THREAD_RELATIVE_PRIORITY /* pri */, gsm_msgq);
if (gsm_thread == NULL) {
err_msg("failed to create gsm task \n");
}
if (FALSE == gHardCodeSDPMode) {
misc_app_thread = cprCreateThread("MiscApp Task",
(cprThreadStartRoutine) MiscAppTask,
STKSZ, 0 /* pri */, misc_app_msgq);
if (misc_app_thread == NULL) {
err_msg("failed to create MiscApp task \n");
}
}
#ifdef EXTERNAL_TICK_REQUIRED
ticker_thread = cprCreateThread("Ticker task",
(cprThreadStartRoutine) TickerTask,
STKSZ, 0, ticker_msgq);
if (ticker_thread == NULL) {
err_msg("failed to create ticker task \n");
}
#endif
/* Associate the threads with the message queues */
(void) cprSetMessageQueueThread(sip_msgq, sip_thread);
(void) cprSetMessageQueueThread(gsm_msgq, gsm_thread);
if (FALSE == gHardCodeSDPMode) {
(void) cprSetMessageQueueThread(misc_app_msgq, misc_app_thread);
}
(void) cprSetMessageQueueThread(ccapp_msgq, ccapp_thread);
#ifdef JINDO_DEBUG_SUPPORTED
(void) cprSetMessageQueueThread(debug_msgq, debug_thread);
#endif
#ifdef EXTERNAL_TICK_REQUIRED
(void) cprSetMessageQueueThread(ticker_msgq, ticker_thread);
#endif
/*
* initialize debugs of other modules.
*
* dp_init needs the gsm_msgq id. This
* is set in a global variable by the
* GSM task running. However due to timing
* issues dp_init is sometimes run before
* the GSM task has set this variable resulting
* in a NULL msgqueue ptr being passed to CPR
* which returns an error and does not create
* the dialplan timer. Thus pass is the same
* data to dp_init that is passed into the
* cprCreateThread call for GSM above.
*/
config_init();
vcmInit();
dp_init(gsm_msgq);
if (sip_minimum_config_check() != 0) {
PHNChangeState(STATE_UNPROVISIONED);
} else {
PHNChangeState(STATE_CONNECTED);
}
(void) cprPostInit();
if ( vcmGetVideoCodecList(VCM_DSP_FULLDUPLEX) ) {
cc_media_update_native_video_support(TRUE);
}
return (0);
}
#ifdef EXTERNAL_TICK_REQUIRED
uint16_t SecTimer = 50;
unsigned long timeofday_in_seconds = 0;
void
MAIN0Timer (void)
{
if (SecTimer-- == 0) {
SecTimer = 50;
timeofday_in_seconds++;
}
//gtick +=2;
cpr_timer_tick();
}
int
TickerTask (void *a)
{
TNP_DEBUG(DEB_F_PREFIX"Ticker Task initialized..\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, "TickerTask"));
while (FALSE == gStopTickTask) {
cprSleep(20);
MAIN0Timer();
}
return 0;
}
#endif
void
send_protocol_config_msg (void)
{
const char *fname = "send_protocol_config_msg";
char *msg;
TNP_DEBUG(DEB_F_PREFIX"send TCP_DONE message to sip thread..\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname));
msg = (char *) SIPTaskGetBuffer(4);
if (msg == NULL) {
TNP_DEBUG(DEB_F_PREFIX"failed to allocate message..\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname));
return;
}
/* send a config done message to the SIP Task */
if (SIPTaskSendMsg(TCP_PHN_CFG_TCP_DONE, msg, 0, NULL) == CPR_FAILURE) {
err_msg("%s: notify SIP stack ready failed", fname);
cpr_free(msg);
}
gsm_set_initialized();
PHNChangeState(STATE_CONNECTED);
}
/*
* Function: send_task_unload_msg
*
* Description:
* - send shutdown and thread destroy msg to sip, gsm, ccapp, misc
* threads
* Parameters: destination thread
*
* Returns: none
*
*/
void
send_task_unload_msg(cc_srcs_t dest_id)
{
const char *fname = "send_task_unload_msg";
uint16_t len = 4;
cprBuffer_t msg = gsm_get_buffer(len);
int sdpmode = 0;
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
if (msg == NULL) {
err_msg("%s: failed to allocate msg cprBuffer_t\n", fname);
return;
}
DEF_DEBUG(DEB_F_PREFIX"send Unload message to %s task ..\n",
DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname),
dest_id == CC_SRC_SIP ? "SIP" :
dest_id == CC_SRC_GSM ? "GSM" :
dest_id == CC_SRC_MISC_APP ? "Misc App" :
dest_id == CC_SRC_CCAPP ? "CCApp" : "Unknown");
switch(dest_id) {
case CC_SRC_SIP:
{
/* send this msg so phone can send unRegister msg */
SIPTaskPostShutdown(SIP_EXTERNAL, CC_CAUSE_SHUTDOWN, "");
/* allow unRegister msg to sent out and shutdown to complete */
if (!sdpmode) {
cprSleep(2000);
}
/* send a unload message to the SIP Task to kill sip thread*/
msg = SIPTaskGetBuffer(len);
if (msg == NULL) {
err_msg("%s:%d: failed to allocate sip msg buffer\n", fname);
return;
}
if (SIPTaskSendMsg(THREAD_UNLOAD, (cprBuffer_t)msg, len, NULL) == CPR_FAILURE)
{
cpr_free(msg);
err_msg("%s: Unable to send THREAD_UNLOAD msg to sip thread", fname);
}
}
break;
case CC_SRC_GSM:
{
msg = gsm_get_buffer(len);
if (msg == NULL) {
err_msg("%s: failed to allocate gsm msg cprBuffer_t\n", fname);
return;
}
if (CPR_FAILURE == gsm_send_msg(THREAD_UNLOAD, msg, len)) {
err_msg("%s: Unable to send THREAD_UNLOAD msg to gsm thread", fname);
}
}
break;
case CC_SRC_MISC_APP:
{
msg = cpr_malloc(len);
if (msg == NULL) {
err_msg("%s: failed to allocate misc msg cprBuffer_t\n", fname);
return;
}
if (CPR_FAILURE == MiscAppTaskSendMsg(THREAD_UNLOAD, msg, len)) {
err_msg("%s: Unable to send THREAD_UNLOAD msg to Misc App thread", fname);
}
}
break;
case CC_SRC_CCAPP:
{
msg = cpr_malloc(len);
if (msg == NULL) {
err_msg("%s: failed to allocate ccapp msg cprBuffer_t\n", fname);
return;
}
if (ccappTaskPostMsg(CCAPP_THREAD_UNLOAD, msg, len, CCAPP_CCPROVIER) == CPR_FAILURE )
{
err_msg("%s: Unable to send THREAD_UNLOAD msg to CCapp thread", fname);
}
err_msg("%s: send UNLOAD msg to CCapp thread good", fname);
}
break;
default:
err_msg("%s: Unknown destination task passed=%d.", fname, dest_id);
break;
}
}
/*
* Function: ccUnload
*
* Description:
* - deinit portable runtime.
* - Cleanup call control modules, GSM and SIp Stack
*
* Parameters: none
*
* Returns: none
*
*/
void
ccUnload (void)
{
static const char fname[] = "ccUnload";
DEF_DEBUG(DEB_F_PREFIX"ccUnload called..\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname));
if (platform_initialized == FALSE)
{
TNP_DEBUG(DEB_F_PREFIX"system is not loaded, ignore unload\n", DEB_F_PREFIX_ARGS(SIP_CC_INIT, fname));
return;
}
/*
* We are going to send an unload msg to each of the thread, which on
* receiving the msg, will kill itself.
*/
send_task_unload_msg(CC_SRC_SIP);
send_task_unload_msg(CC_SRC_GSM);
if (FALSE == gHardCodeSDPMode) {
send_task_unload_msg(CC_SRC_MISC_APP);
}
send_task_unload_msg(CC_SRC_CCAPP);
cprSleep(200);
gStopTickTask = TRUE;
}