/* 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_types.h" #include "cpr_stdlib.h" #include "cpr_stdio.h" #include "fsm.h" #include "fim.h" #include "lsm.h" #include "sm.h" #include "gsm.h" /* for GSM_ERR_MSG */ #include "ccapi.h" #include "phone_debug.h" #include "debug.h" #include "text_strings.h" #include "sip_interface_regmgr.h" #include "resource_manager.h" #include "platform_api.h" #define FSM_MAX_FCBS (LSM_MAX_CALLS * (FSM_TYPE_MAX - 1)) #define FSM_S_IDLE 0 extern sm_table_t *pfsmcnf_sm_table; extern sm_table_t *pfsmb2bcnf_sm_table; extern sm_table_t *pfsmxfr_sm_table; extern sm_table_t *pfsmdef_sm_table; static fsm_fcb_t *fsm_fcbs; static fsmdef_dcb_t fsm_dcb; extern uint16_t g_numofselected_calls; extern void dcsm_update_gsm_state(fsm_fcb_t *fcb, callid_t call_id, int state); static const char *fsm_type_names[] = { "HEAD", "CNF", "B2BCNF", "XFR", "DEF" }; static resource_manager_t *ci_map_p[MAX_REG_LINES + 1]; static resource_manager_t *shown_calls_ci_map_p[MAX_REG_LINES + 1]; const char * fsm_type_name (fsm_types_t type) { if ((type <= FSM_TYPE_MIN) || (type >= FSM_TYPE_MAX)) { return (get_debug_string(GSM_UNDEFINED)); } return (fsm_type_names[type]); } const char * fsm_state_name (fsm_types_t type, int id) { switch (type) { case FSM_TYPE_DEF: return (fsmdef_state_name(id)); case FSM_TYPE_XFR: return (fsmxfr_state_name(id)); case FSM_TYPE_CNF: return (fsmcnf_state_name(id)); case FSM_TYPE_B2BCNF: return (fsmb2bcnf_state_name(id)); case FSM_TYPE_NONE: return ("IDLE"); default: return (get_debug_string(GSM_UNDEFINED)); } } void fsm_sm_ftr (cc_features_t ftr_id, cc_srcs_t src_id) { FSM_DEBUG_SM(get_debug_string(FSM_DBG_SM_FTR_ENTRY), cc_feature_name(ftr_id), cc_src_name(src_id)); } void fsm_sm_ignore_ftr (fsm_fcb_t *fcb, int fname, cc_features_t ftr_id) { FSM_DEBUG_SM(get_debug_string(FSM_DBG_IGNORE_FTR), fsm_type_name(fcb->fsm_type), fcb->call_id, fname, cc_feature_name(ftr_id)); } void fsm_sm_ignore_src (fsm_fcb_t *fcb, int fname, cc_srcs_t src_id) { FSM_DEBUG_SM(get_debug_string(FSM_DBG_IGNORE_SRC), fsm_type_name(fcb->fsm_type), fcb->call_id, fname, cc_src_name(src_id)); } void fsm_init_fcb (fsm_fcb_t *fcb, callid_t call_id, fsmdef_dcb_t *dcb, fsm_types_t type) { fcb->call_id = call_id; fcb->state = FSM_S_IDLE; fcb->old_state = FSM_S_IDLE; fcb->fsm_type = type; fcb->dcb = dcb; fcb->xcb = NULL; fcb->ccb = NULL; fcb->b2bccb = NULL; } /* * ROUTINE: fsm_get_fcb_by_call_id_and_type * * DESCRIPTION: return the fcb referenced by the given call_id and type * * PARAMETERS: fsm_id * * RETURNS: fcb * !NULL: fcb found * NULL: fcb not found * * NOTES: */ fsm_fcb_t * fsm_get_fcb_by_call_id_and_type (callid_t call_id, fsm_types_t type) { static const char fname[] = "fsm_get_fcb_by_call_id_and_type"; fsm_fcb_t *fcb; fsm_fcb_t *fcb_found = NULL; FSM_FOR_ALL_CBS(fcb, fsm_fcbs, FSM_MAX_FCBS) { if ((fcb->call_id == call_id) && (fcb->fsm_type == type)) { fcb_found = fcb; break; } } FSM_DEBUG_SM(get_debug_string(GSM_DBG_PTR), "FSM", call_id, fname, "fcb", fcb_found); return (fcb_found); } /* * DESCRIPTION: return the fcb referenced by the given call_id and type * * PARAMETERS: fsm_id * * @return void * !NULL: fcb found * NULL: fcb not found * */ void fsm_get_fcb_by_selected_or_connected_call_fcb (callid_t call_id, fsm_fcb_t **con_fcb_found, fsm_fcb_t **sel_fcb_found) { static const char fname[] = "fsm_get_fcb_by_selected_or_connected_call_fcb"; fsm_fcb_t *fcb; *con_fcb_found = NULL; *sel_fcb_found = NULL; FSM_FOR_ALL_CBS(fcb, fsm_fcbs, FSM_MAX_FCBS) { if (fcb->call_id == call_id) { /* Do not count current call_id */ continue; } if (fcb->fsm_type == FSM_TYPE_DEF && (fcb->state == FSMDEF_S_CONNECTED || fcb->state == FSMDEF_S_CONNECTED_MEDIA_PEND || fcb->state == FSMDEF_S_OUTGOING_ALERTING)) { *con_fcb_found = fcb; } else if (fcb->fsm_type == FSM_TYPE_DEF && fcb->dcb->selected) { *sel_fcb_found = fcb; break; } } FSM_DEBUG_SM(get_debug_string(GSM_DBG_PTR), "FSM", call_id, fname, "fcb", con_fcb_found); } /* * ROUTINE: fsm_get_fcb_by_call_id * * DESCRIPTION: return the fcb referenced by the given call_id * * PARAMETERS: fsm_id * * RETURNS: fcb * !NULL: fcb found * NULL: fcb not found * * NOTES: */ fsm_fcb_t * fsm_get_fcb_by_call_id (callid_t call_id) { static const char fname[] = "fsm_get_fcb_by_call_id"; fsm_fcb_t *fcb; fsm_fcb_t *fcb_found = NULL; FSM_FOR_ALL_CBS(fcb, fsm_fcbs, FSM_MAX_FCBS) { if (fcb->call_id == call_id) { fcb_found = fcb; break; } } FSM_DEBUG_SM(get_debug_string(GSM_DBG_PTR), "FSM", call_id, fname, "fcb", fcb_found); return (fcb_found); } /* * ROUTINE: fsm_get_new_fcb * * DESCRIPTION: return a new fcb initialized with the given data * * PARAMETERS: * call_id: call_id * type: feature type * * RETURNS: * fcb: the new fcb */ fsm_fcb_t * fsm_get_new_fcb (callid_t call_id, fsm_types_t fsm_type) { static const char fname[] = "fsm_get_new_fcb"; fsm_fcb_t *fcb; /* * Get free fcb by using CC_NO_CALL_ID as the call_id because a free fcb * will have a call_id of CC_NO_CALL_ID. */ fcb = fsm_get_fcb_by_call_id(CC_NO_CALL_ID); if (fcb != NULL) { fsm_init_fcb(fcb, call_id, FSMDEF_NO_DCB, fsm_type); } FSM_DEBUG_SM(get_debug_string(GSM_DBG_PTR), "FSM", call_id, fname, "fcb", fcb); return (fcb); } fsmdef_dcb_t * fsm_get_dcb (callid_t call_id) { fsmdef_dcb_t *dcb; dcb = fsmdef_get_dcb_by_call_id(call_id); /* * Return the fsm default dcb if a dcb was not found. */ if (dcb == NULL) { dcb = &fsm_dcb; } return (dcb); } void fsm_get_fcb (fim_icb_t *icb, callid_t call_id) { icb->cb = fsm_get_new_fcb(call_id, icb->scb->type); } void fsm_init_scb (fim_icb_t *icb, callid_t call_id) { icb->scb->get_cb = &fsm_get_fcb; switch (icb->scb->type) { case FSM_TYPE_B2BCNF: icb->scb->sm = pfsmb2bcnf_sm_table; icb->scb->free_cb = fsmb2bcnf_free_cb; break; case FSM_TYPE_CNF: icb->scb->sm = pfsmcnf_sm_table; icb->scb->free_cb = fsmcnf_free_cb; break; case FSM_TYPE_XFR: icb->scb->sm = pfsmxfr_sm_table; icb->scb->free_cb = fsmxfr_free_cb; break; case FSM_TYPE_DEF: icb->scb->sm = pfsmdef_sm_table; icb->scb->free_cb = fsmdef_free_cb; break; case FSM_TYPE_HEAD: default: icb->scb->get_cb = NULL; icb->scb->free_cb = NULL; icb->scb->sm = NULL; } } void fsm_change_state (fsm_fcb_t *fcb, int fname, int new_state) { DEF_DEBUG(DEB_L_C_F_PREFIX"%s: %s -> %s\n", DEB_L_C_F_PREFIX_ARGS(FSM, ((fcb->dcb == NULL)? CC_NO_LINE: fcb->dcb->line), fcb->call_id, "fsm_change_state"), fsm_type_name(fcb->fsm_type), fsm_state_name(fcb->fsm_type, fcb->state), fsm_state_name(fcb->fsm_type, new_state)); fcb->old_state = fcb->state; fcb->state = new_state; NOTIFY_STATE_CHANGE(fcb, fcb->call_id, new_state); } void fsm_release (fsm_fcb_t *fcb, int fname, cc_causes_t cause) { fsm_change_state(fcb, fname, FSM_S_IDLE); /* Cleanup any pending cac request for that call */ fsm_cac_call_release_cleanup(fcb->call_id); fsm_init_fcb(fcb, CC_NO_CALL_ID, FSMDEF_NO_DCB, FSM_TYPE_NONE); } cc_int32_t fsm_show_cmd (cc_int32_t argc, const char *argv[]) { fsm_fcb_t *fcb; int i = 0; void *cb = NULL; PR_ASSERT(i == 0); /* * check if need help */ if ((argc == 2) && (argv[1][0] == '?')) { debugif_printf("%s", "show fsm\n"); return 0; } /* * Print the fcbs */ debugif_printf("%s", "\n----------------------------- FSM fcbs -------------------------------"); debugif_printf("%s", "\ni call_id fcb type state dcb cb "); debugif_printf("%s", "\n----------------------------------------------------------------------\n"); FSM_FOR_ALL_CBS(fcb, fsm_fcbs, FSM_MAX_FCBS) { switch (fcb->fsm_type) { case FSM_TYPE_CNF: cb = fcb->ccb; break; case FSM_TYPE_B2BCNF: cb = fcb->ccb; break; case FSM_TYPE_XFR: cb = fcb->xcb; break; case FSM_TYPE_DEF: cb = fcb->dcb; break; default: cb = NULL; } debugif_printf("%-3d %-7d 0x%8p %-9s %-9s 0x%8p 0x%8p\n", i++, fcb->call_id, fcb, fsm_type_name(fcb->fsm_type), fsm_state_name(fcb->fsm_type, fcb->state), fcb->dcb, cb); } return (0); } void fsm_init (void) { fsm_fcb_t *fcb; fsmdef_init_dcb(&fsm_dcb, 0, FSMDEF_CALL_TYPE_NONE, NULL, LSM_NO_LINE, NULL); fsmdef_init(); fsmb2bcnf_init(); fsmcnf_init(); fsmxfr_init(); fsm_cac_init(); /* * Initialize the fcbs. */ fsm_fcbs = (fsm_fcb_t *) cpr_calloc(FSM_MAX_FCBS, sizeof(fsm_fcb_t)); if (fsm_fcbs == NULL) { GSM_ERR_MSG(GSM_F_PREFIX"Failed to allcoate FSM FCBs.\n", "fsm_init"); return; } FSM_FOR_ALL_CBS(fcb, fsm_fcbs, FSM_MAX_FCBS) { fsm_init_fcb(fcb, CC_NO_CALL_ID, FSMDEF_NO_DCB, FSM_TYPE_NONE); } /* * Init call instance id map. */ fsmutil_init_ci_map(); } void fsm_shutdown (void) { fsmdef_shutdown(); fsmb2bcnf_shutdown(); fsmcnf_shutdown(); fsmxfr_shutdown(); fsm_cac_shutdown(); cpr_free(fsm_fcbs); fsm_fcbs = NULL; /* * Free call instance id map. */ fsmutil_free_ci_map(); } /* * ROUTINE: fsm_set_fcb_dcbs * * DESCRIPTION: Set the dcbs for the fsms. The fsm call chain is setup before * the dcb is known, so this function is called after the dcb * is known to set the dcb in the fcbs. * * PARAMETERS: * dcb * * RETURNS: NONE * * NOTES: */ cc_causes_t fsm_set_fcb_dcbs (fsmdef_dcb_t *dcb) { callid_t call_id = dcb->call_id; fsm_fcb_t *fcb; fsm_types_t i; for (i = FSM_TYPE_CNF; i < FSM_TYPE_MAX; i++) { fcb = fsm_get_fcb_by_call_id_and_type(call_id, i); if (fcb == NULL) { return CC_CAUSE_ERROR; } fcb->dcb = dcb; } return CC_CAUSE_OK; } /* * ROUTINE: fsm_get_new_outgoing_call_context * * DESCRIPTION: get a new outgoing call context * * PARAMETERS: * fcb * call_id * line * * RETURNS: rc * FSM_SUCCESS: context successfully created * FSM_SUCCESS: context unsuccessfully created * * NOTES: */ cc_causes_t fsm_get_new_outgoing_call_context (callid_t call_id, line_t line, fsm_fcb_t *fcb, boolean expline) { static const char fname[] = "fsm_get_new_outgoing_call_context"; fsmdef_dcb_t *dcb; cc_causes_t cause = CC_CAUSE_OK; cc_causes_t lsm_rc; /* * Get a dcb to handle the call. */ dcb = fsmdef_get_new_dcb(call_id); if (dcb == NULL) { return CC_CAUSE_NO_RESOURCE; } /* * Get a free facility associated with this line. */ lsm_rc = lsm_get_facility_by_line(call_id, line, expline, dcb); if (lsm_rc != CC_CAUSE_OK) { FSM_DEBUG_SM(get_debug_string(FSM_DBG_FAC_ERR), call_id, fname, "lsm_get_facility_by_line failed", cc_cause_name(lsm_rc)); } /* * If no line was returned, then init the dcb with an invalid line to * indicate that no line was returned. */ if (lsm_rc != CC_CAUSE_OK) { line = LSM_NO_LINE; } fsmdef_init_dcb(dcb, call_id, FSMDEF_CALL_TYPE_OUTGOING, NULL, line, fcb); cause = fsm_set_fcb_dcbs(dcb); if (cause == CC_CAUSE_OK) { cause = lsm_rc; } FSM_DEBUG_SM(get_debug_string(FSM_DBG_FAC_FOUND), call_id, fname, dcb->line); return cause; } /* * ROUTINE: fsm_get_new_incoming_call_context * * DESCRIPTION: get a new incoming call context * * PARAMETERS: * fcb * call_id * * RETURNS: rc * FSM_SUCCESS: context successfully created * FSM_SUCCESS: context unsuccessfully created * * NOTES: */ cc_causes_t fsm_get_new_incoming_call_context (callid_t call_id, fsm_fcb_t *fcb, const char *called_number, boolean expline) { static const char fname[] = "fsm_get_new_incoming_call_context"; fsmdef_dcb_t *dcb; line_t free_line; cc_causes_t cause; cc_causes_t lsm_rc; /* * Get a dcb to handle the call. */ dcb = fsmdef_get_new_dcb(call_id); if (dcb == NULL) { return CC_CAUSE_NO_RESOURCE; } /* * Get a free facility associated with this called_number. */ if ((lsm_rc = lsm_get_facility_by_called_number(call_id, called_number, &free_line, expline, dcb)) != CC_CAUSE_OK) { /* * Set a default free line (This should really be changed * to a special invalid value and GSM modified to recognize it.) * The dcb is needed in order for GSM to clean up the call correctly. */ free_line = 1; FSM_DEBUG_SM(get_debug_string(FSM_DBG_FAC_ERR), call_id, fname, "lsm_get_facility_by_called_number", cc_cause_name(lsm_rc)); } fsmdef_init_dcb(dcb, call_id, FSMDEF_CALL_TYPE_INCOMING, called_number, free_line, fcb); cause = fsm_set_fcb_dcbs(dcb); if (cause == CC_CAUSE_OK) { cause = lsm_rc; } FSM_DEBUG_SM(get_debug_string(FSM_DBG_FAC_FOUND), call_id, fname, dcb->line); return cause; } /* * fsmutil_is_cnf_leg * * Description: * * Returns TRUE if conferencing is active for the call_id * * * Parameters: * * call_id - ccapi call identifier associated with the call. * fsmxcb_ccbs - pointer to all conf ccbs * max_ccbs - Max number of ccbs to check * * Returns TRUE if the conferencing is active for the call_id */ int fsmutil_is_cnf_leg (callid_t call_id, fsmcnf_ccb_t *fsmcnf_ccbs, unsigned short max_ccbs) { fsmcnf_ccb_t *ccb; FSM_FOR_ALL_CBS(ccb, fsmcnf_ccbs, max_ccbs) { if ((ccb->cnf_call_id == call_id) || (ccb->cns_call_id == call_id)) { return TRUE; } } return FALSE; } /* * fsmutil_is_xfr_leg * * Description: * * Returns transfer mode if the specified leg identified by call_id is * participating in a xfer * * Parameters: * * call_id - ccapi call identifier associated with the call. * fsmxfr_xcbs - pointer to all xfr ccbs * max_xcbs - Max number of ccbs to check * * Returns: fsmxfr_modes_t */ int fsmutil_is_xfr_leg (callid_t call_id, fsmxfr_xcb_t *fsmxfr_xcbs, unsigned short max_xcbs) { fsmxfr_xcb_t *xcb; FSM_FOR_ALL_CBS(xcb, fsmxfr_xcbs, max_xcbs) { if ((xcb->xfr_call_id == call_id) || (xcb->cns_call_id == call_id)) { return xcb->mode; } } return FSMXFR_MODE_MIN; } void fsm_display_no_free_lines (void) { char tmp_str[STATUS_LINE_MAX_LEN]; if ((platGetPhraseText(STR_INDEX_NO_FREE_LINES, (char *)tmp_str, (STATUS_LINE_MAX_LEN - 1))) == CPR_SUCCESS) { lsm_ui_display_notify(tmp_str, NO_FREE_LINES_TIMEOUT); } } /* * Function: fsm_display_use_line_or_join_to_complete * * Description: * The function is used to put up the status line * "Use Line or Join to Complete" * * @param None * * @return None */ void fsm_display_use_line_or_join_to_complete (void) { char tmp_str[STATUS_LINE_MAX_LEN]; if ((platGetPhraseText(STR_INDEX_USE_LINE_OR_JOIN_TO_COMPLETE, (char *)tmp_str, (STATUS_LINE_MAX_LEN - 1))) == CPR_SUCCESS) { lsm_ui_display_notify(tmp_str, NO_FREE_LINES_TIMEOUT); } } void fsm_display_feature_unavailable (void) { char tmp_str[STATUS_LINE_MAX_LEN]; if ((platGetPhraseText(STR_INDEX_FEAT_UNAVAIL, (char *)tmp_str, (STATUS_LINE_MAX_LEN - 1))) == CPR_SUCCESS) { lsm_ui_display_notify(tmp_str, NO_FREE_LINES_TIMEOUT); } } void fsm_set_call_status_feature_unavailable (callid_t call_id, line_t line) { char tmp_str[STATUS_LINE_MAX_LEN]; if ((platGetPhraseText(STR_INDEX_FEAT_UNAVAIL, (char *)tmp_str, (STATUS_LINE_MAX_LEN - 1))) == CPR_SUCCESS) { ui_set_call_status(tmp_str, line, lsm_get_ui_id(call_id)); } } /** * * Get total number of selected calls. * * @param void * * @return uint16_t * * @pre (none) */ uint16_t fsmutil_get_num_selected_calls (void) { return(g_numofselected_calls); } /** * This function will hide/unhide ringingin calls. * * @param[in] hide - indicates whether calls should be hidden or unhidden * * @return none */ void fsm_display_control_ringin_calls (boolean hide) { fsm_fcb_t *fcb; FSM_FOR_ALL_CBS(fcb, fsm_fcbs, FSM_MAX_FCBS) { if ((fcb->state == FSMDEF_S_INCOMING_ALERTING) && (lsm_is_it_priority_call(fcb->call_id) == FALSE)) { /* priority call should not be hidden */ lsm_display_control_ringin_call (fcb->call_id, fcb->dcb->line, hide); if (hide == TRUE) { fsmutil_clear_shown_calls_ci_element(fcb->dcb->caller_id.call_instance_id, fcb->dcb->line); } else { fsmutil_set_shown_calls_ci_element(fcb->dcb->caller_id.call_instance_id, fcb->dcb->line); } } } } /* * fsmutil_init_groupid * * Description: * * Assign the group id to the default control block. * * Parameters: * dcb - default control block * call_id - ccapi call identifier associated with the call * call_type - incoming or outgoing call * * Returns: None. groupid will be assigned in the dcb. */ void fsmutil_init_groupid (fsmdef_dcb_t *dcb, callid_t call_id, fsmdef_call_types_t call_type) { fsmcnf_ccb_t *ccb = NULL; /* if this was a consult leg of a conference then there will be * a ccb on the primary leg */ dcb->group_id = CC_NO_GROUP_ID; if (call_type != FSMDEF_CALL_TYPE_NONE) { ccb = fsmcnf_get_ccb_by_call_id(call_id); if (ccb) { /* consult leg of a conference */ fsmdef_dcb_t *other_dcb = NULL; other_dcb = fsmdef_get_dcb_by_call_id(fsmcnf_get_other_call_id(ccb, call_id)); if (other_dcb) { dcb->group_id = other_dcb->group_id; } } else { /* either a primary or some other leg; not part of any conference */ dcb->group_id = dcb->call_id; } } return; } /** * * Find out if the call pointed by call_id is a consult call * of a conference, transfer. * * @param line line related to that call * @param call_id call_id * * @return call attributes * * @pre none */ int fsmutil_get_call_attr (fsmdef_dcb_t *dcb, line_t line, callid_t call_id) { int call_attr; if (fsmutil_is_cnf_consult_call(call_id) == TRUE) { call_attr = LOCAL_CONF_CONSULT; } else if (fsmutil_is_b2bcnf_consult_call(call_id) == TRUE) { call_attr = CONF_CONSULT; } else if (fsmutil_is_xfr_consult_call(call_id) == TRUE) { call_attr = XFR_CONSULT; } else { if (dcb == NULL) { return(NORMAL_CALL); } switch (dcb->active_feature) { case CC_FEATURE_CFWD_ALL: call_attr = CC_ATTR_CFWD_ALL; break; default: call_attr = NORMAL_CALL; break; } } return call_attr; } /* * fsmutil_is_cnf_consult_leg * * Description: * Returns TRUE if the specified call_id is for a call that is * the consultative call of a conference. * * Parameters: * call_id - ccapi call identifier associated with the call. * fsmxcb_ccbs - pointer to all conf ccbs * max_ccbs - Max number of ccbs to check * * Returns: TRUE if consultative call; otherwise, FALSE. */ int fsmutil_is_cnf_consult_leg (callid_t call_id, fsmcnf_ccb_t *fsmcnf_ccbs, uint16_t max_ccbs) { fsmcnf_ccb_t *ccb; FSM_FOR_ALL_CBS(ccb, fsmcnf_ccbs, max_ccbs) { if (ccb->cns_call_id == call_id) { return TRUE; } } return FALSE; } /* * fsmutil_is_xfr_consult_leg * * Description: * Returns TRUE if the specified call_id is for a call that is * the consultative call of a transfer only when that consult * was an initiated transfer. * * Parameters: * call_id - ccapi call identifier associated with the call. * fsmxfr_xcbs - pointer to all xfr ccbs * max_xcbs - Max number of ccbs to check * * Returns: TRUE if consultative call; otherwise, FALSE. */ int fsmutil_is_xfr_consult_leg (callid_t call_id, fsmxfr_xcb_t *fsmxfr_xcbs, uint16_t max_xcbs) { fsmxfr_xcb_t *xcb; FSM_FOR_ALL_CBS(xcb, fsmxfr_xcbs, max_xcbs) { if ((xcb->mode == FSMXFR_MODE_TRANSFEROR) && (xcb->cns_call_id == call_id)) { return TRUE; } } return FALSE; } /* * fsmutil_clear_feature_invocation_state * * Description: * This function clears the feature invocation state of the feature id * supplied. This function is used by the code that would receive the * feature ack (from SIP stack). * * Note: Code responsible for invoking features and receiving feature acks * must call this function to clear the feature invocation state. * * Parameters: * fsmdef_dcb_t *dcb - dcb associated with the call * cc_features_t feature_id - feature id in question * * Returns: None */ static void fsmutil_clear_feature_invocation_state (fsmdef_dcb_t *dcb, cc_features_t feature_id) { if ((feature_id < CC_FEATURE_NONE) || (feature_id >= CC_FEATURE_MAX)) { /* Log Error */ GSM_ERR_MSG(GSM_L_C_F_PREFIX"Invalid feature id -> %d\n", dcb->line, dcb->call_id, "fsmutil_clear_feature_invocation_state", feature_id); return; } rm_clear_element((resource_manager_t *) dcb->feature_invocation_state, (int16_t) feature_id); } /* * fsmutil_process_feature_ack * * Description: * This function implements the generic feature ack processing. * Feature invocation state is Cleared when feature ack is received. * * Parameters: * fsmdef_dcb_t *dcb - dcb associated with the call * cc_features_t feature_id - feature id in question * * Returns: None */ void fsmutil_process_feature_ack (fsmdef_dcb_t *dcb, cc_features_t feature_id) { /* clear the feature invocation state (was set when invoked) */ fsmutil_clear_feature_invocation_state(dcb, feature_id); } /* * fsmutil_clear_all_feature_invocation_state * * Description: * This function clears the feature invocation state of ALL features. * * This function may be used by the code that would initialize/reset * the state machine. * * Parameters: * fsmdef_dcb_t *dcb - dcb associated with the call * * Returns: None */ void fsmutil_clear_all_feature_invocation_state (fsmdef_dcb_t *dcb) { rm_clear_all_elements((resource_manager_t *) dcb->feature_invocation_state); } /* * fsmutil_init_feature_invocation_state * * Description: * Utility function to allocate and init a feature invocation state table. * * Parameters: * dcb - dcb whose feature invocation state table is being created * * Returns: * none */ void fsmutil_init_feature_invocation_state (fsmdef_dcb_t *dcb) { static const char fname[] = "fsmutil_init_feature_invocation_state"; dcb->feature_invocation_state = rm_create(CC_FEATURE_MAX); if (!dcb->feature_invocation_state) { GSM_ERR_MSG(GSM_L_C_F_PREFIX"failed to allocate feature invocation state table\n", dcb->line, dcb->call_id, fname); } } /* * fsmutil_free_feature_invocation_state * * Description: * Utility function to free the feature invocation state table of the * specified dcb. * * Parameters: * None * * Returns: * None */ void fsmutil_free_feature_invocation_state (fsmdef_dcb_t *dcb) { rm_destroy((resource_manager_t *) dcb->feature_invocation_state); dcb->feature_invocation_state = NULL; } /* * fsmutil_free_all_ci_id * * Description: * This function clears the entire call instance map. * * Parameters: * None * * Returns: * None */ void fsmutil_free_all_ci_id (void) { uint16_t line; for (line = 1; line <= MAX_REG_LINES; line++) { rm_clear_all_elements((resource_manager_t *) ci_map_p[line]); } } /* * fsmutil_free_ci_id * * Description: * This function clears a specified call instance id from * the call instance map. * * Note that call instance ids are one based. The resource manager * used to implement the call instance map is zero based so we have * to adjust the call instance id when using the resource manager API. * * Parameters: * id - the call instance id to be freed * line - line from where to free the call instance id * * Returns: * None */ void fsmutil_free_ci_id (uint16_t id, line_t line) { static const char fname[] = "fsmutil_free_ci_id"; if (id < 1 || id > MAX_CALLS) { GSM_ERR_MSG(GSM_F_PREFIX"specified id %d is invalid\n", fname, id); return; } if (line < 1 || line > MAX_REG_LINES) { GSM_ERR_MSG(GSM_F_PREFIX"specified line %d is invalid\n", fname, line); return; } rm_clear_element((resource_manager_t *) ci_map_p[line], (int16_t) --id); } #ifdef LOCAL_UI_CALLINSTANCE_ID /*This routine is not needed now as the local assignment *of call instance id is no longer supported. */ /* * fsmutil_get_ci_id * * Description: * This function locates the next available call instance id in * the call instance map. This function is utilized when operating in * the peer to peer mode to assign call instance ids for inbound * and outbound calls. * * Note that call instance ids are one based. The resource manager * used to implement the call instance map is zero based so we have * to adjust the call instance id when using the resource manager API. * * Parameters: * line - line from where to retrieve the call instance id * * Returns: * uint16_t - Non-zero call instance id. 0 if no call instance ids * are available. */ uint16_t fsmutil_get_ci_id (line_t line) { static const char fname[] = "fsmutil_get_ci_id"; int16_t id; uint16_t return_id = 0; if (line < 1 || line > MAX_REG_LINES) { GSM_ERR_MSG("specified line %d is invalid\n", fname, line); return 0; } id = rm_get_free_element(ci_map_p[line]); if (id >= 0) { return_id = ++id; } return (return_id); } #endif /* * fsmutil_set_ci_id * * Description: * This function marks a specified call instance id as being in * use in the call instance map. This function is used when in * CCM mode to store the call instance id specified by the CCM * for inbound and outbound calls. * * Note that call instance ids are one based. The resource manager * used to implement the call instance map is zero based so we have * to adjust the call instance id when using the resource manager API. * Parameters: * * Parameters: * id - The call instance id to set. * line - Line being used for the call. * * Returns: * None */ void fsmutil_set_ci_id (uint16_t id, line_t line) { static const char fname[] = "fsmutil_set_ci_id"; if (id < 1 || id > MAX_CALLS) { GSM_ERR_MSG(GSM_F_PREFIX"specified id %d is invalid\n", fname, id); return; } if (line < 1 || line > MAX_REG_LINES) { GSM_ERR_MSG(GSM_F_PREFIX"specified line %d is invalid\n", fname, line); return; } rm_set_element(ci_map_p[line], (int16_t) --id); } /* * fsmutil_init_ci_map * * Description: * Utility function to allocate and init the call instance id map. * * Parameters: * None * * Returns: * None */ void fsmutil_init_ci_map (void) { static const char fname[] = "fsmutil_init_ci_map"; uint16_t line; for (line = 1; line <= MAX_REG_LINES; line++) { ci_map_p[line] = rm_create(MAX_CALLS); if (!ci_map_p[line]) { GSM_ERR_MSG(GSM_F_PREFIX"failed to allocate call instance id map for line %d", fname, line); } } } /** * This function will allocate and initialize the shown_calls_call_instnace map. * * @return none */ void fsmutil_init_shown_calls_ci_map (void) { static const char fname[] = "fsmutil_init_shown_calls_ci_map"; uint16_t line; for (line = 1; line <= MAX_REG_LINES; line++) { shown_calls_ci_map_p[line] = rm_create(MAX_CALLS); if (!shown_calls_ci_map_p[line]) { GSM_ERR_MSG(GSM_F_PREFIX"failed to allocate shown calls call instance id map for line %d", fname, line); } } } /** * This function will set the shown_calls_call_instnace map to zeros. * * @return none */ void fsmutil_free_all_shown_calls_ci_map (void) { uint16_t line; for (line = 1; line <= MAX_REG_LINES; line++) { rm_clear_all_elements((resource_manager_t *) shown_calls_ci_map_p[line]); } } /** * This function marks a given call to be hidden. * * @param[in] id - call instance id of the call to be hidden. * @param[in] line - the line being used for the call. * * @return none */ void fsmutil_clear_shown_calls_ci_element (uint16_t id, line_t line) { static const char fname[] = "fsmutil_clear_shown_calls_ci_element"; if (id < 1 || id > MAX_CALLS) { GSM_ERR_MSG(GSM_F_PREFIX"specified id %d is invalid\n", fname, id); return; } if (line < 1 || line > MAX_REG_LINES) { GSM_ERR_MSG(GSM_F_PREFIX"specified line %d is invalid\n", fname, line); return; } rm_clear_element((resource_manager_t *) shown_calls_ci_map_p[line], (int16_t)(id - 1)); } /** * This function marks a given call to be shown. * * @param[in] id - call instance id of the call to be shown. * @param[in] line - the line being used for the call. * * @return none */ void fsmutil_set_shown_calls_ci_element (uint16_t id, line_t line) { static const char fname[] = "fsmutil_set_shown_calls_ci_element"; if (id < 1 || id > MAX_CALLS) { GSM_ERR_MSG(GSM_F_PREFIX"specified id %d is invalid\n", fname, id); return; } if (line < 1 || line > MAX_REG_LINES) { GSM_ERR_MSG(GSM_F_PREFIX"specified line %d is invalid\n", fname, line); return; } rm_set_element(shown_calls_ci_map_p[line], (int16_t)(id - 1)); } /** * This function checks if a given call is to be shown. * * @param[in] id - call instance id of the call. * @param[in] line - the line being used for the call. * * @return none */ boolean fsmutil_is_shown_calls_ci_element_set (uint16_t id, line_t line) { static const char fname[] = "fsmutil_is_shown_calls_ci_element_set"; if (id < 1 || id > MAX_CALLS) { GSM_ERR_MSG(GSM_F_PREFIX"specified id %d is invalid\n", fname, id); return FALSE; } if (line < 1 || line > MAX_REG_LINES) { GSM_ERR_MSG(GSM_F_PREFIX"specified line %d is invalid\n", fname, line); return FALSE; } if (rm_is_element_set(shown_calls_ci_map_p[line], (int16_t)(id - 1))) { return (TRUE); } return (FALSE); } /* * fsmutil_free_ci_map * * Description: * Utility function to free the call instance id map. * * Parameters: * None * * Returns: * None */ void fsmutil_free_ci_map (void) { uint16_t line; for (line = 1; line <= MAX_REG_LINES; line++) { rm_destroy((resource_manager_t *) ci_map_p[line]); ci_map_p[line] = NULL; } } /* * fsmutil_show_ci_map * * Description: * Utility function to display the current state of the call * instance map. * * Parameters: * None * * Returns: * None */ void fsmutil_show_ci_map (void) { uint16_t line; for (line = 1; line <= MAX_REG_LINES; line++) { rm_show(ci_map_p[line]); } }