Files
microser/mmslib/mvlu/mvl61850.c

1178 lines
43 KiB
C
Raw Normal View History

2026-06-15 15:48:16 +08:00
/************************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/* (c) Copyright Systems Integration Specialists Company, Inc., */
/* 2002-2006 All Rights Reserved */
/* */
/* MODULE NAME : mvl61850.c */
/* PRODUCT(S) : MMSEASE-LITE */
/* */
/* MODULE DESCRIPTION : */
/* Code to support IEC-61850 Reporting as a Server. */
/* */
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */
/* mvl61850_rcb_chk_state */
/* mvl61850_urcb_rpt_send */
/* */
/* MODIFICATION LOG : */
/* Date Who Rev Comments */
/* -------- --- ------ ------------------------------------------- */
/* 08/05/08 JRB 31 Increment ConfRev if DatSet is written. */
/* 07/22/08 JRB 30 Add mvl61850_objref_create. */
/* 06/30/08 JRB 29 For Ed2, return different EntryID/TimeOfEntry*/
/* values if RptEna=FALSE or TRUE. */
/* 05/15/08 JRB 28 Use NEW mvl61850_integrity_timeout. */
/* 05/06/08 JRB 27 Fix memory leak after "PDU size" error. */
/* 04/15/08 JRB 26 Don't call mvlu_rpt_va_change for GI */
/* (save "reason" later when scan completes). */
/* 02/29/08 JRB 25 Allow VMD_SPEC DatSet for URCB or BRCB. */
/* Allow AA_SPEC DatSet for URCB, but ONLY if */
/* RCB is reserved (Resv=TRUE). */
/* Set changed_flags for Integrity BEFORE loop. */
/* chk_seg_needed: allow longer (129) RptID, etc*/
/* 03/16/07 JRB 24 mvlu_gi_wr_ind: Chk that this client reserved URCB.*/
/* 03/07/07 JRB 23 Use mvlu_get_leaf_val_int_any for Beh$stVal. */
/* 02/28/07 JRB 22 mvlu_gi_wr_ind: allow write only if RCB is */
/* enabled; if TrgOps.GI=FALSE, allow write but */
/* DO NOT generate a report. */
/* 02/13/07 JRB 21 mvl61850_get_rcb: del unused net_info arg. */
/* Use new _rcb_writable. */
/* 12/20/06 JRB 20 PurgeBuf only if DatSet val changed (tissue 322)*/
/* Allow Beh$stVal to be INT8 (Enum) or INT32 */
/* (for Tissues 120, 146, 171, 234). */
/* 10/30/06 JRB 19 Use new mvl_vmd_* object handling functions. */
/* 08/09/06 JRB 18 Moved most 61850 Rpt code to mvl61850_rpt.c */
/* Chg mvl61850_rcb_build to mvl61850_urcb_rpt_send*/
/* & use only for URCB (new functs handle BRCB).*/
/* Use new mvlu_rpt_ready, mvl61850_mk_dataref, */
/* mvl61850_rcb_cleanup. */
/* Use new mvl61850_mk_rptid to generate RptID */
/* in RPT if RptID is NULL in RCB. */
/* Allow GI write only if TrgOp GI bit=1. */
/* Del mvl_enc_va_data, use new ms_local_to_asn1_2.*/
/* Add mvl61850_datset_wr_ind to allow DatSet write.*/
/* Store EntryID everywhere as Ostring8. */
/* Fix type for all ObjectReference (Vstring129).*/
/* Use mvl61850_get_rcb to find the RCB. */
/* 07/11/05 JRB 17 BUG FIX: Set cur_bufsize=0 after PurgeBuf write.*/
/* Set BufOvfl=SD_FALSE after PurgeBuf write */
/* (not clear in 61850, but passes KEMA test). */
/* 07/08/05 JRB 16 For URCB, ignore BUFOVFL, ENTRYID bits in */
/* OptFlds to conform to 61850-8-1. */
/* 06/27/05 JRB 15 mvlu_entryid_rd_ind: return lastSentEntryID. */
/* Old code returned "last queued" EntryID. */
/* 06/27/05 JRB 14 _mvlu_get_rd_rcb: add (MVLU_RPT_CLIENT **) arg*/
/* 05/16/05 JRB 13 Set failure=ARE_TEMP_UNAVAIL when trying to */
/* write RCB elements while RptEna=TRUE. */
/* Del mvlu_sqnum_int16u_wr.. (not writable). */
/* 05/04/05 JRB 12 Call u_mvlu_rpt_time_get just once BEFORE */
/* main loop in ..rcb_build so that each */
/* segmented report has the same time stamp. */
/* 01/19/05 JRB 11 Add mvl61850_beh_stval_rd_ind. */
/* 08/20/04 JRB 10 Increment EntryID before encoding rpt, */
/* so EntryID encoded in rpt matches EntryID */
/* stored in BUFLIST_ENTRY struct. */
/* 08/06/04 EJV 09 mvlu_entryid_wr_ind: add typecast. */
/* 06/30/04 JRB 08 Add mvlu_sqnum_int16u_rd(wr)_ind_fun & use */
/* SqNumInt16u instead of SqNum for BRCB. */
/* Chg RptID type to vstring65. */
/* Del SCL parsing functions: */
/* mvl61850_ln_create_start, mvl61850_do_create,*/
/* mvl61850_da_create, mvl61850_ln_create_finish,*/
/* & mvl61850_ln_destroy. New SCL standard */
/* makes these obsolete. */
/* 03/18/04 JRB 07 Fix dataref in reports by adding scope. */
/* 12/17/03 JRB 06 61850-8-1 FDIS changes: */
/* Add ConfRev to rpt if enabled by OptFlds. */
/* Move SubSeqNum, MoreSegmentsFollow to just */
/* before inclusion bitstring. */
/* Save TimeofEntry in "basrcb". */
/* Add mvlu_timeofentry_rd_ind. */
/* 07/09/03 JRB 05 Del assert in mvlu_gi_scan_done so GI works */
/* for URCB too. */
/* 04/14/03 JRB 04 Eliminate compiler warnings. */
/* 04/04/03 JRB 03 Fix integrity/GI scan code so multiple */
/* concurrent scans don't corrupt one another. */
/* 03/13/03 JRB 02 Add URCB support: rename/rearrange some things*/
/* Add code for 61850 dynamic type creation. */
/* Trigger Intg Rpt ONLY by setting IntgPd!=0. */
/* Trigger GI ONLY by writing GI!=0. */
/* Move bstrcpy, bvstrcpy to "asn1r.c". */
/* Fix report segmenting (see chk_seg_needed). */
/* 12/15/02 JRB 01 Created */
/************************************************************************/
#include "glbtypes.h"
#include "sysincs.h"
#include "mvl_uca.h"
#include "mvl_log.h"
#include "mvl_acse.h" /* need mvl_cfg_info */
/************************************************************************/
/* 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
static ST_RET fill_asn1_len_array (MVLU_RPT_CLIENT *rptClient,
MVL_NVLIST_CTRL *dsNvl,
ST_INT *asn1_len_array);
/******
* mvl61850_rcb_chk_state
* Check RCB state and build/send report if necessary. This function works for
* BRCB or URCB.
*/
ST_VOID mvl61850_rcb_chk_state (MVLU_RPT_CTRL *rptCtrl,
MVLU_RPT_CLIENT *rptClient,
ST_DOUBLE timeNow)
{
/* If URCB enabled or BRCB enabled ONCE, chk Integrity period & triggers.*/
if (rptClient->basrcb.RptEna
|| (rptClient->rpt_ctrl->rcb_type == RCB_TYPE_IEC_BRCB
&& rptClient->rpt_ctrl->brcbCtrl.enabled_once))
{
/* Chk for Integrity Period timeout. */
/* NOTE: use mvl61850_integrity_timeout (mvlu_integrity_timeout is */
/* only for UCA). */
mvl61850_integrity_timeout (rptClient, timeNow);
/* Chk for other triggers. */
/* NOTE: numTrgs ONLY incremented if changes matched the TrgOps. */
if (rptClient->numTrgs > 0)
{
/* If BufTim disabled (=0) OR BufTim expired, send report now. */
if (rptClient->basrcb.BufTim == 0 || timeNow > rptClient->buf_time_done)
{
MVLU_LOG_FLOW1 ("Non-Integrity report for client %08lx", rptClient);
mvlu_rpt_ready (rptClient, MVLU_RPT_TYPE_RBE); /* send or queue rpt*/
}
}
} /* end if rpt enabled at least once */
return;
}
/************************************************************************/
/* mvlu_gi_scan_va_done */
/* This function is called by 'mvlu_rd_prim_done' when all "leaf" */
/* functions for a VA have been completed (i.e. data ready for this VA).*/
/************************************************************************/
ST_VOID mvlu_gi_scan_va_done (MVL_IND_PEND *indCtrl,
MVL_VAR_ASSOC *va)
{
ST_INT data_size;
/* CRITICAL: DO NOT call mvlu_rpt_va_change. rptClient->reasons_data */
/* will be set in mvlu_gi_scan_done when scan completes. */
data_size = mvl_type_ctrl[va->type_id].data_size;
memcpy (va->last_data, va->data, data_size);
}
/************************************************************************/
/* mvlu_gi_scan_done */
/* Same as "_mvlu_rpt_scan_done" except arg is (MVL_IND_PEND *) */
/* instead of (MVLU_RPT_SCAN_CTRL *). */
/* */
/* This function is called when the gi scan is complete. */
/* (i.e. 'mvlu_rd_prim_done' has been called for all "leafs" of all */
/* variables in the report). Everything is ready to build a report, */
/* so build it now. */
/************************************************************************/
ST_RET mvlu_gi_scan_done (MVL_IND_PEND *indCtrl)
{
ST_RET retCode;
MVLU_RPT_CLIENT *rptClient;
ST_INT j;
/* Get "rptClient", saved in "indCtrl" when scan initialized. */
rptClient = (MVLU_RPT_CLIENT *) indCtrl->usr_ind_ctrl;
/* Set "reason" for each variable of Dataset now. */
for (j = 0; j < rptClient->rpt_ctrl->dsNvl->num_of_entries; j++)
rptClient->reasons_data[j] = MVLU_TRGOPS_GI;
/* Assume this is a BRCB or URCB. Should never get here otherwise. */
/* Build the report. */
retCode = mvlu_rpt_ready (rptClient, MVLU_RPT_TYPE_INTEGRITY_OR_GI);
if (retCode != SD_SUCCESS)
MVLU_LOG_FLOW1 ("GI report send failed: err=0x%X", retCode);
mvlu_integrity_scan_destroy (indCtrl); /* destroy temporary struct*/
return (retCode);
}
/************************************************************************/
/* mvl61850_urcb_rpt_send */
/* Set up all info needed to build an Information Report for a URCB, */
/* then call "mvl_info_variables" to encode/send it. */
/************************************************************************/
ST_RET mvl61850_urcb_rpt_send (MVLU_RPT_CTRL *rptCtrl,
MVLU_RPT_CLIENT *rptClient,
ST_INT rpt_type)
{
MVL_NVLIST_CTRL *dsNvl;
MVL_NVLIST_CTRL *rptNvl;
MVL_VAR_ASSOC *va;
ST_INT j; /* loop counter */
ST_RET retCode;
ST_INT sendIndex;
ST_INT sendIndexSave; /* save index before data, compare after data */
ST_UINT8 *optFlds;
MVLU_BASRCB *basrcb;
ST_INT incSize; /* num bytes for inclusion bitstring */
MVL_VAR_ASSOC *tmp_va_arr; /* alloc array of structs */
ST_INT tmp_va_arr_size; /* num of entries in tmp_va_arr */
MVL_VAR_ASSOC *tmp_va; /* current entry in tmp_va_arr */
/* For Segmented reports, all segments are generated by this function,
* so these parameters can be local variables.
*/
ST_INT cur_va_index, next_va_index; /* indices into dsNvl va array */
ST_BOOLEAN segNeeded; /* If TRUE, segmenting needed */
ST_UINT16 SubSeqNum = 0;
ST_BOOLEAN MoreSegmentsFollow;
ST_CHAR *tmp_dataref_buf;
ST_CHAR tmpRptID [MVL61850_MAX_RPTID_LEN+1];
ST_INT *asn1_len_array; /* array of ASN.1 lengths, one for each var (allocated)*/
basrcb = &rptClient->basrcb;
optFlds = basrcb->OptFlds.data_1;
dsNvl = rptCtrl->dsNvl;
rptNvl = &rptCtrl->rptNvl;
incSize = BSTR_NUMBITS_TO_NUMBYTES(dsNvl->num_of_entries);
MVLU_LOG_FLOW1 ("Building IEC-61850 URCB Report, MVL_NET_INFO %08lx", rptClient->netInfo);
/* Need tmp va's for options, array of data_refs, array of reasons_data.*/
tmp_va_arr_size = MVLU_MAX_RPT_OPTS + (dsNvl->num_of_entries * 2);
tmp_va_arr = M_CALLOC (MSMEM_GEN, sizeof (MVL_VAR_ASSOC), tmp_va_arr_size);
/* Need tmp buffer for datarefs. One buffer for all. */
/* Allow max len plus NULL for each dataref. */
tmp_dataref_buf = M_CALLOC (MSMEM_GEN, (MVL61850_MAX_OBJREF_LEN+1), dsNvl->num_of_entries);
asn1_len_array = M_CALLOC (MSMEM_GEN, rptCtrl->dsNvl->num_of_entries, sizeof(ST_INT));
assert (rptCtrl->dsNvl->num_of_entries); /* must be >0 entries */
/* Call user function to get report time. Called here before loop */
/* so that all segmented reports get the same time stamp. */
u_mvlu_rpt_time_get (&basrcb->TimeofEntry);
/* Fill in "asn1_len_array", needed later by "chk_seg_needed". */
if (fill_asn1_len_array (rptClient, rptCtrl->dsNvl, asn1_len_array)!=SD_SUCCESS)
{
/* NOTE: This should NEVER fail, but if it does, just log it. */
/* Real encode will almost certainly fail later. */
MVL_LOG_ERR0 ("Cannot calculate ASN.1 length for Unbuffered Report.");
}
/* If this is Integrity (or GI) report, just set all inclusion bits.*/
if (rpt_type == MVLU_RPT_TYPE_INTEGRITY_OR_GI)
memset (rptClient->changed_flags, 0xff, incSize);
for (cur_va_index = 0, next_va_index = 0;
next_va_index < rptCtrl->dsNvl->num_of_entries;
cur_va_index = next_va_index, SubSeqNum++)
{ /* BEGIN MAIN LOOP */
tmp_va = tmp_va_arr; /* start loop pointing to first entry */
sendIndex = 0; /* start with first rptNvl->entries. */
/* Prepares a UCA Report NVL to be sent, based on the */
/* options, data, and inclusion bitstring in the rptCtrl. After this*/
/* function completes, the rptCtrl->rptNvl is ready to be sent. */
/* CRITICAL: asn1_len_array must be filled in before call to chk_seg_needed.*/
segNeeded = chk_seg_needed (rptClient, asn1_len_array, cur_va_index, &next_va_index);
/*
printf("urcb:segNeeded=%d num=%d va_index = %d->%d\r\n",
segNeeded,rptCtrl->dsNvl->num_of_entries,cur_va_index, next_va_index);
*/
if (next_va_index - cur_va_index == 0)
{
MVL_LOG_ERR0 ("MMS PDU size too small to fit ANY variables in IEC-61850 Report. Report not sent.");
retCode = SD_FAILURE;
break; /* break out of loop so normal cleanup occurs. */
}
/* We will create a NVL to send, using the dsNvl as a model ... */
/* RptID and OptFlds are always the first 2 entries in the Rpt NVL. */
/* Add RptID to Report. */
tmp_va->type_id = rptCtrl->rpt_typeids.vstring65;
if (basrcb->RptID [0] == '\0')
{ /* RptID not set in RCB, so construct it. */
mvl61850_mk_rptid (rptCtrl, tmpRptID, MVL61850_MAX_RPTID_LEN);
tmp_va->data = tmpRptID;
}
else
tmp_va->data = basrcb->RptID;
MVLU_LOG_CFLOW1 (" RptID='%s", tmp_va->data); /* log before tmp_va++*/
rptNvl->entries[sendIndex++] = tmp_va++; /* set entry & point to next*/
/* Add OptFlds to Report. */
tmp_va->type_id = rptCtrl->rpt_typeids.bvstring10;
tmp_va->data = &basrcb->OptFlds;
rptNvl->entries[sendIndex++] = tmp_va++; /* set entry & point to next*/
MVLU_LOG_CFLOW2 (" OptFld = 0x%02x 0x%02x", basrcb->OptFlds.data_1[0],
basrcb->OptFlds.data_1[1]); /* 10 bit bstr (2 bytes) */
/* Add optional RCB vars to NVL, depending on OptFlds. */
/* The following optional vars are controlled by the same OptFlds bits,
* are of the same type, and are in the same order as in UCA, so that
* UCA clients can decode reports if only these options are used.
*/
if (BSTR_BIT_GET(optFlds, OPTFLD_BITNUM_SQNUM))
{
/* NOTE: 61850-7-2 says SqNum in Report is INT16U, but we encode
* INT8U from URCB. ASN.1 encodes same either way, so client
* may decode as INT16U if needed.
*/
tmp_va->type_id = rptCtrl->rpt_typeids.int8u;
tmp_va->data = &basrcb->SqNum;
rptNvl->entries[sendIndex++] = tmp_va++; /* set entry & point to next*/
MVLU_LOG_CFLOW1 (" SqNum : %u", (unsigned) basrcb->SqNum);
}
if (BSTR_BIT_GET(optFlds, OPTFLD_BITNUM_TIMESTAMP))
{
MVLU_LOG_CFLOW2 (" RptTim : %lums, %lu days",
basrcb->TimeofEntry.ms, basrcb->TimeofEntry.day);
tmp_va->type_id = rptCtrl->rpt_typeids.btime6;
tmp_va->data = &basrcb->TimeofEntry;
rptNvl->entries[sendIndex++] = tmp_va++; /* set entry & point to next*/
}
if (BSTR_BIT_GET(optFlds, OPTFLD_BITNUM_DATSETNAME))
{
/* UCA called it OutDat instead of DataSetName. Value is same. */
MVLU_LOG_CFLOW1 (" DataSetName : %s", basrcb->DatSetNa);
tmp_va->type_id = rptCtrl->rpt_typeids.vstring129; /*ObjectReference*/
tmp_va->data = basrcb->DatSetNa;
rptNvl->entries[sendIndex++] = tmp_va++; /* set entry & point to next*/
}
/* The following optional vars are NOT supported by UCA. The OptFlds bits
* must never be set by UCA clients, and the corresponding data
* must NOT be sent to UCA clients.
*/
/* For URCB, ignore BUFOVFL bit in OptFlds. */
/* For URCB, ignore ENTRYID bit in OptFlds. */
/* Add "ConfRev" if enabled by "OptFlds". */
if (BSTR_BIT_GET(optFlds, OPTFLD_BITNUM_CONFREV))
{
tmp_va->type_id = rptCtrl->rpt_typeids.int32u;
tmp_va->data = &basrcb->ConfRev;
rptNvl->entries[sendIndex++] = tmp_va++; /* set entry & point to next*/
}
if (segNeeded)
{
/* Set appropriate bit in OptFlds. */
/* NOTE: this bit only for output. Never used as input. */
BSTR_BIT_SET_ON (optFlds,OPTFLD_BITNUM_SUBSEQNUM);
tmp_va->type_id = rptCtrl->rpt_typeids.int16u;
tmp_va->data = &SubSeqNum;
rptNvl->entries[sendIndex++] = tmp_va++; /* set entry & point to next*/
if (next_va_index < rptCtrl->dsNvl->num_of_entries)
MoreSegmentsFollow = SD_TRUE;
else
MoreSegmentsFollow = SD_FALSE;
tmp_va->type_id = rptCtrl->rpt_typeids.mmsbool;
tmp_va->data = &MoreSegmentsFollow;
rptNvl->entries[sendIndex++] = tmp_va++; /* set entry & point to next*/
}
else
{
BSTR_BIT_SET_OFF (optFlds,OPTFLD_BITNUM_SUBSEQNUM);
}
/* Add inclusion bitstring. */
tmp_va->type_id = rptCtrl->inclusion_typeid;
if (segNeeded)
{
/* just set the bits included in this segment. */
memset (rptClient->segmented_inclusion, 0, incSize); /* start clean */
for (j = cur_va_index; j < next_va_index; ++j)
{
if (BSTR_BIT_GET (rptClient->changed_flags, j))
BSTR_BIT_SET_ON (rptClient->segmented_inclusion, j);
}
tmp_va->data = rptClient->segmented_inclusion;
}
else
tmp_va->data = rptClient->changed_flags;
rptNvl->entries[sendIndex++] = tmp_va++; /* set entry & point to next*/
/* If data-Ref enabled, go through inclusion_data to decide what to send*/
if (BSTR_BIT_GET(optFlds, OPTFLD_BITNUM_DATAREF))
{
for (j = cur_va_index; j < next_va_index; ++j)
{
if (BSTR_BIT_GET (rptClient->changed_flags, j))
{
tmp_va->type_id = rptCtrl->rpt_typeids.vstring129; /*ObjectReference*/
/* point to right part of tmp buffer & construct dataref */
tmp_va->data = &tmp_dataref_buf [j * (MVL61850_MAX_OBJREF_LEN+1)];
mvl61850_mk_dataref (dsNvl->entries[j], &dsNvl->va_scope[j],
tmp_va->data, MVL61850_MAX_OBJREF_LEN);
rptNvl->entries[sendIndex++] = tmp_va++; /* set entry & point to next*/
}
}
}
/* HERE'S DATA: Go through inclusion_data to decide what to send */
sendIndexSave = sendIndex; /* save index before data included */
for (j = cur_va_index; j < next_va_index; ++j)
{
if (BSTR_BIT_GET (rptClient->changed_flags, j))
{
va = dsNvl->entries[j];
MVLU_LOG_CFLOW3 (" Including variable %d ('%s'), reason=0x%02X",
j, va->name, rptClient->reasons_data[j]);
rptNvl->entries[sendIndex++] = va;
/* va->data already points to latest data. No need to copy data.*/
}
}
assert (sendIndex>sendIndexSave); /* make sure SOME data included */
/* If "reason" enabled, go through inclusion_data to decide what to send*/
if (BSTR_BIT_GET(optFlds, OPTFLD_BITNUM_REASON))
{
for (j = cur_va_index; j < next_va_index; ++j)
{
if (BSTR_BIT_GET (rptClient->changed_flags, j))
{
/* Don't need BVSTR here, because size is fixed. */
tmp_va->type_id = rptCtrl->rpt_typeids.bstr6;
tmp_va->data = &rptClient->reasons_data[j];
rptNvl->entries[sendIndex++] = tmp_va++; /* set entry & point to next*/
}
}
}
rptNvl->num_of_entries = sendIndex;
assert (rptNvl->num_of_entries <= rptCtrl->maxNumRptVars); /* past end of array?*/
assert ((tmp_va-tmp_va_arr) <= tmp_va_arr_size); /* past end of array?*/
/* Encode the InformationReport and send it. */
retCode = mvl_info_variables (rptClient->netInfo, /* URCB: encode & send*/
&rptClient->rpt_ctrl->rptNvl,
SD_FALSE); /* FALSE means "send as NVL" */
/* If send fails, just log it. Try to send other segments anyway.*/
if (retCode)
MVL_LOG_ERR1 ("Sending IEC-61850 Unbuffered Report failed: err=0x%X", retCode);
} /* END MAIN LOOP */
/* Increment seq number for next rpt. */
basrcb->SqNum++; /* used only for URCB */
/* Reset reasons, etc. to prepare for new report triggers. */
mvl61850_rcb_cleanup (rptClient); /* prepare for next RPT. */
if (retCode != SD_SUCCESS)
MVLU_LOG_FLOW1 ("Report Build failed: err=0x%X", retCode);
M_FREE (MSMEM_GEN, tmp_va_arr);
M_FREE (MSMEM_GEN, tmp_dataref_buf);
M_FREE (MSMEM_GEN, asn1_len_array);
return (retCode);
}
/******
* chk_seg_needed
* Check if segmenting is needed.
* Set (*next_va_index) = first va to send in "next" report.
* RETURN: SD_FALSE if segmenting NOT needed.
* SD_TRUE if segmenting IS needed.
*/
ST_BOOLEAN chk_seg_needed (MVLU_RPT_CLIENT *rptClient,
ST_INT *asn1_len_array,
ST_INT cur_va_index, /* input arg */
ST_INT *next_va_index) /* output arg */
{
ST_INT negotiatedPduSize;
ST_INT unusedSize;
ST_INT num_entries;
ST_INT loopIndex;
ST_BOOLEAN segNeeded;
negotiatedPduSize = rptClient->netInfo->max_pdu_size;
/*negotiatedPduSize = 2*1024;*/
num_entries = rptClient->rpt_ctrl->dsNvl->num_of_entries;
/* Subtract overhead from max "negotiated" PDU size. */
/* Very verbose, but most data are constants so compiler should simplify.*/
unusedSize = negotiatedPduSize
- 32 /* InfoRpt overhead (ROUGH estimate) */
- 131 /* RptID (Vstring129) */
- 5 /* OptFlds (Bstring10) */
- 4 /* SqNum (Int16) */
- 131 /* DataSetNam (Vstring129) */
- 3 /* BufOvfl (Boolean) */
- 8 /* TimeOfEntry (Btime6) */
- 4 /* SubSeqNum (Int16) */
- 3 /* MoreSegFoll (Boolean) */
-10 /* EntryID (Ostring8) */
-(3+num_entries/8) /* Inclusion Bitstring */
;
/* In a loop, check if each var fits in the Report. */
for (loopIndex = cur_va_index; loopIndex < num_entries; ++loopIndex)
{
/* Subtract space needed for this var. */
/* If len==0, this var must not be included in the report, so skip it.*/
if (asn1_len_array[loopIndex])
{ /* this var should be included in rpt. Check for space. */
unusedSize -= 131; /* DataRef (Vstring129) */
unusedSize -= 4; /* ReasonForInclusion (Bstring4?) */
unusedSize -= asn1_len_array[loopIndex]; /* Data */
}
if (unusedSize < 0)
break; /* cannot fit this va. Break out of loop. */
}
/* When loop ends, "loopIndex" is index to first variable of "next" report.*/
*next_va_index = loopIndex;
if (cur_va_index == 0 && (*next_va_index) == num_entries)
segNeeded = SD_FALSE; /* All fit in one PDU (no segmenting) */
else
segNeeded = SD_TRUE;
return (segNeeded);
}
/************************************************************************/
/* mvlu_confrev_rd_ind */
/* NOTE: confrev write funct should be something like u_no_write_allowed*/
/************************************************************************/
ST_VOID mvlu_confrev_rd_ind (MVLU_RD_VA_CTRL *mvluRdVaCtrl)
{
ST_UINT32 *dest;
MVLU_BASRCB *rcb;
ST_RET rc;
rc = SD_FAILURE;
/* Only for 61850, so use mvl61850_get_rcb to find the RCB. */
rcb = mvl61850_get_rcb (mvluRdVaCtrl->rdVaCtrl->va->base_va,
mvluRdVaCtrl->rt,
NULL);
if (rcb != NULL)
{
dest = (ST_UINT32 *) mvluRdVaCtrl->primData;
*dest = rcb->ConfRev;
rc = SD_SUCCESS;
}
mvlu_rd_prim_done (mvluRdVaCtrl, rc);
}
/************************************************************************/
/* mvlu_purgebuf_rd_ind */
/************************************************************************/
ST_VOID mvlu_purgebuf_rd_ind (MVLU_RD_VA_CTRL *mvluRdVaCtrl)
{
ST_BOOLEAN *dest;
MVLU_BASRCB *rcb;
ST_RET rc;
rc = SD_FAILURE;
/* Only for 61850, so use mvl61850_get_rcb to find the RCB. */
rcb = mvl61850_get_rcb (mvluRdVaCtrl->rdVaCtrl->va->base_va,
mvluRdVaCtrl->rt,
NULL);
if (rcb != NULL)
{
dest = (ST_BOOLEAN *) mvluRdVaCtrl->primData;
*dest = 0; /* no data stored. ALWAYS return 0 */
rc = SD_SUCCESS;
}
mvlu_rd_prim_done (mvluRdVaCtrl, rc);
}
/************************************************************************/
/* mvlu_gi_rd_ind */
/************************************************************************/
ST_VOID mvlu_gi_rd_ind (MVLU_RD_VA_CTRL *mvluRdVaCtrl)
{
ST_BOOLEAN *dest;
MVLU_BASRCB *rcb;
ST_RET rc;
rc = SD_FAILURE;
/* Only for 61850, so use mvl61850_get_rcb to find the RCB. */
rcb = mvl61850_get_rcb (mvluRdVaCtrl->rdVaCtrl->va->base_va,
mvluRdVaCtrl->rt,
NULL);
if (rcb != NULL)
{
dest = (ST_BOOLEAN *) mvluRdVaCtrl->primData;
*dest = 0; /* no data stored. ALWAYS return 0 */
rc = SD_SUCCESS;
}
mvlu_rd_prim_done (mvluRdVaCtrl, rc);
}
/************************************************************************/
/* mvlu_entryid_rd_ind */
/************************************************************************/
ST_VOID mvlu_entryid_rd_ind (MVLU_RD_VA_CTRL *mvluRdVaCtrl)
{
MVLU_BASRCB *rcb;
ST_RET rc;
MVLU_RPT_CLIENT *rptClient; /* can access all rpt info from this struct.*/
BUFLIST_ENTRY *entry;
rc = SD_FAILURE;
/* Only for 61850, so use mvl61850_get_rcb to find the RCB. */
rcb = mvl61850_get_rcb (mvluRdVaCtrl->rdVaCtrl->va->base_va,
mvluRdVaCtrl->rt,
&rptClient);
if (rcb != NULL)
{
#if 1 /* NOTE: Ed2 says to return different value if RptEna=FALSE or TRUE.*/
if (rptClient->basrcb.RptEna==0)
{
entry = (BUFLIST_ENTRY *) list_find_last ((DBL_LNK *) rptClient->rpt_ctrl->brcbCtrl.rpt_list);
if (entry == NULL) /* empty list, return all 0 */
memset (mvluRdVaCtrl->primData, 0, 8);
else
memcpy (mvluRdVaCtrl->primData, entry->EntryID, 8);
}
else
memcpy (mvluRdVaCtrl->primData, rptClient->rpt_ctrl->brcbCtrl.lastSentEntryID, 8);
#else /* old way (before Ed2) */
memcpy (mvluRdVaCtrl->primData, rptClient->rpt_ctrl->brcbCtrl.lastSentEntryID, 8);
#endif
rc = SD_SUCCESS;
}
mvlu_rd_prim_done (mvluRdVaCtrl, rc);
}
/************************************************************************/
/* mvlu_timeofentry_rd_ind */
/************************************************************************/
ST_VOID mvlu_timeofentry_rd_ind (MVLU_RD_VA_CTRL *mvluRdVaCtrl)
{
MVLU_BASRCB *rcb;
ST_RET rc;
MVLU_RPT_CLIENT *rptClient; /* can access all rpt info from this struct.*/
BUFLIST_ENTRY *entry;
rc = SD_FAILURE;
/* Only for 61850, so use mvl61850_get_rcb to find the RCB. */
rcb = mvl61850_get_rcb (mvluRdVaCtrl->rdVaCtrl->va->base_va,
mvluRdVaCtrl->rt,
&rptClient);
if (rcb != NULL)
{
#if 1 /* NOTE: Ed2 says to return different value if RptEna=FALSE or TRUE.*/
if (rptClient->basrcb.RptEna==0)
{
entry = (BUFLIST_ENTRY *) list_find_last ((DBL_LNK *) rptClient->rpt_ctrl->brcbCtrl.rpt_list);
if (entry == NULL) /* empty list */
{ /* Empty buffer. Return all 0. */
MMS_BTIME6 *btime = (MMS_BTIME6 *)mvluRdVaCtrl->primData;
btime->ms = 0;
btime->day = 0;
}
else
memcpy (mvluRdVaCtrl->primData, &entry->TimeOfEntry, sizeof (MMS_BTIME6));
}
else
memcpy (mvluRdVaCtrl->primData, &rptClient->rpt_ctrl->brcbCtrl.lastSentTimeOfEntry, sizeof (MMS_BTIME6));
#else /* old way (before Ed2) */
memcpy (mvluRdVaCtrl->primData, &rcb->TimeofEntry, sizeof (MMS_BTIME6));
#endif
rc = SD_SUCCESS;
}
mvlu_rd_prim_done (mvluRdVaCtrl, rc);
}
/************************************************************************/
/* mvlu_purgebuf_wr_ind */
/************************************************************************/
ST_VOID mvlu_purgebuf_wr_ind (MVLU_WR_VA_CTRL *mvluWrVaCtrl)
{
ST_BOOLEAN newval; /* val to write to RptEna */
MVLU_BASRCB *rcb;
MVLU_RPT_CLIENT *rptClient;
ST_RET rc;
rc = SD_FAILURE;
/* Only for 61850, so use mvl61850_get_rcb to find the RCB. */
rcb = mvl61850_get_rcb (mvluWrVaCtrl->wrVaCtrl->va->base_va,
mvluWrVaCtrl->rt,
&rptClient);
if (_rcb_writable (rcb, rptClient, mvluWrVaCtrl))
{ /* rcb found and NOT enabled */
rc = SD_SUCCESS; /* allow write */
newval = *(ST_BOOLEAN *) mvluWrVaCtrl->primData;
/* If the client is enabling the Purge, dump rpts_sent & rpts_queued */
if (newval != 0) /* any non-zero val means "enable" */
{
/* this function does just what we want. */
mvl61850_brcb_rpt_lists_clean (&rptClient->rpt_ctrl->brcbCtrl);
/*renxiaobao 61850 <20>ڶ<EFBFBD><DAB6><EFBFBD><EFBFBD>޸<EFBFBD>*/
memset(rcb->EntryID,0,8);
}
/* NOTE: don't actually change any value because PurgeBuf is */
/* automatically set back to 0 when Purge is complete. */
}
else
mvluWrVaCtrl->wrVaCtrl->failure = ARE_TEMP_UNAVAIL;
mvlu_wr_prim_done (mvluWrVaCtrl, rc);
}
/************************************************************************/
/* mvlu_gi_wr_ind */
/************************************************************************/
ST_VOID mvlu_gi_wr_ind (MVLU_WR_VA_CTRL *mvluWrVaCtrl)
{
ST_BOOLEAN newval; /* val to write to RptEna */
MVLU_BASRCB *rcb;
MVLU_RPT_CLIENT *rptClient;
ST_RET rc;
rc = SD_FAILURE;
/* Only for 61850, so use mvl61850_get_rcb to find the RCB. */
rcb = mvl61850_get_rcb (mvluWrVaCtrl->wrVaCtrl->va->base_va,
mvluWrVaCtrl->rt,
&rptClient);
/* Check all condtions. If all conditions right, set rc=SD_SUCCESS to allow write.*/
if (rcb != NULL)
{
/* RCB must be enabled. */
/* NOTE: this is only RCB attribute that is writable when RCB enabled.*/
if (rptClient->basrcb.RptEna)
{
if (rptClient->rpt_ctrl->rcb_type == RCB_TYPE_IEC_URCB)
{
/* URCB must be reserved by this clint. RCB is enabled, so it */
/* must already be reserved. Just make sure reserved by this client.*/
if (rptClient->netInfo == mvluWrVaCtrl->indCtrl->event->net_info)
rc = SD_SUCCESS; /* allow write */
else
MVLU_LOG_FLOW1 ("Write of GI for RptID='%s' FAILED because RCB reserved by another client",
rcb->RptID);
}
else /* RCB_TYPE_IEC_BRCB */
rc = SD_SUCCESS; /* allow write */
}
else
MVLU_LOG_FLOW1 ("Write of GI for RptID='%s' FAILED because RCB not enabled",
rcb->RptID);
}
if (rc == SD_SUCCESS)
{
newval = *(ST_BOOLEAN *) mvluWrVaCtrl->primData;
/* If client is enabling the GI & TrgOps.GI=TRUE, start GI scan.*/
if (newval != 0 /* any non-zero val means "enable" */
&& BSTR_BIT_GET(rcb->TrgOps.data, TRGOPS_BITNUM_GENERAL_INTERROGATION) != 0)
mvlu_integrity_scan_read (rptClient,
mvlu_gi_scan_va_done,
mvlu_gi_scan_done); /* begin GI scan*/
else if(newval != 0) rc = SD_FAILURE; /*renxiaobao add 20180731*/
/* NOTE: don't actually change any value because GI is automatically*/
/* set back to 0 when GI is complete. */
}
else /* for any error, return TEMP_UNAVAIL */
mvluWrVaCtrl->wrVaCtrl->failure = ARE_TEMP_UNAVAIL;
mvlu_wr_prim_done (mvluWrVaCtrl, rc);
}
/************************************************************************/
/* mvlu_entryid_wr_ind */
/************************************************************************/
ST_VOID mvlu_entryid_wr_ind (MVLU_WR_VA_CTRL *mvluWrVaCtrl)
{
MVLU_BASRCB *rcb;
MVLU_RPT_CLIENT *rptClient;
ST_RET rc;
rc = SD_FAILURE;
/* Only for 61850, so use mvl61850_get_rcb to find the RCB. */
rcb = mvl61850_get_rcb (mvluWrVaCtrl->wrVaCtrl->va->base_va,
mvluWrVaCtrl->rt,
&rptClient);
if (_rcb_writable (rcb, rptClient, mvluWrVaCtrl))
{
/* NOTE: primData points to EntryID as Ostring8. */
rc = mvl61850_brcb_rpt_set_entryid (rptClient, (ST_UCHAR *) mvluWrVaCtrl->primData);
}
else
mvluWrVaCtrl->wrVaCtrl->failure = ARE_TEMP_UNAVAIL;
mvlu_wr_prim_done (mvluWrVaCtrl, rc);
}
/************************************************************************/
/* mvlu_sqnum_int16u_rd_ind_fun */
/* Same as mvlu_sqnum_rd_ind_fun except uses SqNumInt16u */
/* (UINT16 instead of UINT8). */
/************************************************************************/
ST_VOID mvlu_sqnum_int16u_rd_ind_fun (MVLU_RD_VA_CTRL *mvluRdVaCtrl)
{
ST_UINT16 *dest;
MVLU_BASRCB *rcb;
ST_RET rc;
rc = SD_FAILURE;
/* Only for 61850, so use mvl61850_get_rcb to find the RCB. */
rcb = mvl61850_get_rcb (mvluRdVaCtrl->rdVaCtrl->va->base_va,
mvluRdVaCtrl->rt,
NULL);
if (rcb != NULL)
{
dest = (ST_UINT16 *) mvluRdVaCtrl->primData;
*dest = rcb->SqNumInt16u;
rc = SD_SUCCESS;
}
mvlu_rd_prim_done (mvluRdVaCtrl, rc);
}
/************************************************************************/
/* mvl61850_beh_stval_rd_ind */
/************************************************************************/
ST_VOID mvl61850_beh_stval_rd_ind (MVLU_RD_VA_CTRL *mvluRdVaCtrl)
{
MVL_VAR_ASSOC *base_var;
MVL_VAR_ASSOC *lln0_var;
ST_RET retcode = SD_SUCCESS;
ST_INT32 mod_stval; /* ST$Mod$stVal from this LN */
ST_INT32 lln0mod_stval; /* ST$Mod$stVal from LLN0 */
ST_INT32 beh_stval; /* ST$Beh$stVal from this LN (computed) */
MVL_DOM_CTRL *dom;
ST_INT j;
base_var = mvluRdVaCtrl->rdVaCtrl->va->base_va;
/* Get value of "ST$Mod$stVal" in this LN. */
retcode = mvlu_get_leaf_val_int_any (base_var, "ST$Mod$stVal", &mod_stval);
if (retcode == SD_SUCCESS)
{
/* Get value of "ST$Mod$stVal" in LLN0 of the same domain. */
lln0_var = NULL; /* assume it's not found */
assert (mvluRdVaCtrl->rdVaCtrl->va_scope.scope == DOM_SPEC);
dom = mvluRdVaCtrl->rdVaCtrl->va_scope.dom;
for (j = 0; j < dom->num_var_assoc; j++)
{
/* Use "strstr" because name may have prefix and suffix*/
if (strstr (dom->var_assoc_tbl[j]->name, "LLN0") != NULL)
{
lln0_var = dom->var_assoc_tbl[j];
break; /* found it. stop looping */
}
}
if (lln0_var)
retcode = mvlu_get_leaf_val_int_any (lln0_var, "ST$Mod$stVal", &lln0mod_stval);
else
retcode = SD_FAILURE;
}
if (retcode == SD_SUCCESS)
{ /* both successful. combine results. */
switch (lln0mod_stval)
{
case 1:
if (mod_stval > 0 && mod_stval <= 5)
beh_stval = mod_stval;
else
beh_stval = 0; /* Mod is illegal, so set Beh to illegal value too*/
break;
case 2:
switch (mod_stval)
{
case 1:
case 2:
beh_stval = 2; break;
case 3:
case 4:
beh_stval = 4; break;
case 5:
beh_stval = 5; break;
default:
beh_stval = 0; break; /* Mod is illegal, so set Beh to illegal value too*/
}
break;
case 3:
switch (mod_stval)
{
case 1:
beh_stval = 3; break;
case 2:
beh_stval = 4; break;
case 3:
beh_stval = 3; break;
case 4:
beh_stval = 4; break;
case 5:
beh_stval = 5; break;
default:
beh_stval = 0; break; /* Mod is illegal, so set Beh to illegal value too*/
}
break;
case 4:
switch (mod_stval)
{
case 1:
case 2:
case 3:
case 4:
beh_stval = 4; break;
case 5:
beh_stval = 5; break;
default:
beh_stval = 0; break; /* Mod is illegal, so set Beh to illegal value too*/
}
break;
case 5:
if (mod_stval > 0 && mod_stval <= 5)
beh_stval = 5;
else
beh_stval = 0; /* Mod is illegal, so set Beh to illegal value too*/
break;
default:
beh_stval = 0; /* LLNO Mod is illegal, so set Beh to illegal value too*/
break;
} /* end outer switch */
}
if (retcode == SD_SUCCESS)
{
/* Convert data to configured type (INT8, INT16, or INT32). */
if (mvluRdVaCtrl->rt->u.p.el_len == 1)
*(ST_INT8 *) mvluRdVaCtrl->primData = (ST_INT8) beh_stval; /* copy data */
else if (mvluRdVaCtrl->rt->u.p.el_len == 2)
*(ST_INT16 *) mvluRdVaCtrl->primData = (ST_INT16) beh_stval; /* copy data */
else if (mvluRdVaCtrl->rt->u.p.el_len == 4)
*(ST_INT32 *) mvluRdVaCtrl->primData = beh_stval; /* copy data */
else
retcode = SD_FAILURE; /* unsupported len. Should never happen.*/
}
mvlu_rd_prim_done (mvluRdVaCtrl, retcode);
}
/************************************************************************/
/* mvl61850_datset_wr_ind */
/* Try to change IEC 61850 Report Dataset. */
/* NOTE: for IEC 61850 only (not for UCA). */
/************************************************************************/
ST_VOID mvl61850_datset_wr_ind (MVLU_WR_VA_CTRL *mvluWrVaCtrl)
{
MVLU_BASRCB *rcb;
ST_RET retCode;
ST_CHAR tmpbuf [MVL61850_MAX_OBJREF_LEN+1];
OBJECT_NAME nvl_oname;
MVLU_RPT_CLIENT *rptClient;
MVL_NVLIST_CTRL *nvl;
ST_BOOLEAN do_purge = SD_FALSE; /* Chg to SD_TRUE if Purge Buffer required*/
ST_INT16 failure = ARE_TEMP_UNAVAIL; /* use on err if no other value set*/
retCode = SD_FAILURE;
/* Only for 61850, so use mvl61850_get_rcb to find the RCB. */
rcb = mvl61850_get_rcb (mvluWrVaCtrl->wrVaCtrl->va->base_va,
mvluWrVaCtrl->rt,
&rptClient);
if (_rcb_writable (rcb, rptClient, mvluWrVaCtrl))
{
if (strcmp (rcb->DatSetNa, mvluWrVaCtrl->primData) == 0)
{
retCode = SD_SUCCESS; /* Same val written. Nothing to do but allow it*/
}
else if (mvluWrVaCtrl->primData[0] == '\0')
{ /* client wrote empty string, and it was NOT already empty */
mvl61850_rpt_dataset_destroy (rptClient->rpt_ctrl);
rcb->ConfRev++; /* DatSet changed. Must increment ConfRev. */
retCode = SD_SUCCESS;
}
else if (strlen ((ST_CHAR *) mvluWrVaCtrl->primData) > MVL61850_MAX_OBJREF_LEN)
{
failure = ARE_OBJ_VALUE_INVALID;
}
else
{
/* strtok modifies input buffer, so copy to local buffer first. */
strcpy (tmpbuf, (ST_CHAR *) mvluWrVaCtrl->primData);
if (tmpbuf[0] == '@')
{ /* AA-Specific Dataset */
nvl_oname.obj_name.vmd_spec = &tmpbuf[1]; /*extract NVL name*/
nvl_oname.object_tag = AA_SPEC;
}
else if (tmpbuf[0] == '/')
{ /* VMD-Specific Dataset */
nvl_oname.obj_name.vmd_spec = &tmpbuf[1]; /*extract NVL name*/
nvl_oname.object_tag = VMD_SPEC;
}
else
{ /* must be Domain-Specific Dataset */
nvl_oname.domain_id = strtok (tmpbuf, "/"); /*extract dom name*/
nvl_oname.obj_name.vmd_spec = strtok (NULL, ""); /*extract NVL name*/
nvl_oname.object_tag = DOM_SPEC;
}
/* If DatSet name is illegal, fail.*/
if (nvl_oname.obj_name.vmd_spec == NULL) /* strtok failed*/
{
MVL_LOG_ERR1 ("DatSet name '%s' is invalid. Cannot write it to RCB.",
(ST_CHAR *) mvluWrVaCtrl->primData);
failure = ARE_OBJ_VALUE_INVALID;
}
else if (nvl_oname.object_tag == AA_SPEC &&
rptClient->rpt_ctrl->rcb_type == RCB_TYPE_IEC_BRCB)
{
MVL_LOG_ERR1 ("Writing AA-Specific DatSet '%s' to BRCB is NEVER allowed.",
(ST_CHAR *) mvluWrVaCtrl->primData);
failure = ARE_OBJ_VALUE_INVALID;
}
else if (nvl_oname.object_tag == AA_SPEC &&
rptClient->rpt_ctrl->rcb_type == RCB_TYPE_IEC_URCB &&
rptClient->basrcb.Resv == 0)
{
MVL_LOG_ERR1 ("Writing AA-Specific DatSet '%s' to URCB not allowed because URCB is not reserved.",
(ST_CHAR *) mvluWrVaCtrl->primData);
failure = ARE_OBJ_VALUE_INVALID;
}
else
{
nvl = mvl_vmd_find_nvl (&mvl_vmd, &nvl_oname,
mvluWrVaCtrl->indCtrl->event->net_info); /* for AA_SPEC*/
if (nvl)
{
if (rptClient->rpt_ctrl->rcb_type == RCB_TYPE_IEC_BRCB)
do_purge = SD_TRUE; /* BRCB & val changed, must purge buffer*/
/* Replace "dataset". */
/* NOTE: If dataset was empty, destroy function does nothing. */
mvl61850_rpt_dataset_destroy (rptClient->rpt_ctrl);
retCode = mvl61850_rpt_dataset_create (rptClient->rpt_ctrl, nvl);
/* WARNING: if create fails, old dataset is lost.*/
if (retCode)
{
MVL_LOG_ERR1 ("DatSet change failed. RCB DatSet '%s' is no longer valid.", rcb->DatSetNa);
/* Old DatSet is no longer valid, so clear it.*/
rcb->DatSetNa[0] = '\0';
}
/* Even if create failed, DatSet changed (to NULL) so inc ConfRev.*/
rcb->ConfRev++; /* DatSet changed. Must increment ConfRev.*/
/*renxiaobao 61850 <20>ڶ<EFBFBD><DAB6><EFBFBD><EFBFBD>޸<EFBFBD>*/
memset(rcb->EntryID,0,8);
}
}
}
}
if (do_purge)
mvl61850_brcb_rpt_lists_clean (&rptClient->rpt_ctrl->brcbCtrl);
if (retCode != SD_SUCCESS)
mvluWrVaCtrl->wrVaCtrl->failure = failure;
mvlu_wr_prim_done (mvluWrVaCtrl, retCode);
}
/************************************************************************/
/* fill_asn1_len_array */
/* Compute the ASN.1 encoded len for each var in a rpt dataset. */
/************************************************************************/
static ST_RET fill_asn1_len_array (MVLU_RPT_CLIENT *rptClient,
MVL_NVLIST_CTRL *dsNvl, /* rpt dataset */
ST_INT *asn1_len_array) /* array of ASN.1 lengths, one for each var*/
/* array filled in by this function */
{
ST_UCHAR *tmp_asn1_buf; /* temporary ASN.1 buffer (allocated) */
ST_INT tmp_asn1_buf_size = mvl_cfg_info->max_msg_size; /* reasonable size*/
ST_INT j;
ST_RET retCode=SD_SUCCESS; /* assume success */
/* Alloc tmp ASN.1 buffer. Use it for each encode in this loop. */
tmp_asn1_buf = chk_malloc (tmp_asn1_buf_size);
for (j = 0; j < dsNvl->num_of_entries; ++j)
{
if (rptClient->reasons_data[j]) /* this var should be included in rpt */
{
ST_UCHAR *asn1_ptr;
MVL_TYPE_CTRL *type_ctrl = dsNvl->entries[j]->type_ctrl;
retCode = ms_local_to_asn1_2 (type_ctrl->rt, type_ctrl->num_rt,
dsNvl->entries[j]->data, /* CRITICAL: use data from var*/
tmp_asn1_buf,
tmp_asn1_buf_size,
&asn1_ptr, /* function sets asn1_ptr (not needed here)*/
&asn1_len_array[j]); /* function sets len at this ptr*/
if (retCode)
{
/* Should NEVER fail, but if so, don't continue with other vars.*/
break;
}
}
} /* end loop */
chk_free (tmp_asn1_buf);
return (retCode);
}
/************************************************************************/
/* mvl61850_objref_create */
/* Create the ObjectReference for this Object. */
/* objRef must point to buffer of at least [MVL61850_MAX_OBJREF_LEN+1] char*/
/************************************************************************/
ST_RET mvl61850_objref_create (ST_CHAR *objName,
MVL_SCOPE *objScope,
ST_CHAR *objRef) /* ptr to ObjectReference */
{
switch (objScope->scope)
{
case VMD_SPEC:
strcpy (objRef, "/");
break;
case DOM_SPEC:
strcpy (objRef, objScope->dom->name);
strcat (objRef, "/");
break;
case AA_SPEC:
strcpy (objRef,"@/");
break;
}
/* Scope in place, now append the name of the Object. */
if (strlen(objRef) + strlen(objName) > MVL61850_MAX_OBJREF_LEN)
{ /* should NEVER happen */
MVL_LOG_ERR0 ("Can't generate ObjectReference (too long)");
objRef [0] = '\0'; /* return empty string */
return (SD_FAILURE);
}
strcat (objRef, objName);
return (SD_SUCCESS);
}