Files
microser/mmslib/mvlu/mvl_uca.c
2026-06-15 15:48:16 +08:00

2689 lines
93 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/************************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/* (c) Copyright Systems Integration Specialists Company, Inc., */
/* 1998-2005, All Rights Reserved. */
/* */
/* PROPRIETARY AND CONFIDENTIAL */
/* */
/* MODULE NAME : mvl_uca.c */
/* PRODUCT(S) : MMSEASE */
/* */
/* MODULE DESCRIPTION : */
/* Special read/write processing functions for UCA and */
/* IEC 61850 objects. */
/* */
/* NOTE: define MVL61850_CTL_DISABLE to avoid calling user functions */
/* (u_mvl61850_ctl_oper_*) if 61850 Controls not needed. */
/* */
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */
/* */
/* MODIFICATION LOG : */
/* Date Who Rev Comments */
/* -------- --- ------ ------------------------------------------- */
/* 01/27/09 JRB 70 Don't send write resp until ind is done. */
/* Don't allow write if any leaf unwritable. */
/* Call user func at start/end of complex write.*/
/* 01/07/09 JRB 69 Del S_LOCK for OPC_CLIENT in u_mvl_read_ind */
/* (already locked by mvl_comm_serve). */
/* 06/30/08 JRB 68 Repl cmd_executing w/ ctlState (more flexible)*/
/* Do SBO Ctrl checks only if Oper/Cancel is */
/* ONLY structure being written. */
/* Fix sboName buffer size. */
/* 05/06/08 JRB 67 Set new cmd_executing flag. */
/* 03/03/08 JRB 66 Call mvl61850_ctl_req_done to do what's needed*/
/* when IEC 61850 control request completes. */
/* 02/18/08 JRB 65 Use new mvl_var_create_derived function. */
/* 02/07/08 JRB 64 Fix alignment of ptr passed to mvlu_clone.. */
/* 12/18/07 MDE 63 Fixed lastDollar crash for IOS */
/* 11/12/07 MDE 62 Changed MMSOP_RDWR_USR_HANDLED to _RD_ */
/* 07/20/07 JRB 61 getGnlVarNames: fix crash when flatname */
/* too long; add return code & check it. */
/* 05/09/07 JRB 60 Fix alt_acc arg passed to mvlu_find_component*/
/* Fix log macro args. */
/* 04/30/07 JRB 59 Fix to work with RUNTIME_TYPE change. */
/* 04/17/07 JRB 58 Fix calc of offset_from_base & prim_num */
/* to work for Alt Access on arrays (corrects */
/* primData, prim_num, and prim_offset_base */
/* passed to leaf functions). */
/* mvlu_find_struct_comp: add args to compute */
/* offset & prim_num. */
/* 03/07/07 JRB 57 Add mvlu_get_leaf_val_int_any. */
/* 11/21/06 JRB 56 Send LastApplError if write of Oper, etc fails.*/
/* 10/30/06 JRB 55 Use new mvl_vmd_* object handling functions. */
/* mvlu_find_base_va: add args. */
/* u_mvl_get_va_aa: add args. */
/* u_gnl_ind_*: add net_info arg to */
/* elim use of global var "_mvl_curr_net_info". */
/* u_mvl_get_va_aa: do not set va->usr_ind_ctrl */
/* (done by calling functions). */
/* 10/26/06 JRB 54 Del unused local vars. */
/* 09/27/06 MDE 53 Added MMSOP_RD_USR_HANDLED for IOS */
/* 09/13/06 JRB 52 mvlu_find_comp_type: allow non-dynamic types.*/
/* 08/09/06 JRB 51 Del u_mvl_get_nvl, u_mvl_free_nvl functions */
/* (not needed with new improved Foundry). */
/* Use "mvl_var_create/destroy" so all variables*/
/* created/destroyed in one place. */
/* 07/24/06 JRB 50 Chg some common ERR logs to FLOW. */
/* 03/27/06 JRB 49 Add more mvlu_get_leaf_* functions. */
/* 07/29/05 MDE 48 Fixed static data use for write handling */
/* 07/11/05 JRB 47 Call user fcts (u_mvl61850_ctl_oper_*) if */
/* !defined (MVL61850_CTL_DISABLE). */
/* 01/19/05 JRB 46 u_gnl_ind_* return (-1) on error. */
/* 12/09/04 JRB 45 init_prim_info_recursive: fix ARR_END handling.*/
/* init_prim_info_arr: simplify & ret ST_VOID. */
/* Add mvlu_find_comp_type, mvlu_get_leaf_val*. */
/* Chg trim_branch_name to global mvlu_trim_.. */
/* & simplify it using strrchr. */
/* 09/20/04 JRB 44 startElWrites: if writing "Oper" or "Cancel" */
/* struct, check SBO state. */
/* mvlu_wr_prim_done call mvlu_sbo_ctrl_free. */
/* 06/29/04 JRB 43 Del global var mvluUseStaticData, instead use*/
/* use_static_data flag in MVL_VAR_ASSOC for Read.*/
/* NEVER use static data for Write. */
/* startElReads, etc: add prim_info arg. */
/* Del elmntOffset, use prim_info->prim_offset. */
/* 11/24/03 JRB 42 getGnlVarNames: fix prefix len by using */
/* MAX_IDENT_LEN, chk overflow BEFORE writing, */
/* & add logging & asserts. */
/* 09/18/03 JRB 41 Allow alt acc on array of "nested" structures*/
/* Add some debug logging & extra comments. */
/* 05/02/03 JRB 40 switch(rt->el_tag): Use default for most cases*/
/* 04/04/03 JRB 39 Fix integrity/GI scan code so multiple */
/* concurrent scans don't corrupt one another. */
/* 12/20/02 JRB 38 Moved mvlu_set_leaf_param to mvluleaf.c */
/* 12/12/02 JRB 37 Use usr_resp_fun ptr to call scan done funcs.*/
/* 12/09/02 MDE 36 Made mvlu_find_uca_var global */
/* 11/27/02 MDE 35 Addded leaf indication handlers */
/* Addded mvlu_find_rt_leaf */
/* Addded mvlu_set_leaf_param */
/* 11/29/01 MDE 34 Added GOOSE function pointer */
/* 11/14/01 EJV 33 Added support for new MMS type UtcTime: */
/* 11/13/01 MDE 32 Added GOOSE scan support */
/* 05/21/01 MDE 31 Cleaned up memory allocation for SMEM */
/* 10/25/00 JRB 30 Del u_mvl & u_gnl funct ptrs. Call directly. */
/* Del mvlu_install (no longer needed). */
/* 08/18/00 JRB 29 Don't clear va_to_free. Need value later. */
/* mvlu_free_nvl free va->va_to_free only if */
/* it was allocated by mvlu_get_nvl. */
/* 08/18/00 RKR 28 Added rt fields to MVLU_ typedefs */
/* 07/13/00 JRB 27 Cleanup ms_comp_na.. chg for MVL_XNAME. */
/* 07/13/00 JRB 26 Use new ms_comp_name_find to get comp names. */
/* 07/13/00 JRB 25 Move these functs to mvl_type.c: */
/* mvlu_add_rt_type, mvlu_free_rt_type. */
/* 06/21/00 MDE 24 Now copy base VA user_info to new VA */
/* 05/15/00 MDE 23 Now filder out too-long variable names */
/* 04/14/00 JRB 22 Lint cleanup. */
/* 04/05/00 RKR 21 Made MVL_XNAME a compile time option */
/* 04/03/00 RKR 20 Added the xName to UCA Rd and Wr Ind funs */
/* 03/30/00 RKR 19 Passed the expanded UCA var name to ind fun */
/* 01/21/00 MDE 18 Now use MEM_SMEM for dynamic memory */
/* 12/20/99 MDE 17 Fix getArrAARtType to return SUCCESS/FAIL */
/* 11/03/99 JRB 16 Fix GetNameList if CA name = base var name. */
/* 09/30/99 EJV 15 Added slog macro to mvlu_rd_prim_done */
/* 09/13/99 MDE 14 Added SD_CONST modifiers */
/* 09/07/99 MDE 13 Revised and enhanced the UCA report system */
/* 06/04/99 MDE 12 Now allow arrays as base VA type, other */
/* minor changes to VA processing */
/* 06/04/99 MDE 11 Fixed memory leak for nested array alt acc */
/* 04/07/99 MDE 10 Logging improvements (fixed wrong AA log too)*/
/* 03/09/99 JRB 12 Fix illegal free of gnlNameBuf. */
/* 02/22/99 JRB 11 BUG FIX: Always start with clean "arrCtrl". */
/* 01/08/99 JRB 10 Use new "bsearch" object model. Don't use */
/* "_UCA_" prefix on va and nvl names. */
/* 12/11/98 MDE 09 Removed scope references from VA */
/* 11/17/98 MDE 08 Made mvlu_get_va_aa alloc space for name */
/* 11/16/98 MDE 07 Renamed internal functions (prefix '_') */
/* 09/21/98 MDE 06 Uninitialized ptr fix, Minor lint cleanup */
/* 08/11/98 MDE 05 Added UCA variable array support */
/* 07/13/98 MDE 04 Mixed scope NVL fixes, data alignment fix */
/* 06/29/98 MDE 03 Added report function pointers */
/* 06/15/98 MDE 02 Changes to allow compile under C++ */
/* 01/02/98 MDE 01 New */
/************************************************************************/
#include "glbtypes.h"
#include "sysincs.h"
#include "glbsem.h"
#include "mmsdefs.h"
#include "mms_pvar.h"
#include "mms_vvar.h"
#include "mvl_uca.h"
#include "mvl_log.h"
#if defined(MVL_UCA) /* This entire module is only valid for UCA. */
/************************************************************************/
/* For debug version, use a static pointer to avoid duplication of */
/* __FILE__ strings. */
#ifdef DEBUG_SISCO
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
#endif
/* PRIM_INFO struct: extra info about primitive. */
typedef struct
{
ST_UINT prim_num; /* index to data */
ST_UINT prim_offset; /* mem offset from start of var */
ST_UINT prim_offset_base; /* mem offset from start of "base" var */
} PRIM_INFO; /* extra info about primitive */
/************************************************************************/
static ST_VOID mvluDefGetVaDataBufFun (ST_INT service, MVL_VAR_ASSOC *va,
ST_INT size);
static ST_VOID mvluDefFreeVaDataBufFun (ST_INT service, MVL_VAR_ASSOC *va);
/************************************************************************/
/* Read/Write leaf indication override handlers */
ST_VOID (*u_mvlu_leaf_rd_ind_fun)(MVLU_RD_VA_CTRL *mvluRdVaCtrl);
ST_VOID (*u_mvlu_leaf_wr_ind_fun)(MVLU_WR_VA_CTRL *mvluWrVaCtrl);
/************************************************************************/
/* STATIC VARIABLES, LOCAL DEFINES */
/* GNL Variables */
static ST_CHAR *gnlNameBuf;
static ST_CHAR *currGnlNamePos;
/* Index to "u_no_write_allowed" function. It is set to correct value */
/* at startup by calling "mvlu_find_wr_ind_fun_index" (one time). */
static ST_RTINT idx_u_no_write_allowed = -2; /* start with illegal val*/
#define _OBJ_NAME_CLONE_NAME_SIZE (65)
#define _OBJ_NAME_CLONE_SIZE (sizeof(OBJECT_NAME)+(2 * _OBJ_NAME_CLONE_NAME_SIZE))
/************************************************************************/
/* STATIC FUNCTIONS */
ST_RET mvlu_find_component (
ST_CHAR *flatname, /* flattened name (e.g. ST$Mod$stVal) */
ALT_ACCESS *alt_acc,
RUNTIME_TYPE **rtIo,
ST_INT *numRtIo,
ST_INT *offset_io,
ST_RTINT *prim_num_io);
static ST_RET mvlu_find_struct_comp (ST_CHAR *compName,
RUNTIME_TYPE **rtIo, ST_INT *numRtIo,
ST_INT *offset_io,
ST_RTINT *prim_num_io);
static ST_VOID mvlu_handle_alt_acc (OBJECT_NAME *obj, ALT_ACCESS *alt_acc,
MVL_ARR_CTRL *arrCtrl);
static ST_RET getArrAARtType (MVL_ARR_CTRL *arrCtrl,
RUNTIME_TYPE **pRt, ST_INT *pNumRt);
static ST_VOID cloneArrAA (ALT_ACC_EL *arrAa, ALT_ACCESS *dest);
static ST_VOID mvlu_find_base_va (MVL_VMD_CTRL *vmd_ctrl, OBJECT_NAME *obj, MVL_NET_INFO *net_info, MVL_VAR_ASSOC **vaOut);
ST_RET getGnlVarNames (MVL_VAR_ASSOC *va, ST_CHAR *caPtr,
ST_CHAR **dest, ST_INT maxNames,
ST_INT *numNames, ST_BOOLEAN *moreFollowsOut);
static ST_VOID mvlu_clone_objname (OBJECT_NAME *dest, OBJECT_NAME *src);
static ST_VOID startArrRds (MVL_IND_PEND *indCtrl, MVLAS_READ_CTRL *rdCtrl,
MVLAS_RD_VA_CTRL *rdVaCtrl, RUNTIME_TYPE *rt, PRIM_INFO *prim_info);
static ST_VOID startElReads (MVL_IND_PEND *indCtrl, MVLAS_READ_CTRL *rdCtrl,
MVLAS_RD_VA_CTRL *rdVaCtrl,
RUNTIME_TYPE *rt, ST_INT rt_num, PRIM_INFO *prim_info);
static ST_VOID startArrWrs (MVL_IND_PEND *indCtrl, MVLAS_WRITE_CTRL *wrCtrl,
MVLAS_WR_VA_CTRL *wrVaCtrl, RUNTIME_TYPE *rt, PRIM_INFO *prim_info);
static ST_VOID startElWrites (MVL_IND_PEND *indCtrl, MVLAS_WRITE_CTRL *wrCtrl,
MVLAS_WR_VA_CTRL *wrVaCtrl,
RUNTIME_TYPE *rt, ST_INT rt_num, PRIM_INFO *prim_info);
static ST_INT countPrimEl (MVL_VAR_ASSOC *va, RUNTIME_TYPE *rt, ST_INT rt_num);
static ST_RET chk_var_writable (RUNTIME_TYPE *rt, ST_INT rt_num);
static ST_RET chk_write_resp_ready (MVL_IND_PEND *indCtrl);
static ST_VOID set_write_resp_dae (MVLAS_WR_VA_CTRL *wrVaCtrl,
ST_INT16 dae); /* DataAccessError code */
/************************************************************************/
/* Global function pointers. May be set by user. */
/************************************************************************/
/* This function pointer called BEFORE all write leaf functions. */
/* NOTE: called only for complex variables (struct or array). */
ST_RET (*u_mvl_wr_ind_var_start)(MVL_IND_PEND *indCtrl,
MVLAS_WR_VA_CTRL *wrVaCtrl); /* current var in list of var */
/* This function pointer called AFTER all write leaf functions. */
/* NOTE: called only for complex variables (struct or array). */
ST_RET (*u_mvl_wr_ind_var_end)(MVL_IND_PEND *indCtrl,
MVLAS_WR_VA_CTRL *wrVaCtrl); /* current var in list of var */
/************************************************************************/
/* init_prim_info */
/* Initialize PRIM_INFO struct using info saved in MVL_VAR_ASSOC. */
/************************************************************************/
ST_RET init_prim_info (MVL_VAR_ASSOC *va, PRIM_INFO *prim_info)
{
/* Just use values computed earlier & saved in va. */
prim_info->prim_num = va->prim_num;
prim_info->prim_offset = 0;
prim_info->prim_offset_base = va->offset_from_base;
return (SD_SUCCESS);
}
/************************************************************************/
/************************************************************************/
/* MANUFACTURED VARIABLE RESOLUTION FUNCTIONS */
/************************************************************************/
/* u_mvl_get_va_aa */
/************************************************************************/
/* This function is called from MVL when it is unable to find a */
/* configured MMS server variable for a READ, WRITE, or GET VARIABLE */
/* ACCESS ATTRIBUTES indication. */
MVL_VAR_ASSOC *u_mvl_get_va_aa (MVL_VMD_CTRL *vmd_ctrl, ST_INT service, OBJECT_NAME *obj,
MVL_NET_INFO *netInfo,
ST_BOOLEAN alt_access_pres,
ALT_ACCESS *alt_acc,
ST_BOOLEAN *alt_access_done_out)
{
ST_CHAR *name;
MVL_VAR_ASSOC *va;
MVL_VAR_ASSOC *baseVa;
ST_RET rc;
OBJECT_NAME *objClone; /*ptr to OBJECT_NAME plus 2 name strings*/
/* Space for OBJECT_NAME struct plus 2 name strings. */
/* objClone will point to this, passed to mvlu_clone_objname. */
/* CRITICAL: Must be a struct so alignment is correct. */
struct
{
ST_CHAR bytearray[_OBJ_NAME_CLONE_SIZE];
} objNameBuf;
RUNTIME_TYPE *baseRt;
ST_INT numBaseRt;
RUNTIME_TYPE *ucaRt;
ST_INT numUcaRt;
ST_CHAR *subStart;
ST_INT subTypeId;
MVL_ARR_CTRL arrCtrl;
ST_CHAR *flatname; /* flattened variable name (for mvlu_find_component)*/
RUNTIME_TYPE *comp_rt; /* set by mvlu_find_component */
ST_INT comp_num_rt; /* set by mvlu_find_component */
ST_INT offset_from_base; /* set by mvlu_find_component */
ST_RTINT prim_num; /* set by mvlu_find_component */
/* Make a working copy of the variable name (mvlu_handle_alt_acc may change it) */
objClone = (OBJECT_NAME *) (&objNameBuf);
mvlu_clone_objname (objClone, obj);
/* We will handle any alternate access here, by creating the UCA from */
/* variable name. */
memset (&arrCtrl, 0, sizeof (MVL_ARR_CTRL)); /* start with clean "arrCtrl"*/
if (alt_access_pres)
{
mvlu_handle_alt_acc (objClone, alt_acc, &arrCtrl);
*alt_access_done_out = SD_TRUE;
}
/* We need to find the base type for this variable */
mvlu_find_base_va (vmd_ctrl, objClone, netInfo, &baseVa);
if (baseVa == NULL)
{
MVL_LOG_NERR1 ("Could not resolve UCA variable '%s'", objClone->obj_name.vmd_spec);
return (NULL);
}
/* Use mvlu_find_component to compute offset_from_base & prim_num. */
/* Look for '$' in name. If found, point after it, else use NULL. */
flatname = strstr (obj->obj_name.vmd_spec, "$");
if (flatname != NULL)
flatname++; /* point after the '$' */
/* Start with base variable RUNTIME_TYPE. */
rc = mvl_get_runtime (baseVa->type_id, &comp_rt, &comp_num_rt);
if (rc != SD_SUCCESS)
{
MVL_LOG_NERR1 ("Could not get RT type for type id %d", baseVa->type_id);
return (NULL);
}
offset_from_base = 0;
prim_num = 0;
/* NOTE: mvlu_find_component changes comp_rt, comp_num_rt, */
/* offset_from_base, prim_num. */
/* NOTE: offset_from_base, prim_num different for each array elem.*/
/* CRITICAL: mvlu_find_component expects alt_acc=NULL if Alt Access */
/* Spec NOT present. Make sure "alt_acc" is set correctly. */
if (!alt_access_pres)
alt_acc = NULL; /* CRITICAL */
rc = mvlu_find_component (flatname, alt_acc,
&comp_rt, &comp_num_rt, &offset_from_base, &prim_num);
if (rc)
return (NULL); /* if this fails, stop now. */
/* Now resolve this variable's type given it's name and the base */
/* type. */
rc = mvl_get_runtime (baseVa->type_id, &baseRt, &numBaseRt);
if (rc != SD_SUCCESS)
{
MVL_LOG_NERR1 ("Could not get RT type for type id %d", baseVa->type_id);
return (NULL);
}
ucaRt = baseRt;
numUcaRt = numBaseRt;
/* Check to see if this is for base var... name has no embedded '$' */
/* If is a derived variable we need to create from the variable name */
/* 'path' and runtime type. */
name = objClone->obj_name.vmd_spec; /* We know this is a union ... */
subStart = strstr (name,"$"); /* Skip the outer (base) name */
if (subStart)
{
/* This is a derived variable, and we have the base UCA variable */
/* Using the base runtime table and the variable name, we can get the */
/* subset type for this variable */
++subStart;
rc = mvlu_find_uca_var (&ucaRt, &numUcaRt, subStart);
if (rc != SD_SUCCESS)
{
MVL_LOG_NERR1 ("Error - could not find subcomponent '%s'", subStart);
return (NULL);
}
}
/* If this is an alternate access on an array, we need to copy the */
/* RT type so we can modify the number of elements and total size */
if (arrCtrl.arrAltAccPres == SD_TRUE)
{
rc = getArrAARtType (&arrCtrl, &ucaRt, &numUcaRt);
if (rc != SD_SUCCESS)
{
M_FREE (MSMEM_MVLU_AA, arrCtrl.alt_acc.aa);
return (NULL);
}
}
/* Make sure type computed matches what mvlu_find_component computed. */
/* DEBUG: delete these before release? */
assert (comp_num_rt == numUcaRt);
assert (comp_rt->el_tag == ucaRt->el_tag);
assert (comp_rt->mvluTypeInfo.prim_count == ucaRt->mvluTypeInfo.prim_count);
/* OK, now we have the sub-runtime type, go ahead and create a temp */
/* RT type and variable association. */
rc = mvlu_add_rt_type (ucaRt, numUcaRt, &subTypeId);
if (rc != SD_SUCCESS)
{
MVL_LOG_NERR0 ("Error - could not add temp RT type");
return (NULL);
}
/* Create "derived" variable from baseVa. */
/* NOTE: This var is NOT added to list so its name is NOT sent */
/* in GetNameList responses. */
va = mvl_var_create_derived (objClone->obj_name.vmd_spec, subTypeId,
baseVa,
offset_from_base,
prim_num);
/* CRITICAL: If use_static_data==SD_FALSE, mvl_var_create_derived could */
/* not set "va->data". Must call this function to allocate it. */
/* NOTE: Since this code executes every time a variable is accessed, */
/* it requires MANY more allocations when use_static_data==SD_FALSE. */
if (baseVa->use_static_data==SD_FALSE)
mvluDefGetVaDataBufFun (service, va, ucaRt->offset_to_last);
#if defined(MVLU_USE_REF)
va->ref = ucaRt->mvluTypeInfo.ref;
#endif
/* Copy the array AA information */
memcpy (&va->arrCtrl, &arrCtrl, sizeof (MVL_ARR_CTRL));
va->arrCtrl.curr_index = arrCtrl.low_index;
/* Good work, we are done here. */
return (va);
}
/************************************************************************/
/* getArrAARtType */
/************************************************************************/
static ST_RET getArrAARtType (MVL_ARR_CTRL *arrCtrl,
RUNTIME_TYPE **pRt, ST_INT *pNumRt)
{
ST_INT numRt;
ST_INT i, j;
RUNTIME_TYPE *rt;
RUNTIME_TYPE *endRt;
RUNTIME_TYPE *newRt;
ALT_ACCESS *alt_acc;
ALT_ACC_EL *alt_acc_el; /* ptr to current entry in alt acc array */
ST_INT nest_level = 0;
rt = *pRt;
numRt = *pNumRt;
/* Check to see if further nesting with this AA selection ... */
if (arrCtrl->nested == SD_FALSE)
{
/* If just one element, need to lose the outer array */
if (arrCtrl->num_elmnts == 1)
{
numRt -= 2;
++rt;
}
}
else /* Further nesting is requested, let's do it! */
{
/* We only support a single drill down AA */
if (arrCtrl->num_elmnts > 1)
{
MVL_LOG_NERR0 ("AA resolution problem - multiple elements and nested");
return (SD_FAILURE);
}
numRt -= 2;
++rt;
/* OK, we now need to find the type of the component ... */
alt_acc = &arrCtrl->alt_acc;
/* Only support AA_COMP and AA_COMP_NEST for now. */
/* If AA_COMP_NEST is used, this is recursive process. */
for (j=0; j < alt_acc->num_aa; j++)
{
alt_acc_el = &alt_acc->aa[j];
if (alt_acc_el->sel_type == AA_COMP || alt_acc_el->sel_type == AA_COMP_NEST)
{
if (alt_acc_el->sel_type == AA_COMP_NEST)
nest_level++;
/* find this component name within the current RUNTIME_TYPE array*/
for (i = 0; i < numRt; ++i, ++rt)
{
if (!strcmp (alt_acc_el->u.component, ms_comp_name_find (rt)))
break;
}
if (i >= numRt)
{
MVL_LOG_NERR1 ("AA resolution problem - could not find component '%s'",
alt_acc_el->u.component);
return (SD_FAILURE);
}
if (rt->el_tag == RT_STR_START)
numRt = rt->u.str.num_rt_blks+2;
else if (rt->el_tag == RT_ARR_START)
numRt = rt->u.arr.num_rt_blks+2;
else
numRt = 1;
}
else if (alt_acc_el->sel_type == AA_END_NEST)
nest_level--;
else
{
MVL_LOG_NERR0 ("AA resolution problem - complex nested AA on array");
return (SD_FAILURE);
}
} /* end "for" loop */
if (nest_level != 0)
{
MVL_LOG_NERR0 ("AA resolution problem - invalid nesting");
return (SD_FAILURE);
}
}
/* OK, now copy the runtime type elements into a new one so we can fool */
/* with it. */
newRt = (RUNTIME_TYPE *) M_MALLOC (MSMEM_DYN_RT, numRt * sizeof (RUNTIME_TYPE));
memcpy (newRt, rt, numRt * sizeof (RUNTIME_TYPE));
/* Adjust the total size of the type, using scaling */
if (arrCtrl->num_elmnts > 1)
{
newRt->offset_to_last = rt[1].offset_to_last * arrCtrl->num_elmnts;
/* Now set the number of elements as desired */
newRt->u.arr.num_elmnts = arrCtrl->num_elmnts;
endRt = newRt + (newRt->u.arr.num_rt_blks + 1);
endRt->u.arr.num_elmnts = arrCtrl->num_elmnts;
/* We don't want end of array padding */
endRt->el_size = 0;
}
*pRt = newRt;
*pNumRt = numRt;
return (SD_SUCCESS);
}
/************************************************************************/
/* mvlu_handle_alt_acc */
/************************************************************************/
/* Here we deal with an alternate access. We will simply add the */
/* sub-name components to the base name to create a fully qualified UCA */
/* sub-var name */
/* Of course, this only handles the most simple form of alternate */
/* access correctly ... */
static ST_VOID mvlu_handle_alt_acc (OBJECT_NAME *obj, ALT_ACCESS *alt_acc,
MVL_ARR_CTRL *arrCtrl)
{
ST_INT i;
ST_CHAR *name;
ST_BOOLEAN done;
name = obj->obj_name.vmd_spec; /* We know this is a union ... */
arrCtrl->nested = SD_FALSE;
done = SD_FALSE;
for (i = 0; i < alt_acc->num_aa && !done; ++i)
{
switch (alt_acc->aa[i].sel_type)
{
case AA_COMP :
case AA_COMP_NEST :
strcat (name, "$");
strcat (name, alt_acc->aa[i].u.component);
break;
case AA_INDEX_NEST :
arrCtrl->nested = SD_TRUE;
cloneArrAA (&alt_acc->aa[i], &arrCtrl->alt_acc);
/* Lets fall through into common code ... */
case AA_INDEX :
arrCtrl->arrAltAccPres = SD_TRUE;
arrCtrl->low_index = (ST_RTINT) alt_acc->aa[i].u.index;
arrCtrl->num_elmnts = 1;
done = SD_TRUE;
break;
case AA_INDEX_RANGE_NEST :
arrCtrl->nested = SD_TRUE;
cloneArrAA (&alt_acc->aa[i], &arrCtrl->alt_acc);
/* Lets fall through into common code ... */
case AA_INDEX_RANGE :
arrCtrl->arrAltAccPres = SD_TRUE;
arrCtrl->low_index = (ST_RTINT) alt_acc->aa[i].u.ir.low_index;
arrCtrl->num_elmnts = (ST_RTINT) alt_acc->aa[i].u.ir.num_elmnts;
done = SD_TRUE;
break;
case AA_ALL:
case AA_ALL_NEST :
arrCtrl->nested = SD_TRUE;
cloneArrAA (&alt_acc->aa[i], &arrCtrl->alt_acc);
arrCtrl->arrAltAccPres = SD_TRUE;
arrCtrl->low_index = 0;
arrCtrl->num_elmnts = 0; /* 'all' flag */
done = SD_TRUE;
break;
case AA_END_NEST :
done = SD_TRUE;
break;
default:
MVL_LOG_NERR1 ("Error: Invalid alt access sel_type = %d",
alt_acc->aa[i].sel_type);
break;
}
}
}
/************************************************************************/
/* cloneArrAA */
/************************************************************************/
static ST_VOID cloneArrAA (ALT_ACC_EL *arrAa, ALT_ACCESS *dest)
{
ST_INT elCount;
ST_INT nestLevel;
ALT_ACC_EL *aaEl;
/* First let's count how many we need */
nestLevel = 0;
elCount = 0;
aaEl = arrAa + 1;
while (SD_TRUE)
{
if (nestLevel == 0 && aaEl->sel_type == AA_END_NEST)
break;
++elCount;
if (aaEl->sel_type == AA_COMP_NEST ||
aaEl->sel_type == AA_INDEX_NEST ||
aaEl->sel_type == AA_INDEX_RANGE_NEST ||
aaEl->sel_type == AA_ALL_NEST)
{
++nestLevel;
}
if (aaEl->sel_type == AA_END_NEST)
{
--nestLevel;
}
++aaEl;
}
/* OK, now just calloc and copy the nested alternate access */
if (elCount)
{
dest->num_aa = elCount;
dest->aa = (ALT_ACC_EL *) M_MALLOC (MSMEM_MVLU_AA, elCount * sizeof (ALT_ACC_EL));
memcpy (dest->aa, arrAa+1, elCount * sizeof (ALT_ACC_EL));
}
else
{
MVL_LOG_NERR0 ("Nested AA construction problem");
}
}
/************************************************************************/
/* mvlu_find_base_va */
/************************************************************************/
/* This function takes a MMS variable name and determines the type ID */
/* for the base type for the variable. This is done here by */
/* extracting the name root then looking for a configured variable */
/* of that name. */
static ST_VOID mvlu_find_base_va (MVL_VMD_CTRL *vmd_ctrl, OBJECT_NAME *obj, MVL_NET_INFO *net_info, MVL_VAR_ASSOC **vaOut)
{
MVL_VAR_ASSOC *va;
ST_CHAR *p;
ST_CHAR *name;
OBJECT_NAME *objClone; /*ptr to OBJECT_NAME plus 2 name strings*/
/* Space for OBJECT_NAME struct plus 2 name strings. */
/* objClone will point to this, passed to mvlu_clone_objname. */
/* CRITICAL: Must be a struct so alignment is correct. */
struct
{
ST_CHAR bytearray[_OBJ_NAME_CLONE_SIZE];
} objNameBuf;
objClone = (OBJECT_NAME *) (&objNameBuf);
mvlu_clone_objname (objClone, obj);
name = objClone->obj_name.vmd_spec; /* We know this is a union ... */
/* See if this variable name has embedded '$', and if so wack it so */
/* that we have the base name to work with. */
p = strstr (name,"$");
if (p)
*p = 0;
va = mvl_vmd_find_var (vmd_ctrl, objClone, net_info);
if (va && (va->flags & MVL_VAR_FLAG_UCA) == 0)
va = NULL; /* Found va but not UCA variable, so don't return it. */
*vaOut = va;
}
/************************************************************************/
/* mvlu_find_uca_var */
/************************************************************************/
/* This function searches a runtime type for the given UCA variable */
/* name. It does this by breaking the UCA name into its components */
/* and then finding the name in the current level of the runtime type. */
ST_RET mvlu_find_uca_var (RUNTIME_TYPE **rtIo, ST_INT *numRtIo,
ST_CHAR *varName)
{
ST_CHAR nameBuf[MAX_IDENT_LEN+1];
ST_CHAR *nameToFind;
ST_CHAR *compEnd,*arr;
ST_BOOLEAN nameDone;
ST_RET ret;
ST_INT offset=0; /* mvlu_find_struct_comp needs it but not used */
ST_RTINT prim_num=0; /* mvlu_find_struct_comp needs it but not used */
/* Note that varName does not have the base name prefix */
strcpy (nameBuf, varName);
nameToFind = nameBuf;
nameDone = SD_FALSE;
while (nameDone == SD_FALSE)
{
/* Isolate the component name for this level, removing subcomp names */
compEnd = strstr (nameToFind, "$");
if (compEnd != NULL)
*compEnd = 0;
else /* This is the last nest level */
nameDone = SD_TRUE;
/*renxiaobao <20><><EFBFBD><EFBFBD>*/
arr = strstr (nameToFind, "[");
if (arr != NULL)
*arr = 0;
/* Find the component name in the current runtime type nest level */
ret = mvlu_find_struct_comp (nameToFind, rtIo, numRtIo, &offset, &prim_num);
if (ret == SD_FAILURE)
{
/* Many things can cause this so just use FLOW Logging. */
MVLU_LOG_FLOW2 ("Could not find name component %s from name %s",
nameToFind, varName);
return (SD_FAILURE);
}
/* OK, we now have found the component in the runtime type, and our */
/* runtime pointer and numRt reflect the sub-runtime type. */
/* next component. */
/* Prepare to find the next level component name */
nameToFind = compEnd+1;
}
return (SD_SUCCESS);
}
/************************************************************************/
/* mvlu_find_struct_comp */
/************************************************************************/
/* This function searches a structure runtime type for the given */
/* component name at the outer level. */
/* NOTE: modifies (*rtIo), (*numRtIo), (*offset_io), (*prim_num_io). */
static ST_RET mvlu_find_struct_comp (ST_CHAR *compName,
RUNTIME_TYPE **rtIo, ST_INT *numRtIo,
ST_INT *offset_io,
ST_RTINT *prim_num_io)
{
RUNTIME_TYPE *rt;
RUNTIME_TYPE *endRt;
ST_BOOLEAN foundRt;
foundRt = SD_FALSE;
rt = *rtIo;
endRt = rt + *numRtIo;
/* renxiaobao <20><><EFBFBD><EFBFBD>*/
if (rt->el_tag == RT_ARR_START)
{
++rt;
}
if (rt->el_tag != RT_STR_START)
{
MVL_LOG_NERR0 ("Find struct comp: First RT is not structure start");
return (SD_FAILURE);
}
++rt; /* Skip the structure start */
while (rt < endRt)
{
if (!strcmp (compName, ms_comp_name_find (rt)))
{
*rtIo = rt;
foundRt = SD_TRUE;
}
switch (rt->el_tag)
{
case RT_STR_START :
if (foundRt == SD_TRUE)
{
*numRtIo = rt->u.str.num_rt_blks+2;
return (SD_SUCCESS);
}
/* Not found yet. */
*offset_io += rt->offset_to_last; /* adjust offset */
*prim_num_io += rt->mvluTypeInfo.prim_count; /* adjust prim_num*/
rt += rt->u.str.num_rt_blks+2; /* Skip the structure contents */
break;
case RT_ARR_START :
if (foundRt == SD_TRUE)
{
*numRtIo = rt->u.arr.num_rt_blks+2;
return (SD_SUCCESS);
}
/* Not found yet. */
*offset_io += rt->offset_to_last; /* adjust offset */
*prim_num_io += rt->mvluTypeInfo.prim_count; /* adjust prim_num*/
rt += rt->u.arr.num_rt_blks+1; /* Skip the array contents */
break;
case RT_STR_END :
case RT_ARR_END :
++rt;
break;
default:
if (foundRt == SD_TRUE)
{
*numRtIo = 1;
return (SD_SUCCESS);
}
/* Not found yet. */
*offset_io += rt->offset_to_last; /* adjust offset */
*prim_num_io += rt->mvluTypeInfo.prim_count; /* adjust prim_num*/
++rt;
break;
}
}
return (SD_FAILURE);
}
/************************************************************************/
/* u_mvl_free_va */
/************************************************************************/
/* MVL calls this function when it is through with it. We will free */
/* the data buffer, and then the VA (unless it was a base VA). */
ST_VOID u_mvl_free_va (ST_INT service, MVL_VAR_ASSOC *va,
MVL_NET_INFO *netInfo)
{
RUNTIME_TYPE *ucaRt;
ST_INT numUcaRt;
ST_RET rc;
/* If "va->data" was allocated, free it now. */
if (va->base_va->use_static_data==SD_FALSE)
mvluDefFreeVaDataBufFun(service, va);
/* If this was not a 'base' VA, free the derived type */
if ( (va->flags & MVL_VAR_FLAG_UCA) == 0)
{
/* See if we allocated the runtime type ... */
if (va->arrCtrl.arrAltAccPres == SD_TRUE)
{
rc = mvl_get_runtime (va->type_id, &ucaRt, &numUcaRt);
if (rc == SD_SUCCESS)
M_FREE (MSMEM_DYN_RT, ucaRt);
else
{
MVL_LOG_NERR0 ("Error: internal error");
}
if (va->arrCtrl.nested == SD_TRUE)
M_FREE (MSMEM_MVLU_AA, va->arrCtrl.alt_acc.aa);
}
mvlu_free_rt_type (va->type_id);
mvl_var_destroy (va);
}
}
/************************************************************************/
/************************************************************************/
/* MANUFACTURED VARIABLE_LIST RESOLUTION FUNCTIONS */
/************************************************************************/
/* u_mvl_get_nvl, u_mvl_free_nvl functions deleted (no longer needed). */
/* They were only needed because Foundry could not find the variables */
/* for the NVL to set "vl->entries". But new improved Foundry */
/* generates code like the following (only done once at startup, */
/* so it is much more efficient): */
/*
* varObjName.obj_name.vmd_spec = "DI$Name";
* varObjName.object_tag = DOM_SPEC;
* varObjName.domain_id = mvl_vmd.dom_tbl[6]->name;
* vl->entries [0] = u_mvl_get_va_aa (MMSOP_INFO_RPT, &varObjName, NULL, SD_FALSE, NULL, NULL);
*/
/************************************************************************/
/************************************************************************/
/* GET NAMELIST HELPER FUNCTIONS */
/* These functions are necessary because MVL does not know about our */
/* manufactured variables and variable lists. We will fill in part of */
/* the namelist response data structure. */
/************************************************************************/
/************************************************************************/
/* u_gnl_ind_vars */
/************************************************************************/
ST_INT u_gnl_ind_vars (MVL_NET_INFO *net_info, NAMELIST_REQ_INFO *req_info,
ST_CHAR **ptr, ST_BOOLEAN *moreFollowsOut,
ST_INT maxNames)
{
ST_INT i;
ST_INT numRespNames;
ST_CHAR caBuf[100];
ST_CHAR *caPtr;
ST_CHAR *p;
ST_INT numVa;
ST_INT v;
MVL_VAR_ASSOC **va;
MVL_AA_OBJ_CTRL *aa;
MVL_DOM_CTRL *domCtrl;
gnlNameBuf = (ST_CHAR *) M_CALLOC (MSMEM_MVLU_GNL, 1, maxNames * (MAX_IDENT_LEN +1));
/* Start by finding the VA that we should start with */
/* Get the variable associations in the selected scope */
numVa = 0;
if (req_info->objscope == VMD_SPEC)
{
numVa = mvl_vmd.num_var_assoc;
va = mvl_vmd.var_assoc_tbl;
}
else if (req_info->objscope == DOM_SPEC)
{
domCtrl = mvl_vmd_find_dom (&mvl_vmd, req_info->dname);
if (domCtrl)
{
numVa = domCtrl->num_var_assoc;
va = domCtrl->var_assoc_tbl;
}
else
{
MVL_LOG_NERR1 ("GetNameList variables: Domain '%s' not found", req_info->dname);
*moreFollowsOut = SD_FALSE;
return (-1); /* error. This triggers error response */
}
}
else /* AA_SPEC */
{
aa = (MVL_AA_OBJ_CTRL *) net_info->aa_objs;
if (aa)
{
numVa = aa->num_var_assoc;
va = aa->var_assoc_tbl;
}
else
{
*moreFollowsOut = SD_FALSE;
return (-1); /* error. This triggers error response */
}
}
/* Take care of the 'continue after' business as necessary. Note that */
/* we will only look at the base name. */
i = 0;
if (req_info->cont_after_pres)
{
caPtr = req_info->continue_after;
strcpy (caBuf, req_info->continue_after);
p = strstr (caBuf,"$");
if (p)
*p = 0;
while (i < numVa)
{
p = va[i]->name;
v = strcmp (caBuf, p);
if (v == 0) /* Exact match */
break;
if (v < 0) /* CA is less than real VA name */
{
if (i > 0) /* Start with the previous VA */
--i;
break;
}
++i; /* We have not found our place yet ... */
}
}
else
caPtr = NULL;
*moreFollowsOut = SD_FALSE;
currGnlNamePos = gnlNameBuf;
/* OK, va[i] is where we start putting together our names */
for (numRespNames = 0; numRespNames < maxNames && i < numVa; ++i)
{
ST_INT j;
ST_INT numRespNamesStart = numRespNames; /* save count modified by fct*/
if (getGnlVarNames (va[i], caPtr, &ptr[numRespNames],
maxNames, &numRespNames, moreFollowsOut) != SD_SUCCESS)
return (-1); /* error response will be sent */
MVLU_LOG_DEBUG0 ("Names returned from getGnlVarNames");
for (j = numRespNamesStart; j<numRespNames; j++)
MVLU_LOG_CDEBUG2 ("[%d]%s", j, ptr[j]);
caPtr = NULL;
}
if (i < numVa)
*moreFollowsOut = SD_TRUE;
return (numRespNames);
}
/************************************************************************/
/* getGnlVarNames */
/************************************************************************/
/* GNL Variables defines */
#define MAX_NEST_LEVEL 10
ST_RET getGnlVarNames (MVL_VAR_ASSOC *va, ST_CHAR *caPtr,
ST_CHAR **dest, ST_INT maxNames,
ST_INT *numNames, ST_BOOLEAN *moreFollowsOut)
{
RUNTIME_TYPE *ucaRt;
ST_INT numUcaRt;
ST_INT i;
ST_CHAR nameBuf[MAX_IDENT_LEN+1];
ST_INT nameCount;
ST_INT maxSortedNum;
ST_INT sortedNum;
ST_INT startSortedNum;
ST_CHAR *subStart;
ST_RET rc;
ST_INT baseIndexOffset;
ST_INT maxRetNames;
/* prefix len should never reach MAX_IDENT_LEN but could get very close*/
ST_CHAR namePrefix[MAX_NEST_LEVEL][MAX_IDENT_LEN+1];
ST_INT nestLevel;
ST_INT strLen;
ST_INT get;
ST_INT put;
ST_INT numNewNames;
ST_BOOLEAN compress;
ST_CHAR *comp_name; /* component name */
if ( (va->flags & MVL_VAR_FLAG_UCA) == 0)
{
++(*numNames);
dest[0] = va->name;
return (SD_SUCCESS);
}
memset (namePrefix, 0, sizeof(namePrefix));
strcpy (namePrefix[0], va->name);
/* First we need to find the starting 'sortedNum', based on the CA name */
nameCount = *numNames;
startSortedNum = 1;
if (caPtr != NULL)
{
baseIndexOffset = 0;
/* CA name could be base name, or derived name. */
if (strcmp (caPtr, va->name) == 0)
{ /* CA name equals base name. Start with next name AFTER base. */
startSortedNum = 1;
}
else if ((subStart = strstr (caPtr,"$")) == NULL) /* Skip the base name*/
{
MVL_LOG_ERR1 ("Problem finding sub-type in '%s'", caPtr);
return (SD_FAILURE);
}
else
{
rc = mvl_get_runtime (va->type_id, &ucaRt, &numUcaRt);
++subStart;
rc = mvlu_find_uca_var (&ucaRt, &numUcaRt, subStart);
if (rc == SD_SUCCESS)
startSortedNum = ucaRt->mvluTypeInfo.sortedNum + 1;
}
}
else /* No continue after, we need to include the base name */
{
dest[0] = va->name;
++nameCount;
baseIndexOffset = 1;
--maxNames;
}
maxRetNames = maxNames - *numNames;
maxSortedNum = startSortedNum + maxRetNames - 1;
/* OK, now we start doing the real thing. Derive names for this */
/* type, put them into the dest array. */
/* We will save those elements with 'sortedNum' between */
/* 'startSortedNum' and 'maxSortedNum' */
compress = SD_FALSE;
rc = mvl_get_runtime (va->type_id, &ucaRt, &numUcaRt);
/* This code assumes all UCA vars are structs, so first tag must be RT_STR_START*/
/* DEBUG: change this to "assert"? */
if (ucaRt->el_tag != RT_STR_START)
MVL_LOG_ERR1 ("IEC/UCA type (type_id=%d) is not a struct. Cannot derive variable names for GetNameList response.",
va->type_id);
nestLevel = 0;
for (i = 0; i < numUcaRt; ++i, ++ucaRt)
{
sortedNum = ucaRt->mvluTypeInfo.sortedNum;
comp_name = ms_comp_name_find (ucaRt);
if (strlen (comp_name) &&
sortedNum >= startSortedNum && sortedNum <= maxSortedNum)
{
/* Chk len is legal BEFORE writing (need room for 2 strings + '$'.*/
if (strlen (namePrefix[nestLevel]) + strlen (comp_name) + 1 <= MAX_IDENT_LEN)
{
sprintf (nameBuf, "%s$%s", namePrefix[nestLevel], comp_name);
strLen = strlen (nameBuf);
assert (strLen <= MAX_IDENT_LEN); /* if this fails, len chk in "if" is wrong*/
dest[sortedNum-startSortedNum+baseIndexOffset] = currGnlNamePos;
strcpy (currGnlNamePos, nameBuf);
currGnlNamePos += strLen +1;
++nameCount;
}
else
{
/* NOTE: should never happen if len checked in _mvlu_save_rt_uca_name at startup.*/
MVL_LOG_ERR2 ("GetNameList error: Derived variable name '%s$%s' too long",
namePrefix[nestLevel], comp_name);
compress = SD_TRUE;
}
}
if (ucaRt->el_tag == RT_STR_START)
{
comp_name = ms_comp_name_find (ucaRt);
if (strlen (comp_name))
{
/* Chk len is legal BEFORE writing (need room for 2 strings + '$').*/
if (strlen (namePrefix[nestLevel]) + strlen (comp_name) + 1 <= MAX_IDENT_LEN)
{
++nestLevel;
assert (nestLevel < MAX_NEST_LEVEL);
assert (nestLevel > 0);
strcpy (namePrefix[nestLevel], namePrefix[nestLevel-1]);
strcat (namePrefix[nestLevel], "$");
strcat (namePrefix[nestLevel], comp_name);
}
else
{
/* NOTE: should never happen if len checked in _mvlu_save_rt_uca_name at startup.*/
MVL_LOG_ERR2 ("GetNameList error: Flattened variable name too long for struct '%s$%s'",
namePrefix[nestLevel], comp_name);
MVL_LOG_CERR0 ("Flattened name of struct and all lower components cannot be returned");
compress=SD_TRUE;
/* Skip to end of struct */
i += (ucaRt->u.str.num_rt_blks + 1);
ucaRt += (ucaRt->u.str.num_rt_blks + 1);
}
}
}
else if (ucaRt->el_tag == RT_STR_END)
--nestLevel;
else if (ucaRt->el_tag == RT_ARR_START)
{ /* Skip the array elements */
/* There is no way to create UCA names for objects inside an */
/* array, so skip over the array. */
i += (ucaRt->u.arr.num_rt_blks + 1);
ucaRt += (ucaRt->u.arr.num_rt_blks + 1);
}
if (sortedNum > maxSortedNum)
*moreFollowsOut = SD_TRUE;
}
/* DEBUG: at this point loop, 'nestLevel' should equal (-1). This may */
/* sound strange, but nestLevel NOT incremented on first RT_STR_START,*/
/* so last RT_STR_END makes it -1. Add assert here? */
/* If we had to skip one or more names, we need to eliminate the */
/* holes in the name pointer table. */
if (compress == SD_TRUE)
{
get = 0;
put = 0;
numNewNames = nameCount - *numNames;
while (put < numNewNames)
{
if (dest[get] != NULL)
dest[put++] = dest[get];
++get;
}
}
*numNames = nameCount;
return (SD_SUCCESS);
}
/************************************************************************/
/* u_gnl_done */
/************************************************************************/
/* This function is called after MVL has send the MMS response to a */
/* GET_NAME_LIST indication. We will clean up memory resources. */
ST_VOID u_gnl_done (ST_INT16 mms_class,
NAMELIST_RESP_INFO *resp_info)
{
if (mms_class == MMS_CLASS_VAR)
M_FREE (MSMEM_MVLU_GNL, gnlNameBuf);
}
/************************************************************************/
/************************************************************************/
/* u_gnl_ind_nvls */
/************************************************************************/
ST_INT u_gnl_ind_nvls (MVL_NET_INFO *net_info, NAMELIST_REQ_INFO *req_info,
ST_CHAR **ptr, ST_BOOLEAN *moreFollowsOut,
ST_INT maxNames)
{
ST_INT v;
ST_INT i;
ST_INT num_obj;
MVL_AA_OBJ_CTRL *aa;
MVL_NVLIST_CTRL **vl;
MVL_DOM_CTRL *domCtrl;
ST_INT startIndex;
ST_INT numObjLeft;
ST_INT numRetNames;
ST_CHAR *name;
/* First get the number of objects and pointer to the object table */
num_obj = 0;
if (req_info->objscope == VMD_SPEC)
{
num_obj = mvl_vmd.num_nvlist;
vl = mvl_vmd.nvlist_tbl;
}
else if (req_info->objscope == DOM_SPEC)
{
domCtrl = mvl_vmd_find_dom (&mvl_vmd, req_info->dname);
if (domCtrl)
{
num_obj = domCtrl->num_nvlist;
vl = domCtrl->nvlist_tbl;
}
else
{
MVL_LOG_NERR1 ("GetNameList NVL: Domain '%s' not found", req_info->dname);
*moreFollowsOut = SD_FALSE;
return (-1); /* error. This triggers error response */
}
}
else /* AA_SPEC */
{
aa = (MVL_AA_OBJ_CTRL *) net_info->aa_objs;
if (aa)
{
num_obj = aa->num_nvlist;
vl = aa->nvlist_tbl;
}
else
{
*moreFollowsOut = SD_FALSE;
return (-1); /* error. This triggers error response */
}
}
if (num_obj)
{
/* Take care of the 'continue after' business if necessary */
startIndex = 0;
if (req_info->cont_after_pres)
{
while (startIndex < num_obj)
{
name = vl[startIndex]->name;
v = strcmp (req_info->continue_after, name);
if (v == 0)
{
++startIndex; /* Index to the next one */
break;
}
if (v < 0)
break;
++startIndex; /* We have not found our place yet ... */
}
}
numObjLeft = num_obj-startIndex;
numRetNames = min(numObjLeft, maxNames);
if (numRetNames < numObjLeft)
*moreFollowsOut = SD_TRUE;
/* Now make the list for the response */
for (i = 0; i < numRetNames; ++i, ++ptr)
*ptr = vl[startIndex+i]->name;
return (numRetNames);
}
return (0);
}
/************************************************************************/
/************************************************************************/
/* mvlu_clone_objname */
/************************************************************************/
/* This function 'clones' a MMS OBJECT_NAME structure, which means that */
/* it must allocate the various storage elements as required. Note */
/* that the name storage allocation is 65, to give calling routines */
/* room to work. */
static ST_VOID mvlu_clone_objname (OBJECT_NAME *dest, OBJECT_NAME *src)
{
memset (dest, 0, _OBJ_NAME_CLONE_SIZE);
dest->object_tag = src->object_tag;
dest->obj_name.vmd_spec = (ST_CHAR *) (dest + 1);
strcpy (dest->obj_name.vmd_spec, src->obj_name.vmd_spec);
if (src->object_tag == DOM_SPEC)
{
dest->domain_id = dest->obj_name.vmd_spec + _OBJ_NAME_CLONE_NAME_SIZE;
strcpy (dest->domain_id, src->domain_id);
}
}
/************************************************************************/
/************************************************************************/
/* MVLU READ/WRITE HANDLERS */
/************************************************************************/
static ST_VOID mvluDefAsyncWrIndFun (struct mvlu_wr_va_ctrl *mvluWrVaCtrl);
static ST_VOID mvluDefAsyncRdIndFun (struct mvlu_rd_va_ctrl *mvluRdVaCtrl);
/* Function pointers for non-UCA variable handling */
ST_VOID(*mvluAsyncRdIndFun)(struct mvlu_rd_va_ctrl *mvluRdVaCtrl) =
mvluDefAsyncRdIndFun;
ST_VOID(*mvluAsyncWrIndFun)(struct mvlu_wr_va_ctrl *mvluWrVaCtrl) =
mvluDefAsyncWrIndFun;
/************************************************************************/
/************************************************************************/
/************************************************************************/
/* mvl_read_ind */
/************************************************************************/
ST_VOID u_mvl_read_ind (MVL_IND_PEND *indCtrl)
{
MVLAS_READ_CTRL *rdCtrl;
MVLAS_RD_VA_CTRL *rdVaCtrl;
MVL_VAR_ASSOC *va;
MVLU_RD_VA_CTRL *mvluRdVaCtrl;
ST_INT i;
ST_INT numVar;
RUNTIME_TYPE *rt;
ST_INT numRt;
PRIM_INFO prim_info;
rdCtrl = &indCtrl->u.rd;
numVar = rdCtrl->numVar;
/* First we will go through each variable being read and count the */
/* primitive elelemts. */
rdVaCtrl = rdCtrl->vaCtrlTbl;
for (i = 0; i < numVar; ++i, ++rdVaCtrl)
{
va = rdVaCtrl->va;
if (va) /* VA was resolved, we can deal with it */
{
mvl_get_runtime (va->type_id, &rt, &numRt);
rdVaCtrl->acc_rslt_tag = ACC_RSLT_SUCCESS;
rdVaCtrl->numPrimDataDone = 0;
if (va->base_va != NULL) /* UCA variable handling ... */
{
rdVaCtrl->numPrimData = countPrimEl (va, rt, numRt);
}
else
rdVaCtrl->numPrimData = 1;
}
else
rdVaCtrl->numPrimData = 1;
}
/* Now we will go through each var being read and invoke the rdInd */
/* function for it. */
rdVaCtrl = rdCtrl->vaCtrlTbl;
for (i = 0; i < numVar; ++i, ++rdVaCtrl)
{
va = rdVaCtrl->va;
if (va) /* VA was resolved, we can deal with it */
{
/* The VA's data pointer is valid, as is the type ID. */
/* We want to call the handlers for all primitive level functions */
/* for this data type */
if (va->base_va != NULL) /* UCA variable handling ... */
{
mvl_get_runtime (va->type_id, &rt, &numRt);
/* Initialize prim_info struct. */
if (init_prim_info (va, &prim_info))
{ /* Failed. Can't process this var. Skip to next var in list*/
MVL_LOG_ERR1 ("init_prim_info failed for 'Read' of variable '%s'", va->name);
rdVaCtrl->acc_rslt_tag = ACC_RSLT_FAILURE;
continue; /* skip to next variable */
}
startElReads (indCtrl, rdCtrl, rdVaCtrl, rt, numRt, &prim_info);
}
else /* Non-UCA variable handling ... */
{
mvluRdVaCtrl = (MVLU_RD_VA_CTRL *) M_CALLOC (MSMEM_MVLU_VA_CTRL, 1,
sizeof (MVLU_RD_VA_CTRL));
mvluRdVaCtrl->primData = (ST_CHAR *) va->data;
mvluRdVaCtrl->indCtrl = indCtrl;
mvluRdVaCtrl->rdVaCtrl = rdVaCtrl;
(*mvluAsyncRdIndFun)(mvluRdVaCtrl);
}
}
else /* VA not found, let it be done */
{
mvluRdVaCtrl = (MVLU_RD_VA_CTRL *) M_CALLOC (MSMEM_MVLU_VA_CTRL, 1,
sizeof (MVLU_RD_VA_CTRL));
mvluRdVaCtrl->indCtrl = indCtrl;
mvluRdVaCtrl->rdVaCtrl = rdVaCtrl;
mvlu_rd_prim_done (mvluRdVaCtrl, SD_SUCCESS);
}
}
}
/************************************************************************/
/* mvlu_trim_branch_name */
/* Find last '$' in name and replace it with NULL. */
/************************************************************************/
ST_VOID mvlu_trim_branch_name (ST_CHAR *branch_name)
{
ST_CHAR *ptr;
if ((ptr = strrchr (branch_name, '$')) != NULL) /* find last '$'*/
*ptr = 0; /* replace '$' with NULL */
return;
}
/************************************************************************/
/* startElReads */
/************************************************************************/
static ST_VOID startElReads (MVL_IND_PEND *indCtrl, MVLAS_READ_CTRL *rdCtrl,
MVLAS_RD_VA_CTRL *rdVaCtrl,
RUNTIME_TYPE *rt, ST_INT rt_num, PRIM_INFO *prim_info)
{
ST_INT i;
MVLU_RD_VA_CTRL *mvluRdVaCtrl;
ST_RTINT rdIndFunIndex;
ST_UCHAR el_tag;
ST_INT el_size;
ST_RTINT num_rt_blks;
#if defined(MVL_XNAME)
ST_CHAR element_name[MAX_IDENT_LEN+1];
ST_CHAR branch_name[MAX_IDENT_LEN+1];
MVL_VAR_ASSOC *va;
ST_CHAR *comp_name;
#endif
#if defined(MVL_XNAME)
va = rdVaCtrl->va;
element_name[0]=0;
strcpy (branch_name,va->name);
/* if this is a substructure we need to trim back one level of the name */
/* because the first rt element will be the name of the component */
/* already part of the va->name */
if ((rt_num > 1) && (strstr (branch_name,"$")))
{
mvlu_trim_branch_name (branch_name);
}
#endif
for (i = 0; i < rt_num; ++i, ++rt)
{
#if defined(MVL_XNAME)
if (rt_num > 1)
{
comp_name = ms_comp_name_find (rt);
if (strlen (comp_name))
{
if ((rt->el_tag == RT_STR_START))
{
strcat (branch_name, "$");
strcat (branch_name, comp_name);
strcpy (element_name, branch_name);
}
else
{
element_name[0]=0;
strcat (element_name, branch_name);
strcat (element_name, "$");
strcat (element_name, comp_name);
}
}
if (rt->el_tag == RT_STR_END)
{
strcpy (element_name, branch_name);
mvlu_trim_branch_name (branch_name);
}
}
else
{ /* only one element in the RT table assume it's a primitive */
strcpy (element_name, branch_name);
}
#endif
el_tag = rt->el_tag;
num_rt_blks = rt->u.arr.num_rt_blks;
el_size = rt->el_size;
if (ms_is_rt_prim (rt) == SD_TRUE)
{
rdIndFunIndex = rt->mvluTypeInfo.rdIndFunIndex;
if (u_mvlu_leaf_rd_ind_fun != NULL ||
//(rdIndFunIndex >= 0 && rdIndFunIndex < mvluNumRdFunEntries))//lnk<6E><6B><EFBFBD><EFBFBD><EFBFBD>޸ģ<DEB8>ԭǰ<D4AD>ó<EFBFBD><C3B3><EFBFBD>δʹ<CEB4><CAB9>
0)//lnk<6E><6B><EFBFBD><EFBFBD><EFBFBD>޸ģ<DEB8>ԭǰ<D4AD>ó<EFBFBD><C3B3><EFBFBD>δʹ<CEB4><CAB9>
{
mvluRdVaCtrl = (MVLU_RD_VA_CTRL *) M_CALLOC (MSMEM_MVLU_VA_CTRL, 1,
sizeof (MVLU_RD_VA_CTRL));
mvluRdVaCtrl->rt = rt;
#if defined(MVL_XNAME)
strcpy (mvluRdVaCtrl->xName, element_name);
#endif
mvluRdVaCtrl->primData = (ST_CHAR *) rdVaCtrl->va->data +
prim_info->prim_offset;
mvluRdVaCtrl->indCtrl = indCtrl;
mvluRdVaCtrl->rdVaCtrl = rdVaCtrl;
#if defined(MVLU_USE_REF)
mvluRdVaCtrl->primRef = rt->mvluTypeInfo.ref;
#endif
mvluRdVaCtrl->prim_num = prim_info->prim_num;
mvluRdVaCtrl->prim_offset_base = prim_info->prim_offset_base;
if (u_mvlu_leaf_rd_ind_fun == NULL)
{}//(*mvluRdFunInfoTbl[rdIndFunIndex].fun_ptr)(mvluRdVaCtrl);//lnk<6E><6B><EFBFBD><EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD>ԭǰ<D4AD>ó<EFBFBD><C3B3><EFBFBD>δʹ<CEB4><CAB9>
else
(*u_mvlu_leaf_rd_ind_fun)(mvluRdVaCtrl);
}
else
rdVaCtrl->acc_rslt_tag = ACC_RSLT_FAILURE;
prim_info->prim_num++;
}
if (el_tag == RT_ARR_START)
{
startArrRds (indCtrl, rdCtrl, rdVaCtrl, rt, prim_info);
i += (num_rt_blks + 1);
rt += (num_rt_blks + 1);
}
else
{
prim_info->prim_offset += el_size;
prim_info->prim_offset_base += el_size;
}
}
}
/************************************************************************/
/* startArrRds */
/************************************************************************/
static ST_VOID startArrRds (MVL_IND_PEND *indCtrl, MVLAS_READ_CTRL *rdCtrl,
MVLAS_RD_VA_CTRL *rdVaCtrl, RUNTIME_TYPE *rt, PRIM_INFO *prim_info)
{
ST_RTINT i;
MVL_VAR_ASSOC *va;
ST_INT numRt;
/* DEBUG: To allow bigger arrays, must chg type of these two vars */
/* & va->arrCtrl.low_index & va->arrCtrl.curr_index. */
ST_RTINT low_index;
ST_RTINT num_elmnts;
numRt = rt->u.arr.num_rt_blks+2;
va = rdVaCtrl->va;
if (va->arrCtrl.arrAltAccPres == SD_TRUE)
{
low_index = va->arrCtrl.low_index;
num_elmnts = va->arrCtrl.num_elmnts;
}
else
{
low_index = 0;
num_elmnts = (ST_RTINT) rt->u.arr.num_elmnts;
}
/* Let's check to see if the client is selecting a sub-object ... */
prim_info->prim_offset += rt->el_size;
prim_info->prim_offset_base += rt->el_size;
for (i = 0; i < num_elmnts; ++i)
{
va->arrCtrl.curr_index = low_index + i;
startElReads (indCtrl, rdCtrl, rdVaCtrl, rt+1, numRt-2, prim_info);
}
prim_info->prim_offset += (rt+numRt-1)->el_size;
prim_info->prim_offset_base += (rt+numRt-1)->el_size;
}
/************************************************************************/
/* mvlu_rd_prim_done */
/************************************************************************/
/* The user calls this function acynchronously when the primitive data */
/* has been put in the 'primData' buffer. */
ST_VOID mvlu_rd_prim_done (MVLU_RD_VA_CTRL *mvluRdVaCtrl, ST_RET rc)
{
MVL_IND_PEND *indCtrl;
MVLAS_READ_CTRL *rdCtrl;
MVLAS_RD_VA_CTRL *rdVaCtrl;
ST_INT i;
rdVaCtrl = mvluRdVaCtrl->rdVaCtrl;
if (rc != SD_SUCCESS)
{
/* DEBUG LIZ: added logging why read failed */
MVL_LOG_NERR2 ("Read failed for UCA variable '%s' rc=%d",
rdVaCtrl->va->name, rc);
rdVaCtrl->acc_rslt_tag = ACC_RSLT_FAILURE;
}
++rdVaCtrl->numPrimDataDone;
if (rdVaCtrl->numPrimDataDone == rdVaCtrl->numPrimData)
{
/* All primitives for "one" variable are complete. */
indCtrl = mvluRdVaCtrl->indCtrl;
if (indCtrl->scan_va_done_fun)
(*indCtrl->scan_va_done_fun)(indCtrl, rdVaCtrl->va);
/* If all primitives for all variables are complete, respond now */
rdCtrl = &indCtrl->u.rd;
rdVaCtrl = rdCtrl->vaCtrlTbl;
for (i = 0; i < rdCtrl->numVar; ++i, ++rdVaCtrl)
{
if (rdVaCtrl->numPrimDataDone != rdVaCtrl->numPrimData)
break;
}
if (i == rdCtrl->numVar)
{
if (indCtrl->op != MMSOP_READ)
{ /* Not normal read. Do special processing. */
if (indCtrl->usr_resp_fun)
{ /* If user set custom resp fun, call it. */
(*indCtrl->usr_resp_fun) (indCtrl);
}
}
else
mvlas_read_resp (indCtrl);
}
}
M_FREE (MSMEM_MVLU_VA_CTRL, mvluRdVaCtrl);
}
/************************************************************************/
/* mvluDefAsyncRdIndFun */
/************************************************************************/
static ST_VOID mvluDefAsyncRdIndFun (struct mvlu_rd_va_ctrl *mvluRdVaCtrl)
{
mvlu_rd_prim_done (mvluRdVaCtrl, SD_SUCCESS);
}
/************************************************************************/
/************************************************************************/
/* u_mvl_write_ind */
/* NOTE: "indCtrl" is freed when "mvlas_write_resp" is called to send */
/* response. To assure "indCtrl" is valid until the end of this function,*/
/* the "ind_funct_done" flag is used to indicate if this function */
/* is done. It is accessible in all lower level functions. */
/* At end of this function, if response ready, "mvlas_write_resp" is */
/* called & indCtrl is freed (all done). If response NOT ready, this */
/* flag is set to (SD_TRUE), then "mvlu_wr_prim_done" will call */
/* "mvlas_write_resp" later when response is ready. */
/************************************************************************/
ST_VOID u_mvl_write_ind (MVL_IND_PEND *indCtrl)
{
MVLAS_WRITE_CTRL *wrCtrl;
MVLAS_WR_VA_CTRL *wrVaCtrl;
MVL_VAR_ASSOC *va;
MVLU_WR_VA_CTRL *mvluWrVaCtrl;
ST_INT i;
ST_INT numVar;
RUNTIME_TYPE *rt;
ST_INT numRt;
PRIM_INFO prim_info;
/* NOTE: (indCtrl->u.wr.ind_funct_done==SD_FALSE) because indCtrl calloced.*/
/* Changed to SD_TRUE only when this function completes. */
/* Checked in "mvlu_wr_prim_done" funct. */
wrCtrl = &indCtrl->u.wr;
numVar = wrCtrl->numVar;
/* First we will go through each variable being written and count the */
/* primitive elelemts. */
wrVaCtrl = wrCtrl->vaCtrlTbl;
for (i = 0; i < numVar; ++i, ++wrVaCtrl)
{
va = wrVaCtrl->va;
if (va) /* VA was resolved, we can look it over */
{
mvl_get_runtime (va->type_id, &rt, &numRt);
wrVaCtrl->resp_tag = WR_RSLT_SUCCESS;
wrVaCtrl->numPrimDataDone = 0;
if (va->base_va != NULL) /* UCA variable handling ... */
wrVaCtrl->numPrimData = countPrimEl (va, rt, numRt);
else
wrVaCtrl->numPrimData = 1;
}
else
wrVaCtrl->numPrimData = 1;
}
/* Now we will go through each var being written and invoke the wrInd */
/* function for it. */
wrVaCtrl = wrCtrl->vaCtrlTbl;
for (i = 0; i < numVar; ++i, ++wrVaCtrl)
{
va = wrVaCtrl->va;
if (va) /* VA was resolved, we can look it over */
{
/* The VA's data pointer is valid, as is the type ID. */
/* We want to call the handlers for all primitive level functions */
/* for this data type */
if (va->base_va != NULL) /* UCA variable handling ... */
{
mvl_get_runtime (va->type_id, &rt, &numRt);
if (chk_var_writable (rt, numRt))
{ /* This var NOT writable. Set error & skip to next var. */
set_write_resp_dae (wrVaCtrl, ARE_OBJ_ACCESS_DENIED);
continue; /* skip to next variable */
}
/* Initialize prim_info struct. */
if (init_prim_info (va, &prim_info))
{ /* Failed. Can't process this var. Skip to next var in list*/
MVL_LOG_ERR1 ("init_prim_info failed for 'Write' of variable '%s'", va->name);
set_write_resp_dae (wrVaCtrl, ARE_OBJ_ACCESS_DENIED);
continue; /* skip to next variable */
}
/* If this is struct (or array), user function pointer !=NULL, */
/* and function returns error, do not allow write. */
if (numRt > 1 /* must be struct or array */
&& u_mvl_wr_ind_var_start != NULL
&& (*u_mvl_wr_ind_var_start)(indCtrl, wrVaCtrl) != SD_SUCCESS)
{ /* This var NOT writable. Set error & skip to next var. */
set_write_resp_dae (wrVaCtrl, ARE_OBJ_ACCESS_DENIED);
continue; /* skip to next variable */
}
startElWrites (indCtrl, wrCtrl,wrVaCtrl, rt, numRt, &prim_info);
/* If this is struct (or array), user function pointer !=NULL, */
/* and function returns error, do not allow write. */
/* CAUTION: If error is detected here, must make sure that leaf */
/* functions did NOT write any data. */
if (numRt > 1 /* must be struct or array */
&& u_mvl_wr_ind_var_end != NULL
&& (*u_mvl_wr_ind_var_end)(indCtrl, wrVaCtrl) != SD_SUCCESS)
{ /* This var NOT writable. Set error & skip to next var. */
set_write_resp_dae (wrVaCtrl, ARE_OBJ_ACCESS_DENIED);
continue; /* skip to next variable */
}
}
else /* Non-UCA variable handling ... */
{
mvluWrVaCtrl = (MVLU_WR_VA_CTRL *) M_CALLOC (MSMEM_MVLU_VA_CTRL, 1,
sizeof (MVLU_WR_VA_CTRL));
mvluWrVaCtrl->primData = (ST_CHAR *) va->data;
mvluWrVaCtrl->indCtrl = indCtrl;
mvluWrVaCtrl->wrVaCtrl = wrVaCtrl;
(*mvluAsyncWrIndFun)(mvluWrVaCtrl);
}
}
else
{
mvluWrVaCtrl = (MVLU_WR_VA_CTRL *) M_CALLOC (MSMEM_MVLU_VA_CTRL, 1,
sizeof (MVLU_WR_VA_CTRL));
mvluWrVaCtrl->indCtrl = indCtrl;
mvluWrVaCtrl->wrVaCtrl = wrVaCtrl;
mvlu_wr_prim_done (mvluWrVaCtrl, SD_SUCCESS);
}
}
/* If response is ready (i.e. all synchronous leafs), send it now. */
/* If not, just set flag (SD_TRUE) & mvlu_wr_prim_done will send resp.*/
if (chk_write_resp_ready (indCtrl) == SD_SUCCESS)
mvlas_write_resp (indCtrl); /* sends resp & frees indCtrl */
else
indCtrl->u.wr.ind_funct_done = SD_TRUE; /* this funct is done */
}
/************************************************************************/
/* startElWrites */
/* NOTE: Resp NOT sent while in this function (see ind_funct_done flag).*/
/* Therefore, indCtrl is valid throughout this function */
/* (i.e. it is NOT freed). */
/************************************************************************/
static ST_VOID startElWrites (MVL_IND_PEND *indCtrl, MVLAS_WRITE_CTRL *wrCtrl,
MVLAS_WR_VA_CTRL *wrVaCtrl,
RUNTIME_TYPE *rt, ST_INT rt_num, PRIM_INFO *prim_info)
{
ST_INT i;
MVLU_WR_VA_CTRL *mvluWrVaCtrl;
ST_RTINT wrIndFunIndex;
ST_UCHAR el_tag;
ST_INT el_size;
ST_RTINT num_rt_blks;
#if defined(MVL_XNAME)
ST_CHAR element_name[MAX_IDENT_LEN+1];
ST_CHAR branch_name[MAX_IDENT_LEN+1];
MVL_VAR_ASSOC *va;
ST_CHAR *comp_name;
#endif
ST_CHAR sboName[MVL61850_MAX_OBJREF_LEN+1];
RUNTIME_TYPE *rt_first; /* to save ptr to first before incrementing */
#if !defined(MVL61850_CTL_DISABLE)
ST_INT oper_nest_level = 0;
#endif
#if defined(MVL_XNAME)
va = wrVaCtrl->va;
element_name[0]=0;
strcpy (branch_name,va->name);
/* if this is a substructure we need to trim back one level of the name */
/* because the first rt element will be the name of the component */
/* already part of the va->name */
if ((rt_num > 1) && (strstr (branch_name, "$")))
{
mvlu_trim_branch_name (branch_name);
}
#endif
rt_first = rt; /* save first for comparison */
for (i = 0; i < rt_num; ++i, ++rt)
{
#if defined(MVL_XNAME)
if (rt_num > 1) /* is this a collection of elements? */
{
comp_name = ms_comp_name_find (rt);
if (strlen (comp_name))
{
if ((rt->el_tag == RT_STR_START))
{
strcat (branch_name, "$");
strcat (branch_name, comp_name);
strcpy (element_name, branch_name);
}
else
{
element_name[0]=0;
strcat (element_name, branch_name);
strcat (element_name, "$");
strcat (element_name, comp_name);
}
}
if (rt->el_tag == RT_STR_END)
{
strcpy (element_name, branch_name);
mvlu_trim_branch_name (branch_name);
}
}
else
{ /* only one element in the RT table assume it's a primitive */
strcpy (element_name, branch_name);
}
#endif
el_tag = rt->el_tag;
num_rt_blks = rt->u.arr.num_rt_blks;
el_size = rt->el_size;
/* Do some special stuff for IEC 61850 SBO controls. */
/* If this comp is start of struct & comp name is "Oper" or "Cancel",*/
/* check SBO state. */
/* NOTE: must be writing "Oper" or "Cancel" struct and ONLY the struct.*/
if (rt == rt_first && /* this is first element */
rt->el_tag == RT_STR_START && /* it is a struct */
(strcmp (ms_comp_name_find(rt), "Oper") == 0 || strcmp (ms_comp_name_find(rt), "Cancel") == 0))
{
/* Check "Select" timeouts for ALL SBO controls. */
//mvlu_sbo_chk_timers ();//lnk<6E><6B><EFBFBD><EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD>
/* Chk SBO state. Save in wrVaCtrl->sboCtrl (NULL if "Select" not done).*/
//mvl61850_sbo_create_sboname (wrVaCtrl->va, &wrVaCtrl->va_scope, sboName);//lnk<6E><6B><EFBFBD><EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD>
//wrVaCtrl->sboCtrl = mvlu_sbo_chk_state (sboName, indCtrl->event->net_info);//lnk<6E><6B><EFBFBD><EFBFBD><EFBFBD>޸ģ<DEB8><C4A3><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD>
wrVaCtrl->sboCtrl = NULL;//lnk<6E><6B><EFBFBD><EFBFBD><EFBFBD>޸ģ<DEB8><C4A3><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD>
}
#if !defined(MVL61850_CTL_DISABLE)
if (rt->el_tag == RT_STR_START)
{
/* only increment this if this is "Oper" or already inside "Oper". */
if (oper_nest_level>0)
oper_nest_level++;
else if (strcmp (ms_comp_name_find(rt), "Oper") == 0)
{
if (wrVaCtrl->sboCtrl)
wrVaCtrl->sboCtrl->ctlState = MVL61850_CTLSTATE_READY;
//u_mvl61850_ctl_oper_begin (sboName);//lnk<6E><6B><EFBFBD><EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD>
oper_nest_level++;
}
}
if (rt->el_tag == RT_STR_END)
{
if (oper_nest_level>0)
{
if (--oper_nest_level==0)
{
/* All leaf functs have been called for "Oper" struct.*/
/*renxiaobao <20><><EFBFBD><EFBFBD>*/
/*u_mvl61850_ctl_oper_end (indCtrl->event->net_info, sboName, wrVaCtrl->va->base_va);*/
}
}
}
#endif /* !defined(MVL61850_CTL_DISABLE) */
if (ms_is_rt_prim (rt) == SD_TRUE)
{
wrIndFunIndex = rt->mvluTypeInfo.wrIndFunIndex;
if (u_mvlu_leaf_wr_ind_fun != NULL ||
//(wrIndFunIndex >= 0 && wrIndFunIndex < mvluNumWrFunEntries))//lnk<6E><6B><EFBFBD><EFBFBD><EFBFBD>޸ģ<DEB8>ԭǰ<D4AD>ó<EFBFBD><C3B3><EFBFBD>δʹ<CEB4><CAB9>
0)
{
mvluWrVaCtrl = (MVLU_WR_VA_CTRL *) M_CALLOC (MSMEM_MVLU_VA_CTRL, 1,
sizeof (MVLU_WR_VA_CTRL));
#if defined(MVL_XNAME)
strcpy (mvluWrVaCtrl->xName, element_name);
#endif
mvluWrVaCtrl->primData = (ST_CHAR *) wrVaCtrl->va->data +
prim_info->prim_offset;
mvluWrVaCtrl->indCtrl = indCtrl;
mvluWrVaCtrl->wrVaCtrl = wrVaCtrl;
mvluWrVaCtrl->rt = rt;
#if defined(MVLU_USE_REF)
mvluWrVaCtrl->primRef = rt->mvluTypeInfo.ref;
#endif
mvluWrVaCtrl->prim_num = prim_info->prim_num;
mvluWrVaCtrl->prim_offset_base = prim_info->prim_offset_base;
if (u_mvlu_leaf_wr_ind_fun == NULL)
{}//(*mvluWrFunInfoTbl[wrIndFunIndex].fun_ptr)(mvluWrVaCtrl);//lnk<6E><6B><EFBFBD><EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD>ԭǰ<D4AD>ó<EFBFBD><C3B3><EFBFBD>δʹ<CEB4><CAB9>
else
(*u_mvlu_leaf_wr_ind_fun)(mvluWrVaCtrl);
}
else
wrVaCtrl->resp_tag = WR_RSLT_FAILURE;
prim_info->prim_num++;
}
if (el_tag == RT_ARR_START)
{
startArrWrs (indCtrl, wrCtrl, wrVaCtrl, rt, prim_info);
i += (num_rt_blks + 1);
rt += (num_rt_blks + 1);
}
else
{
prim_info->prim_offset += el_size;
prim_info->prim_offset_base += el_size;
}
}
}
/************************************************************************/
/* startArrWrs */
/************************************************************************/
static ST_VOID startArrWrs (MVL_IND_PEND *indCtrl, MVLAS_WRITE_CTRL *wrCtrl,
MVLAS_WR_VA_CTRL *wrVaCtrl, RUNTIME_TYPE *rt, PRIM_INFO *prim_info)
{
ST_RTINT i;
MVL_VAR_ASSOC *va;
ST_INT numRt;
/* DEBUG: To allow bigger arrays, must chg type of these two vars */
/* & va->arrCtrl.low_index & va->arrCtrl.curr_index. */
ST_RTINT low_index;
ST_RTINT num_elmnts;
numRt = rt->u.arr.num_rt_blks+2;
va = wrVaCtrl->va;
if (va->arrCtrl.arrAltAccPres == SD_TRUE)
{
low_index = va->arrCtrl.low_index;
num_elmnts = va->arrCtrl.num_elmnts;
}
else
{
low_index = 0;
num_elmnts = (ST_RTINT) rt->u.arr.num_elmnts;
}
/* Let's check to see if the client is selecting a sub-object ... */
prim_info->prim_offset += rt->el_size;
prim_info->prim_offset_base += rt->el_size;
for (i = 0; i < num_elmnts; ++i)
{
va->arrCtrl.curr_index = low_index + i;
startElWrites (indCtrl, wrCtrl, wrVaCtrl, rt+1, numRt-2, prim_info);
}
prim_info->prim_offset += (rt+numRt-1)->el_size;
prim_info->prim_offset_base += (rt+numRt-1)->el_size;
}
/************************************************************************/
/* mvlu_wr_prim_done */
/************************************************************************/
/* The user calls this function acynchronously when the primitive data */
/* has been put in the 'primData' buffer. */
ST_VOID mvlu_wr_prim_done (MVLU_WR_VA_CTRL *mvluWrVaCtrl, ST_RET rc)
{
MVLAS_WR_VA_CTRL *wrVaCtrl;
wrVaCtrl = mvluWrVaCtrl->wrVaCtrl;
if (rc != SD_SUCCESS)
wrVaCtrl->resp_tag = WR_RSLT_FAILURE;
++wrVaCtrl->numPrimDataDone;
if (wrVaCtrl->numPrimDataDone == wrVaCtrl->numPrimData)
{ /* all prims done for this variable */
MVL_IND_PEND *indCtrl = mvluWrVaCtrl->indCtrl;
#if !defined(MVL61850_CTL_DISABLE)
//mvl61850_ctl_req_done (wrVaCtrl, indCtrl->event->net_info);//lnk<6E><6B><EFBFBD><EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD>ԭǰ<D4AD>ó<EFBFBD><C3B3><EFBFBD>δʹ<CEB4><CAB9>
#endif /* !defined(MVL61850_CTL_DISABLE) */
/* Response "usually" sent from u_mvl_write_ind. If it finished */
/* without sending resp AND resp is ready now, send it. */
if (indCtrl->u.wr.ind_funct_done /* ind funct completed */
&& chk_write_resp_ready(indCtrl)==SD_SUCCESS) /* resp ready */
mvlas_write_resp (indCtrl); /* send resp */
}
M_FREE (MSMEM_MVLU_VA_CTRL, mvluWrVaCtrl);
}
/************************************************************************/
/* mvluDefAsyncWrIndFun */
/************************************************************************/
static ST_VOID mvluDefAsyncWrIndFun (struct mvlu_wr_va_ctrl *mvluWrVaCtrl)
{
mvlu_wr_prim_done (mvluWrVaCtrl, SD_SUCCESS);
}
/************************************************************************/
/************************************************************************/
/* countPrimEl */
/************************************************************************/
static ST_INT countPrimEl (MVL_VAR_ASSOC *va, RUNTIME_TYPE *rt, ST_INT rt_num)
{
ST_INT i;
ST_INT num_elmnts;
ST_INT numPrimData;
ST_INT subElCount;
numPrimData = 0;
for (i = 0; i < rt_num; ++i, ++rt)
{
if (ms_is_rt_prim (rt) == SD_TRUE)
++numPrimData;
if (rt->el_tag == RT_ARR_START)
{
subElCount = countPrimEl (va, rt+1, rt->u.arr.num_rt_blks);
if (va->arrCtrl.arrAltAccPres == SD_FALSE)
num_elmnts = rt->u.arr.num_elmnts;
else
num_elmnts = va->arrCtrl.num_elmnts;
numPrimData += (subElCount * num_elmnts);
i += (rt->u.arr.num_rt_blks + 1);
rt += (rt->u.arr.num_rt_blks + 1);
}
}
return (numPrimData);
}
/************************************************************************/
/* mvluDefGetVaDataBufFun */
/* NOTE: only called when va->base_va->use_static_data==SD_FALSE. */
/************************************************************************/
static ST_VOID mvluDefGetVaDataBufFun (ST_INT service,
MVL_VAR_ASSOC *va, ST_INT size)
{
if (service == MMSOP_READ || service == MMSOP_WRITE ||
service == MMSOP_INFO_RPT || service == MMSOP_RD_USR_HANDLED)
{
va->data = M_MALLOC (MSMEM_MVLU_VA_DATA, size);
}
}
/************************************************************************/
/* mvluDefFreeVaDataBufFun */
/* NOTE: only called when va->base_va->use_static_data==SD_FALSE. */
/************************************************************************/
static ST_VOID mvluDefFreeVaDataBufFun (ST_INT service, MVL_VAR_ASSOC *va)
{
if (service == MMSOP_READ || service == MMSOP_WRITE ||
service == MMSOP_INFO_RPT || service == MMSOP_RD_USR_HANDLED)
{
M_FREE (MSMEM_MVLU_VA_DATA, va->data);
}
}
/************************************************************************/
/* mvlu_find_rt_leaf */
/************************************************************************/
RUNTIME_TYPE *mvlu_find_rt_leaf (ST_INT type_id, ST_CHAR *leafName)
{
RUNTIME_TYPE *rt;
ST_INT numRt;
ST_RET ret;
ret = mvl_get_runtime (type_id, &rt, &numRt);
if (ret != SD_SUCCESS)
{
MVL_LOG_NERR1 ("Could not get RT type for type id %d", type_id);
return (NULL);
}
ret = mvlu_find_uca_var (&rt, &numRt, leafName);
if (ret != SD_SUCCESS)
{
MVL_LOG_NERR1 ("Could not find leaf '%s'", leafName);
return (NULL);
}
if (numRt != 1)
{ /* See if this is an array with a single primitive element */
if (rt->el_tag == RT_ARR_START && numRt == 3)
return (rt+1);
MVL_LOG_NERR1 ("'%s' is a branch, not a leaf", leafName);
return (NULL);
}
return (rt);
}
/************************************************************************/
/* mvlu_find_comp_type */
/* Arguments: */
/* base_type_id type ID for top level variable */
/* flatname flattened component name with top level var */
/* name (Logical Node) stripped off. */
/* sub_rt_type Ptr to (RUNTIME_TYPE *) to be filled in. */
/* sub_rt_num Ptr to "count" to be filled in. */
/************************************************************************/
ST_RET mvlu_find_comp_type (ST_INT base_type_id, ST_CHAR *flatname,
RUNTIME_TYPE **sub_rt_type, /* out */
ST_INT *sub_rt_num) /* out */
{
MVL_TYPE_CTRL *base_type_ctrl;
ST_RET ret;
base_type_ctrl = mvl_type_ctrl_find (base_type_id);
if (base_type_ctrl)
{
*sub_rt_type = base_type_ctrl->rt;
*sub_rt_num = base_type_ctrl->num_rt;
ret = mvlu_find_uca_var (sub_rt_type, sub_rt_num, flatname);
}
else
ret = SD_FAILURE;
/* NOTE: don't log error here. Caller may often pass invalid names. */
return (ret);
}
/************************************************************************/
/* mvlu_get_leaf_val_int8 */
/* Get leaf data value for type ST_INT8. */
/* Arguments: */
/* base_va base variable (i.e. logical node) */
/* flatname flattened leaf name (e.g. ST$Mod$stVal) */
/* data ptr to data written by this function */
/* RETURNS: SD_SUCCESS or SD_FAILURE */
/************************************************************************/
ST_RET mvlu_get_leaf_val_int8 (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname, ST_INT8 *data)
{
RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */
ST_INT comp_rt_num; /* num of rt_types in component */
ST_RET ret = SD_FAILURE;
/* Find the attribute type. */
if (mvlu_find_comp_type (base_va->type_id,
flatname, /* flattened name */
&comp_rt_type, /* ptr to val set by function */
&comp_rt_num) /* ptr to val set by function */
== SD_SUCCESS)
{
if (comp_rt_type->el_tag == RT_INTEGER && comp_rt_type->u.p.el_len == 1)
{ /* must be INT8 */
*data = *(ST_INT8 *)((ST_CHAR *) base_va->data + comp_rt_type->mvluTypeInfo.offSet);
ret = SD_SUCCESS;
}
else
MVL_LOG_ERR1 ("Invalid type for '%s' attribute. Cannot use it.", flatname);
}
else
MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in this variable '%s'",
flatname, base_va->name);
return (ret);
}
/************************************************************************/
/* mvlu_get_leaf_val_int32 */
/* Get leaf data value for type ST_INT32. */
/* Arguments: */
/* base_va base variable (i.e. logical node) */
/* flatname flattened leaf name (e.g. ST$Mod$stVal) */
/* data ptr to data written by this function */
/* RETURNS: SD_SUCCESS or SD_FAILURE */
/************************************************************************/
ST_RET mvlu_get_leaf_val_int32 (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname, ST_INT32 *data)
{
RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */
ST_INT comp_rt_num; /* num of rt_types in component */
ST_RET ret = SD_FAILURE;
/* Find the attribute type. */
if (mvlu_find_comp_type (base_va->type_id,
flatname, /* flattened name */
&comp_rt_type, /* ptr to val set by function */
&comp_rt_num) /* ptr to val set by function */
== SD_SUCCESS)
{
if (comp_rt_type->el_tag == RT_INTEGER && comp_rt_type->u.p.el_len == 4)
{ /* must be INT32 */
*data = *(ST_INT32 *)((ST_CHAR *) base_va->data + comp_rt_type->mvluTypeInfo.offSet);
ret = SD_SUCCESS;
}
else
MVL_LOG_ERR1 ("Invalid type for '%s' attribute. Cannot use it.", flatname);
}
else
MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in this variable '%s'",
flatname, base_va->name);
return (ret);
}
/************************************************************************/
/* mvlu_get_leaf_val_int_any */
/* Get leaf value for any signed integer. Cast value to ST_INT32. */
/************************************************************************/
ST_RET mvlu_get_leaf_val_int_any (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname, ST_INT32 *data)
{
RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */
ST_INT comp_rt_num; /* num of rt_types in component */
ST_CHAR *raw_data; /* ptr to data. May be any integer size */
ST_INT8 tmp_int8; /* Used to get val as INT8, then cast to INT32 */
ST_INT16 tmp_int16; /* Used to get val as INT16, then cast to INT32 */
ST_RET retcode = SD_SUCCESS;
/* Find the attribute type. */
if (mvlu_find_comp_type (base_va->type_id,
flatname, /* flattened name */
&comp_rt_type, /* ptr to val set by function */
&comp_rt_num) /* ptr to val set by function */
== SD_SUCCESS)
{
raw_data = (ST_CHAR *) base_va->data + comp_rt_type->mvluTypeInfo.offSet;
if (comp_rt_type->el_tag == RT_INTEGER)
{
if (comp_rt_type->u.p.el_len == 1) /* INT8 */
{
tmp_int8 = *(ST_INT8 *) raw_data;
*data = (ST_INT32) tmp_int8;
}
else if (comp_rt_type->u.p.el_len == 2) /* INT16 */
{
tmp_int16 = *(ST_INT16 *) raw_data;
*data = (ST_INT32) tmp_int16;
}
else if (comp_rt_type->u.p.el_len == 4) /* INT32 */
{
*data = *(ST_INT32 *) raw_data;
}
else
{
MVL_LOG_ERR2 ("Unsupported integer size for '%s' attribute in variable '%s'",
flatname, base_va->name);
retcode = SD_FAILURE;
}
}
else
{
MVL_LOG_ERR2 ("Invalid type for '%s' attribute in variable '%s'. Cannot get value.",
flatname, base_va->name);
retcode = SD_FAILURE;
}
}
else
{
MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in variable '%s'",
flatname, base_va->name);
retcode = SD_FAILURE;
}
return (retcode);
}
/************************************************************************/
/* mvlu_get_leaf_val_uint32 */
/* Get leaf data value for type ST_UINT32. */
/* Arguments: */
/* base_va base variable (i.e. logical node) */
/* flatname flattened leaf name (e.g. ST$Mod$stVal) */
/* data ptr to data written by this function */
/* RETURNS: SD_SUCCESS or SD_FAILURE */
/************************************************************************/
ST_RET mvlu_get_leaf_val_uint32 (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname, ST_UINT32 *data)
{
RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */
ST_INT comp_rt_num; /* num of rt_types in component */
ST_RET ret = SD_FAILURE;
/* Find the attribute type. */
if (mvlu_find_comp_type (base_va->type_id,
flatname, /* flattened name */
&comp_rt_type, /* ptr to val set by function */
&comp_rt_num) /* ptr to val set by function */
== SD_SUCCESS)
{
if (comp_rt_type->el_tag == RT_UNSIGNED && comp_rt_type->u.p.el_len == 4)
{ /* must be UINT32 */
*data = *(ST_UINT32 *)((ST_CHAR *) base_va->data + comp_rt_type->mvluTypeInfo.offSet);
ret = SD_SUCCESS;
}
else
MVL_LOG_ERR1 ("Invalid type for '%s' attribute. Cannot use it.", flatname);
}
else
MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in this variable '%s'",
flatname, base_va->name);
return (ret);
}
/************************************************************************/
/* mvlu_get_leaf_val_boolean */
/* Get leaf data value for type ST_BOOLEAN. */
/* Arguments: */
/* base_va base variable (i.e. logical node) */
/* flatname flattened leaf name (e.g. ST$Mod$stVal) */
/* data ptr to data written by this function */
/* RETURNS: SD_SUCCESS or SD_FAILURE */
/************************************************************************/
ST_RET mvlu_get_leaf_val_boolean (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname, ST_BOOLEAN *data)
{
RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */
ST_INT comp_rt_num; /* num of rt_types in component */
ST_RET ret = SD_FAILURE;
/* Find the attribute type. */
if (mvlu_find_comp_type (base_va->type_id,
flatname, /* flattened name */
&comp_rt_type, /* ptr to val set by function */
&comp_rt_num) /* ptr to val set by function */
== SD_SUCCESS)
{
if (comp_rt_type->el_tag == RT_BOOL)
{ /* must be BOOLEAN */
*data = *(ST_BOOLEAN *)((ST_CHAR *) base_va->data + comp_rt_type->mvluTypeInfo.offSet);
ret = SD_SUCCESS;
}
else
MVL_LOG_ERR1 ("Invalid type for '%s' attribute. Cannot use it.", flatname);
}
else
MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in this variable '%s'",
flatname, base_va->name);
return (ret);
}
/************************************************************************/
/* mvlu_get_leaf_val_bvstring */
/* Get leaf data value for type MMS_BVSTRING. */
/* Arguments: */
/* base_va base variable (i.e. logical node) */
/* flatname flattened leaf name (e.g. ST$Mod$stVal) */
/* data ptr to data written by this function */
/* RETURNS: SD_SUCCESS or SD_FAILURE */
/************************************************************************/
ST_RET mvlu_get_leaf_val_bvstring (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname,
MMS_BVSTRING *data, ST_INT max_num_bits)
{
RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */
ST_INT comp_rt_num; /* num of rt_types in component */
ST_RET ret = SD_FAILURE;
ST_INT num_bytes;
/* Find the attribute type. */
if (mvlu_find_comp_type (base_va->type_id,
flatname, /* flattened name */
&comp_rt_type, /* ptr to val set by function */
&comp_rt_num) /* ptr to val set by function */
== SD_SUCCESS)
{
/* NOTE: for Bvstring, el_len is negative. */
if (comp_rt_type->el_tag == RT_BIT_STRING && comp_rt_type->u.p.el_len < 0
&& abs (comp_rt_type->u.p.el_len) <= max_num_bits)
{
num_bytes = 2 + (abs (comp_rt_type->u.p.el_len) + 7)/8;
memcpy (data, (ST_CHAR *)base_va->data + comp_rt_type->mvluTypeInfo.offSet, num_bytes);
ret = SD_SUCCESS;
}
else
MVL_LOG_ERR1 ("Invalid type for '%s' attribute. Cannot use it.", flatname);
}
else
MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in this variable '%s'",
flatname, base_va->name);
return (ret);
}
/************************************************************************/
/* mvlu_get_leaf_data_ptr */
/* Get leaf data pointer (for any type of leaf). */
/* Arguments: */
/* base_va base variable (i.e. logical node) */
/* flatname flattened leaf name (e.g. ST$Mod$stVal) */
/* rt_type ptr to ptr to type (function sets "*rt_type") */
/* RETURNS: pointer to leaf data (NULL on error) */
/************************************************************************/
ST_VOID *mvlu_get_leaf_data_ptr (MVL_VAR_ASSOC *base_va, ST_CHAR *flatname, RUNTIME_TYPE **rt_type)
{
RUNTIME_TYPE *comp_rt_type; /* first rt_type of component */
ST_INT comp_rt_num; /* num of rt_types in component */
ST_VOID *data;
/* Find the attribute type. */
if (mvlu_find_comp_type (base_va->type_id,
flatname, /* flattened name */
&comp_rt_type, /* ptr to val set by function */
&comp_rt_num) /* ptr to val set by function */
== SD_SUCCESS)
{
data = ((ST_CHAR *) base_va->data + comp_rt_type->mvluTypeInfo.offSet);
*rt_type = comp_rt_type;
}
else
{
data = NULL;
MVLU_LOG_FLOW2 ("Cannot find '%s' attribute in this variable '%s'",
flatname, base_va->name);
}
return (data);
}
/************************************************************************/
/* mvlu_find_component */
/* Find a lower level variable by processing "flattened" variable name */
/* AND/OR Alternate Access. */
/* NOTE: Similar to "mvlu_find_uca_var" but handles Alternate Access too.*/
/************************************************************************/
ST_RET mvlu_find_component (
ST_CHAR *flatname, /* flattened name (e.g. ST$Mod$stVal) */
ALT_ACCESS *alt_acc, /* NULL if Alt Access Spec not present */
RUNTIME_TYPE **rtIo,
ST_INT *numRtIo,
ST_INT *offset_io,
ST_RTINT *prim_num_io)
{
ST_RET ret;
ST_INT aa_idx; /* index to next alternate access element */
RUNTIME_TYPE *rt_type;
ST_CHAR nameBuf[MAX_IDENT_LEN+1];
ST_CHAR *nameToFind;
ST_CHAR *compEnd;
ST_BOOLEAN nameDone;
/* Deal with "flattened" naming first (i.e. fake Alternate Access). */
if (flatname != NULL)
{
strcpy (nameBuf, flatname); /* copy so we can modify it */
nameToFind = nameBuf;
nameDone = SD_FALSE;
while (nameDone == SD_FALSE)
{
/* Isolate the component name for this level, removing subcomp names */
compEnd = strstr (nameToFind, "$");
if (compEnd != NULL)
*compEnd = 0;
else /* This is the last nest level */
nameDone = SD_TRUE;
/* Find the component name in the current runtime type nest level */
/* NOTE: this modifies (*rtIo), (*numRtIo), (*offset_io), (*prim_num_io).*/
ret = mvlu_find_struct_comp (nameToFind, rtIo, numRtIo, offset_io, prim_num_io);
if (ret == SD_FAILURE)
{
/* Many things can cause this so just use FLOW Logging. */
MVLU_LOG_FLOW2 ("Could not find name component %s from name %s",
nameToFind, flatname);
return (SD_FAILURE);
}
/* OK, we now have found the component in the runtime type, and our */
/* runtime pointer and numRt reflect the sub-runtime type. */
/* next component. */
/* Prepare to find the next level component name */
nameToFind = compEnd+1;
} /* end while */
} /* end if (flatname != NULL)*/
/* Now deal with real alternate access. */
if (alt_acc != NULL)
{
for (aa_idx = 0; aa_idx < alt_acc->num_aa; aa_idx++)
{
ALT_ACC_EL *next_el;
ST_CHAR *comp_name; /* component name (used only if AA_COMP..)*/
ST_INT arr_index; /* array index (used only if AA_INDEX..)*/
next_el = &alt_acc->aa[aa_idx];
switch (next_el->sel_type)
{
case AA_COMP :
case AA_COMP_NEST :
comp_name = next_el->u.component;
/* Find the component name in the current runtime type nest level */
ret = mvlu_find_struct_comp (comp_name, rtIo, numRtIo, offset_io, prim_num_io);
if (ret == SD_FAILURE)
{
/* Many things can cause this so just use FLOW Logging. */
MVLU_LOG_FLOW1 ("Could not find name component %s", comp_name);
return (SD_FAILURE);
}
break;
case AA_INDEX_NEST :
case AA_INDEX :
case AA_INDEX_RANGE_NEST :
case AA_INDEX_RANGE :
rt_type = *rtIo;
if (rt_type->el_tag != RT_ARR_START)
{
MVL_LOG_ERR1 ("Specified array index on non-array component %s", comp_name);
return (SD_FAILURE);
}
/* If Array index range, just need low index for this computation.*/
if (next_el->sel_type== AA_INDEX_RANGE_NEST ||
next_el->sel_type== AA_INDEX_RANGE)
arr_index = next_el->u.ir.low_index;
else
arr_index = next_el->u.index;
*offset_io += rt_type->el_size; /* ARR_START size (usually 0)*/
/* Multiply array element size by array index. */
/* offset_to_last in next rt_type contains array element size.*/
*offset_io += (rt_type+1)->offset_to_last * arr_index;
*prim_num_io += (rt_type+1)->mvluTypeInfo.prim_count * arr_index;
*rtIo = rt_type + 1; /* point to array elem */
*numRtIo-=2;
break;
case AA_END_NEST :
break; /* just ignore these */
default:
MVL_LOG_ERR1 ("Alternate access type '%d' not supported", next_el->sel_type);
return (SD_FAILURE);
}
/* OK, we now have found the component in the runtime type, and our */
/* runtime pointer and numRt reflect the sub-runtime type. */
}
}
return (SD_SUCCESS);
}
/************************************************************************/
/* chk_var_writable */
/* Check if EVERY leaf in this variable is writable. If so, variable */
/* is writable. */
/* RETURNS: SD_SUCCESS if variable is writable */
/* SD_FAILURE if variable is NOT writable */
/************************************************************************/
static ST_RET chk_var_writable (RUNTIME_TYPE *rt, ST_INT rt_num)
{
ST_INT j;
/* DEBUG: This mode is almost never used. */
/* 1 leaf function for all leafs. Assume all leafs writable. */
if (u_mvlu_leaf_wr_ind_fun)
{
return (SD_SUCCESS); /* var is writable */
}
/* Find index to "u_no_write_allowed" function & save in static var. */
/* This calls "mvlu_find.." only once, the first time through here. */
/* NOTE: if not found, idx will be -1. If found, idx will be >= 0. */
if (idx_u_no_write_allowed == -2) /* not yet initialized */
{idx_u_no_write_allowed = -1;}//idx_u_no_write_allowed = mvlu_find_wr_ind_fun_index ("u_no_write_allowed");//lnk<6E><6B><EFBFBD><EFBFBD><EFBFBD>޸ģ<DEB8>ԭǰ<D4AD>ó<EFBFBD><C3B3><EFBFBD>δʹ<CEB4><CAB9>
if (idx_u_no_write_allowed < 0)
return (SD_SUCCESS); /* funct not found. Assume var is writable*/
/* Loop through type def to see if ANY leaf is unwritable. */
for (j = 0; j < rt_num; ++j, ++rt)
{
if (ms_is_rt_prim (rt)
&& rt->mvluTypeInfo.wrIndFunIndex == idx_u_no_write_allowed)
{
return (SD_FAILURE); /* var not writable */
}
}
return (SD_SUCCESS); /* var is writable */
}
/************************************************************************/
/* chk_write_resp_ready */
/* Check if everything ready to send Write response. */
/* RETURNS: SD_SUCCESS if ready */
/* SD_FAILURE if NOT ready */
/************************************************************************/
static ST_RET chk_write_resp_ready (MVL_IND_PEND *indCtrl)
{
MVLAS_WRITE_CTRL *wrCtrl;
MVLAS_WR_VA_CTRL *wrVaCtrl; /* current var in list of var */
ST_INT i;
ST_BOOLEAN retcode;
wrCtrl = &indCtrl->u.wr;
/* If all primitives for all variables are complete, ready to send resp.*/
wrVaCtrl = wrCtrl->vaCtrlTbl;
for (i = 0; i < wrCtrl->numVar; ++i, ++wrVaCtrl)
{
if (wrVaCtrl->numPrimDataDone != wrVaCtrl->numPrimData)
break; /* prims NOT done for this var */
}
if (i == wrCtrl->numVar)
retcode = SD_SUCCESS; /* ready to send response. */
else
retcode = SD_FAILURE; /* not ready */
return (retcode);
}
/************************************************************************/
/* set_write_resp_dae */
/* Set MMS Write Response DataAccessError for this variable. */
/************************************************************************/
static ST_VOID set_write_resp_dae (MVLAS_WR_VA_CTRL *wrVaCtrl,
ST_INT16 dae) /* MMS DataAccessError code */
{
wrVaCtrl->resp_tag = WR_RSLT_FAILURE;
wrVaCtrl->failure = dae;
wrVaCtrl->numPrimDataDone = wrVaCtrl->numPrimData; /* pretend like all prim done*/
}
/************************************************************************/
#endif /* defined(MVL_UCA) */
/************************************************************************/