/** * @file: $RCSfile: mmscli_rpt.c,v $ * @brief: $IEC 61850 Protocol * * @version: $Revision: 1.12 $ * @date: $Date: 2022/11/28 07:13:13 $ * @author: $Author: lizhongming $ * @state: $State: Exp $ * * @latest: $Id: mmscli_rpt.c,v 1.12 2022/11/28 07:13:13 lizhongming Exp $ * */ //$Header: /JoyProject/jspqfe/src/pt61850netd_pqfe/source/mms/mmscli_rpt.c,v 1.12 2022/11/28 07:13:13 lizhongming Exp $ /************************************************************************/ /* SISCO SOFTWARE MODULE HEADER *****************************************/ /************************************************************************/ /* (c) Copyright Systems Integration Specialists Company, Inc., */ /* 2003 - 2005, All Rights Reserved */ /* */ /* MODULE NAME : cli_rpt.c */ /* PRODUCT(S) : MMSEASE-LITE */ /* */ /* MODULE DESCRIPTION : */ /* Functions to perform "client" processing of IEC-61850 Reports */ /* and UCA Reports received from "servers". */ /* */ /* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ /* rpt_typeids_find */ /* rcb_info_create */ /* rcb_info_destroy */ /* u_iec_rpt_ind */ /* u_iec_rpt_ind_data (user modify or replace) */ /* */ /* MODIFICATION LOG : */ /* Date Who Rev Comments */ /* -------- --- ------ ------------------------------------------- */ /* 07/22/05 JRB 08 Allow one conn to control multiple RCBs */ /* (user_info must point to ALL_RCB_INFO). */ /* Save varNameArray in rcb_info to use later. */ /* Chg u_iec_rpt_ind_data 4th arg to (RCB_INFO *).*/ /* 12/03/04 JRB 07 Extract domain name of NVL from dataSetName. */ /* Increase RptID length to vstring65. */ /* 08/04/04 EJV 06 rcb_info_create: added typecast for Inclusion*/ /* 06/29/04 JRB 05 Del mvl_tdl_to_type_id & instead use new */ /* mvl_type_id_create_from_tdl. */ /* 05/13/04 JRB 04 Chg SqNum to INT16U to match 61850-7-2. */ /* 01/23/04 JRB 03 Use ms_local_to_text. */ /* 12/17/03 JRB 02 61850-8-1 FDIS changes: */ /* Decode ConfRev in rpt if enabled by OptFlds. */ /* Move SubSeqNum, MoreSegmentsFollow to just */ /* before inclusion bitstring. */ /* Chg OptFlds from bvstring9 to bvstring10. */ /* 10/24/03 JRB 01 New */ /************************************************************************/ #include "rdb_client.h" #include "db_interface.h" #include "../json/mms_json_inter.h" /************************************************************************/ /* 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 extern pt61850app_t* g_pt61850app; extern RPT_TYPEIDS g_rpt_typeids; //lnk20250115 extern pthread_mutex_t mtx; /************************************************************************/ /* Global variables. */ /************************************************************************/ /* NONE */ /************************************************************************/ /* Static function prototypes. */ /************************************************************************/ static OBJECT_NAME** nvl_var_name_array_create(MVL_NET_INFO* net_info, ST_CHAR* domName, ST_CHAR* nvlName, ST_INT* numVarOut, ST_INT timeOut); static ST_VOID nvl_var_name_array_destroy(OBJECT_NAME** varNameArray, ST_INT numVar); static ST_INT var_type_create(MVL_NET_INFO* net_info, OBJECT_NAME* varObj, ST_INT timeOut); static ST_RET rcb_info_var_create(RCB_INFO* rcb_info, RPT_TYPEIDS* rpt_typeids); static ST_VOID rcb_info_var_destroy(RCB_INFO* rcb_info); static ST_VOID log_var_data(MVL_VAR_ASSOC* var, MMS_DECODE_DATA* data); /* DEBUG: move these functions to library modules? */ OBJECT_NAME* object_name_clone_create(OBJECT_NAME* srcobj); ST_VOID object_name_clone_destroy(OBJECT_NAME* obj); static ST_ULONG a_get_rem_ip_addr_inline(ST_LONG acse_conn_id, int* nPort); static char* _convert_ip_2_char(unsigned long dwIP); #if 1 //测试 获取服务器IP WW 2023-08-29 static char* _convert_ip_2_char(unsigned long dwIP) { static char buf[64] = { 0 }; sprintf(buf, "%d.%d.%d.%d", (dwIP >> 24) & 0xff, (dwIP >> 16) & 0xff, (dwIP >> 8) & 0xff, (dwIP) & 0xff); return buf; } #if defined (TP0_ENABLED) /************************************************************************/ /* a_get_rem_ip_addr */ /* This function returns the remote IP Address as an unsigned long in */ /* "network byte order", just like the "standard sockets" function */ /* "inet_addr" does. If there is an error, it returns */ /* "htonl (INADDR_NONE)", just like "inet_addr" does. */ /* The return value can be stored in the appropriate union member */ /* in the structure "in_addr", which can be passed to "inet_ntoa". */ /************************************************************************/ #include "tp4.h" /* Need internal TP4 defines */ #include "tp0_sock.h" /* Need "sockets" defines */ #include "acse2.h" /* Need "sockets" defines */ #define MAX_PATH 256 static ST_ULONG get_rem_ip_addr_inline(ST_LONG acse_conn_id, int* nPort) { ACSE_CONN *acse_conn; ST_LONG tp_conn_id; TP0_CONN *tp0_conn; ST_INT ret; SOCKADDR_IN sockaddr_in; SOCK_ADDRLEN addr_len; char buf[MAX_PATH] = { 0 }; acse_conn = (ACSE_CONN *)acse_conn_id; tp_conn_id = acse_conn->tp4_conn_id; if (tp_conn_id >= MIN_TP0_CONN_ID && tp_conn_id < tp0_cfg.max_num_conns + MIN_TP0_CONN_ID) { /* Conn id is a legal TP0 conn id */ tp0_conn = &tp0_conn_arr[tp_conn_id - MIN_TP0_CONN_ID]; addr_len = sizeof(SOCKADDR_IN); /* CRITICAL: set to expected len.*/ ret = getpeername(tp0_conn->sock_info->genSock->hSock, (SOCKADDR *)&sockaddr_in, &addr_len); *nPort = htons(sockaddr_in.sin_port); if (ret == 0) return (sockaddr_in.sin_addr.s_addr); } return (htonl(INADDR_NONE)); /* something failed */ } #endif /* defined (TP0_ENABLED) */ #endif /************************************************************************/ /* rpt_typeids_find */ /* Find ALL types needed for controlling & decoding IEC/UCA reports. */ /* These types must be defined in the ODF file and created by Foundry. */ /* RETURN: SD_SUCCESS or SD_FAILURE (if ANY type is NOT found) */ /* NOTE: this function based on "mvlu_rpt_find_typeids" in "mvlu_rpt.c".*/ /************************************************************************/ ST_RET rpt_typeids_find(RPT_TYPEIDS* rpt_typeids) { ST_RET retCode = SD_FAILURE; /* assume FAILURE for now */ ST_CHAR* type_name; /* name of type to be found */ /* stop on any error */ do { /* "one-time" loop: just to have something to break out of */ if ((rpt_typeids->mmsbool = mvl_typename_to_typeid(type_name = "RTYP_BOOL")) < 0) break; if ((rpt_typeids->bstr6 = mvl_typename_to_typeid(type_name = "RTYP_BSTR6")) < 0) break; if ((rpt_typeids->bstr8 = mvl_typename_to_typeid(type_name = "RTYP_BSTR8")) < 0) break; if ((rpt_typeids->bstr9 = mvl_typename_to_typeid(type_name = "RTYP_BSTR9")) < 0) break; if ((rpt_typeids->bvstring6 = mvl_typename_to_typeid(type_name = "RTYP_BVSTR6")) < 0) break; if ((rpt_typeids->bvstring8 = mvl_typename_to_typeid(type_name = "RTYP_BVSTR8")) < 0) break; if ((rpt_typeids->bvstring10 = mvl_typename_to_typeid(type_name = "RTYP_BVSTR10")) < 0) break; if ((rpt_typeids->btime6 = mvl_typename_to_typeid(type_name = "RTYP_BTIME6")) < 0) break; if ((rpt_typeids->int8u = mvl_typename_to_typeid(type_name = "RTYP_INT8U")) < 0) break; if ((rpt_typeids->int16u = mvl_typename_to_typeid(type_name = "RTYP_INT16U")) < 0) break; if ((rpt_typeids->int32u = mvl_typename_to_typeid(type_name = "RTYP_INT32U")) < 0) break; if ((rpt_typeids->ostring8 = mvl_typename_to_typeid(type_name = "RTYP_OSTR8")) < 0) break; if ((rpt_typeids->vstring32 = mvl_typename_to_typeid(type_name = "RTYP_VSTR32")) < 0) break; if ((rpt_typeids->vstring65 = mvl_typename_to_typeid(type_name = "RTYP_VSTR65")) < 0) break; retCode = SD_SUCCESS; /* If we get here, all were successful */ } while (0); /* end of "one-time" loop */ if (retCode) MVL_LOG_ERR1("Can't find type '%s'", type_name); return (retCode); /* If ANY find failed, SD_FAILURE is returned */ } /************************************************************************/ /* rcb_info_create */ /************************************************************************/ RCB_INFO* rcb_info_create(MVL_NET_INFO* net_info, ST_CHAR* domName, ST_CHAR* rcbName, RPT_TYPEIDS* rpt_typeids, ST_INT timeOut) { RCB_INFO* rcb_info; ST_CHAR varName[MAX_IDENT_LEN + 1]; ST_CHAR datSetName[65 + 1]; /* data set name (Vstring65) */ ST_CHAR datdomName[65 + 1]; /* data set name (Vstring65) */ ST_CHAR RptID[65 + 1]; /* RptID (Vstring65) */ ST_CHAR* nvlName; ST_INT numDsVar; /* num variables in NVL */ OBJECT_NAME** varNameArray; /* array of variable names in NVL */ ST_INT j; size_t extended_size; ST_CHAR* extended_ptr; ST_CHAR InclusionTdl[30]; /* place to create TDL for inclusion bstr*/ ST_RET status = SD_SUCCESS; /* set to SD_FAILURE if anything fails. */ ST_CHAR* nvlDomName; ST_INT rcb_type; assert(rpt_typeids->mmsbool || rpt_typeids->int8u); /* make sure global struct initialized*/ /* Read "RptID" from the server & save in "RptID" local variable. */ /* Copy to "rcb_info" struct later. */ strcpy(varName, rcbName); strcat(varName, "$RptID"); if (mms_named_var_read(net_info, varName, DOM_SPEC, domName, rpt_typeids->vstring65, RptID, timeOut)) { echo_warn2("Error reading RptID '%s' in domain '%s'\n", varName, domName); return (NULL); } /* Figure out RCB type from 'rcbName'. */ if (strstr(rcbName, "$BR$") != NULL) rcb_type = RCB_TYPE_IEC_BRCB; else if (strstr(rcbName, "$RP$") != NULL) { /* This could be IEC URCB or UCA URCB. Only IEC contains "Resv" attr.*/ /* Try to read "Resv". If successful, RCB is IEC_URCB, else it is UCA.*/ /* NOTE: "RptID" read was successful, so we know this RCB exists. */ ST_BOOLEAN tmpResv; strcpy(varName, rcbName); strcat(varName, "$Resv"); if (mms_named_var_read(net_info, varName, DOM_SPEC, domName, rpt_typeids->mmsbool, &tmpResv, timeOut) == SD_SUCCESS) rcb_type = RCB_TYPE_IEC_URCB; else rcb_type = RCB_TYPE_UCA; } else { echo_warn1("RCB name '%s' invalid. Must contain 'BR' or 'RP'.\n", rcbName); return (NULL); } /* Read "DatSet" from the server. */ strcpy(varName, rcbName); strcat(varName, "$DatSet"); if (mms_named_var_read(net_info, varName, DOM_SPEC, domName, rpt_typeids->vstring65, datSetName, timeOut)) { /* can't read data set name */ echo_warn2("Error reading data set name ('%s' in domain '%s')\n", varName, domName); return (NULL); } /* datSetName should now be set */ strcpy(datdomName, datSetName);//WW 2023-10-23 nvlDomName = strtok(datdomName, "/");/* extract domain name of NVL */ nvlName = strtok(NULL, ""); /* extract NVL name */ if (nvlName == NULL) /* "/" not found */ { echo_warn1("datSetName '%s' invalid. Does not contain '/' character.", datSetName); return (NULL); } /* Get NVL Attributes from the server */ /* NOTE: Resources allocated by this funct are freed by calling */ /* nvl_var_name_array_destroy (called from rcb_info_destroy). */ varNameArray = nvl_var_name_array_create(net_info, nvlDomName, nvlName, &numDsVar, timeOut); if (varNameArray == NULL) { echo_warn2("GetNamedVariableListAttributes request failed for '%s' in domain '%s'", nvlName, domName); return (NULL); } /* Allocate RCB_INFO structure plus extra room for additional data * that depends on "numDsVar". This effectively combines 8 allocations into one. * Set pointers in RCB_INFO structure to point into the extra space. * CRITICAL: use chk_calloc to start with clean structure */ extended_size = sizeof(RCB_INFO) + numDsVar * sizeof(ST_INT) /* rcb_info->typeIdArr */ + numDsVar * sizeof(MVL_VAR_ASSOC*) /* rcb_info->rcb_var.dataRefName*/ + numDsVar * sizeof(MVL_VAR_ASSOC*) /* rcb_info->rcb_var.dataValue */ + numDsVar * sizeof(MVL_VAR_ASSOC*) /* rcb_info->rcb_var.Reason */ + numDsVar * 66 /* rcb_info->rcb_data.dataRefName*/ + numDsVar * sizeof(MMS_BVSTRING) /* rcb_info->rcb_data.Reason */ + BSTR_NUMBITS_TO_NUMBYTES(numDsVar); /* rcb_info->rcb_data.Inclusion */ rcb_info = (RCB_INFO*)chk_calloc(1, extended_size); strcpy(rcb_info->dom_Name, domName); //WW 2023-08-29 逻辑设备名称 strcpy(rcb_info->rcb_name, rcbName); //WW 2023-08-29 报告控制块名称 ////////////////////////////////////////////////////////////////////////// strcpy(rcb_info->ds_Nam, datSetName); //WW 2023-08-29 数据集名称 ////////////////////////////////////////////////////////////////////////// echo_msg4("Client RCB info 0x%X created for '%s' in domain '%s'.datasetnam '%s' \n", rcb_info, rcbName, domName, datSetName); extended_ptr = (ST_CHAR*)(rcb_info + 1); /* point after RCB_INFO struct */ rcb_info->typeIdArr = (ST_INT*)extended_ptr; extended_ptr += numDsVar * sizeof(ST_INT); /* point after rcb_info->typeIdArr*/ rcb_info->rcb_var.dataRefName = (MVL_VAR_ASSOC**)extended_ptr; extended_ptr += numDsVar * sizeof(MVL_VAR_ASSOC*); /* rcb_info->rcb_var.dataRefName*/ rcb_info->rcb_var.dataValue = (MVL_VAR_ASSOC**)extended_ptr; extended_ptr += numDsVar * sizeof(MVL_VAR_ASSOC*); /* rcb_info->rcb_var.dataValue */ rcb_info->rcb_var.Reason = (MVL_VAR_ASSOC**)extended_ptr; extended_ptr += numDsVar * sizeof(MVL_VAR_ASSOC*); /* rcb_info->rcb_var.Reason */ rcb_info->rcb_data.dataRefName = extended_ptr; extended_ptr += numDsVar * 66; /* rcb_info->rcb_data.dataRefName*/ rcb_info->rcb_data.Reason = (MMS_BVSTRING*)extended_ptr; extended_ptr += numDsVar * sizeof(MMS_BVSTRING); /* rcb_info->rcb_data.Reason */ rcb_info->rcb_data.Inclusion = (ST_UINT8*)extended_ptr; extended_ptr += BSTR_NUMBITS_TO_NUMBYTES(numDsVar); /* rcb_info->rcb_data.Inclusion */ /* Make sure we computed sizes correctly. */ assert(extended_ptr == (ST_CHAR*)rcb_info + extended_size); /* Fill in other rcb_info structure members. */ rcb_info->rcb_type = rcb_type; strcpy(rcb_info->RptID, RptID); /* save RptID to compare when RPTs received*/ rcb_info->varNameArray = varNameArray; rcb_info->numDsVar = numDsVar; /* Create all necessary types. */ /* Try to create all types even if one fails. */ /* This way, we can later destroy all without remembering which */ /* were successfully created. */ /* Create a Type for the Inclusion bitstring. Save it in "rcb_info->InclusionTypeid" */ apr_snprintf(InclusionTdl, sizeof(InclusionTdl), "Bstring%d", rcb_info->numDsVar); rcb_info->InclusionTypeid = mvl_type_id_create_from_tdl(NULL, InclusionTdl); if (rcb_info->InclusionTypeid < 0) { echo_warn("Error - could not add type for 'Inclusion'."); status = SD_FAILURE; } /* Create types and fill in rcb_info->typeIdArr */ /* Start with all set to invalid, so if some fail, cleanup is easier. */ for (j = 0; j < numDsVar; j++) rcb_info->typeIdArr[j] = -1; /* invalid type_id */ for (j = 0; j < numDsVar; j++) { if ((rcb_info->typeIdArr[j] = var_type_create(net_info, varNameArray[j], timeOut)) < 0) { /* couldn't create this type, so stop */ echo_warn1("Error creating type for variable '%s'", varNameArray[j]->obj_name.vmd_spec); status = SD_FAILURE; break; } } if (status == SD_SUCCESS) { /* Types created OK, so create variables */ status = rcb_info_var_create(rcb_info, rpt_typeids); /* returns SD_SUCCESS or SD_FAILURE*/ } if (status != SD_SUCCESS) { /* something failed. Destroy anything created. */ rcb_info_destroy(rcb_info); rcb_info = NULL; } return (rcb_info); } /************************************************************************/ /* rcb_info_destroy */ /************************************************************************/ ST_VOID rcb_info_destroy(RCB_INFO* rcb_info) { ST_INT j; /* Free up array of variable names saved in rcb_info_create */ nvl_var_name_array_destroy(rcb_info->varNameArray, rcb_info->numDsVar); /* Destroy all variables. */ rcb_info_var_destroy(rcb_info); /* Destroy "Inclusion" Type (this should be AFTER destroying "Inclusion" Variable).*/ if (rcb_info->InclusionTypeid > 0) /* 0=never created. -1=error */ mvl_type_id_destroy(rcb_info->InclusionTypeid); /* Destroy "dataValue" Types (this should be AFTER destroying "dataValue" variables). */ for (j = 0; j < rcb_info->numDsVar; j++) { /* All types were initialized to -1. They are also set to -1 if create failed.*/ /* Only destroy types that are NOT (-1). */ if (rcb_info->typeIdArr[j] >= 0) mvl_type_id_destroy(rcb_info->typeIdArr[j]); } chk_free(rcb_info); echo_warn1("Client RCB info 0x%X destroyed", rcb_info); } /************************************************************************/ /* nvl_var_name_array_create */ /* Send a GetNamedVariableListAttributes request to get a list of */ /* variable names in a NamedVariableList (NVL). */ /* Assume the NVL is domain-specific */ /* RETURN: ptr to array of ptrs to variable names (OBJECT_NAME structs).*/ /* Also the variable pointed to by numVarOut contains the number*/ /* of variables in the NVL. */ /* NOTE: this function allocates memory for the (OBJECT_NAME *) array. */ /* Call "nvl_var_name_array_destroy" to free the memory. */ /************************************************************************/ static OBJECT_NAME** nvl_var_name_array_create(MVL_NET_INFO* net_info, ST_CHAR* domName, ST_CHAR* nvlName, ST_INT* numVarOut, ST_INT timeOut) { MVL_REQ_PEND* reqCtrl; GETVLIST_REQ_INFO getvlist_req; GETVLIST_RESP_INFO* getvlist_resp; /* set to reqCtrl->u.getvlist_resp_info*/ VARIABLE_LIST* variable_list; OBJECT_NAME** varNameArray; /* Ptr to array of ptrs to var names */ ST_RET ret; /* general purpose return code */ ST_INT j; getvlist_req.vl_name.object_tag = DOM_SPEC; getvlist_req.vl_name.domain_id = domName; getvlist_req.vl_name.obj_name.vmd_spec = nvlName; ret = mvla_getvlist(net_info, &getvlist_req, &reqCtrl); if (ret == SD_SUCCESS) ret = waitReqDone(reqCtrl, timeOut); if (ret != SD_SUCCESS) { echo_warn1("mvla_getvlist Error = 0x%X.", ret); varNameArray = NULL; } else { getvlist_resp = reqCtrl->u.getvlist.resp_info; variable_list = (VARIABLE_LIST*)(getvlist_resp + 1); /* Allocate array of variable names. */ *numVarOut = getvlist_resp->num_of_variables; varNameArray = (OBJECT_NAME**)chk_malloc(getvlist_resp->num_of_variables * sizeof(OBJECT_NAME*)); /* Copy info from response to allocated array */ for (j = 0; j < getvlist_resp->num_of_variables; j++, variable_list++) { /* Assume all variables are named. */ assert(variable_list->var_spec.var_spec_tag == VA_SPEC_NAMED); varNameArray[j] = object_name_clone_create(&variable_list->var_spec.vs.name); } } mvl_free_req_ctrl(reqCtrl); /* CRITICAL: */ return (varNameArray); } /************************************************************************/ /* nvl_var_name_array_destroy */ /* Free up all resources allocated by "nvl_var_name_array_create". */ /************************************************************************/ static ST_VOID nvl_var_name_array_destroy(OBJECT_NAME** varNameArray, ST_INT numVar) { ST_INT j; for (j = 0; j < numVar; j++) object_name_clone_destroy(varNameArray[j]); chk_free(varNameArray); } /************************************************************************/ /* var_type_create */ /* Send GetVariableAccessAttributes request. Wait for response. When */ /* response received, create new type. Pass NULL as type_name arg to */ /* "mvl_type_id_create" (this avoids the problem of duplicate names). */ /* RETURN: Type ID */ /* NOTE: Call "mvl_type_id_destroy" to destroy the type created here. */ /************************************************************************/ static ST_INT var_type_create(MVL_NET_INFO* net_info, OBJECT_NAME* varObj, ST_INT timeOut) { MVL_REQ_PEND* reqCtrl; GETVAR_REQ_INFO getvar_req; VAR_ACC_TSPEC* type_spec; ST_INT type_id = -1; /* invalid. If anything fails, this value returned*/ ST_RET ret; getvar_req.req_tag = GETVAR_NAME; getvar_req.name = *varObj; /* Send GetVariableAccessAttributes request & wait for response. */ ret = mvla_getvar(net_info, &getvar_req, &reqCtrl); if (ret == SD_SUCCESS) ret = waitReqDone(reqCtrl, timeOut); if (ret != SD_SUCCESS) echo_warn1("GetVariableAccessAttributes error = 0x%x.", ret); else { type_spec = &reqCtrl->u.getvar.resp_info->type_spec; /* First arg (type_name) is NULL to avoid duplicate names. */ type_id = mvl_type_id_create(NULL, type_spec->data, type_spec->len); } mvl_free_req_ctrl(reqCtrl); return (type_id); } /************************************************************************/ /* rcb_info_var_create */ /* Create dummy variables to be used later when a report is received. */ /* These variables are needed to decode the data received in a report. */ /* This function fills in "rcb_info->rcb_data" and "rcb_info->rcb_var". */ /************************************************************************/ static ST_RET rcb_info_var_create(RCB_INFO* rcb_info, RPT_TYPEIDS* rpt_typeids) { OBJECT_NAME dummyvar_objname; /* dummy variable object name */ ST_INT j; ST_INT incSize; /* num bytes for inclusion bitstring */ /* CRITICAL: "mvl_var_create" is used (NOT "mvl_var_add") to create * local variables to store data received later in IEC/UCA Reports. * These are NOT real variables, so remote MMS nodes cannot access them. * All variables use the same name (dummyvar): that's OK because * "mvl_var_create" does NOT add them to the database and nothing needs * to use the name. */ /* NOTE: last arg to mvl_var_create is always SD_FALSE, so the name is * NOT copied. This is OK because all names here are fixed strings. */ /* Set up one OBJECT_NAME to use for all variables. */ dummyvar_objname.object_tag = VMD_SPEC; dummyvar_objname.obj_name.vmd_spec = "dummyvar"; /* all vars use same name */ if ((rcb_info->rcb_var.RptID = mvl_var_create(&dummyvar_objname, rpt_typeids->vstring65, &rcb_info->rcb_data.RptID, NULL, SD_FALSE)) == NULL) return (SD_FAILURE); if ((rcb_info->rcb_var.OptFlds = mvl_var_create(&dummyvar_objname, rpt_typeids->bvstring10, &rcb_info->rcb_data.OptFlds, NULL, SD_FALSE)) == NULL) return (SD_FAILURE); if ((rcb_info->rcb_var.SqNum = mvl_var_create(&dummyvar_objname, rpt_typeids->int16u, &rcb_info->rcb_data.SqNum, NULL, SD_FALSE)) == NULL) return (SD_FAILURE); if ((rcb_info->rcb_var.TimeOfEntry = mvl_var_create(&dummyvar_objname, rpt_typeids->btime6, &rcb_info->rcb_data.TimeOfEntry, NULL, SD_FALSE)) == NULL) return (SD_FAILURE); if ((rcb_info->rcb_var.DatSetNa = mvl_var_create(&dummyvar_objname, rpt_typeids->vstring65, &rcb_info->rcb_data.DatSetNa, NULL, SD_FALSE)) == NULL) return (SD_FAILURE); if ((rcb_info->rcb_var.BufOvfl = mvl_var_create(&dummyvar_objname, rpt_typeids->mmsbool, &rcb_info->rcb_data.BufOvfl, NULL, SD_FALSE)) == NULL) return (SD_FAILURE); if ((rcb_info->rcb_var.SubSeqNum = mvl_var_create(&dummyvar_objname, rpt_typeids->int16u, &rcb_info->rcb_data.SubSeqNum, NULL, SD_FALSE)) == NULL) return (SD_FAILURE); if ((rcb_info->rcb_var.MoreSegmentsFollow = mvl_var_create(&dummyvar_objname, rpt_typeids->mmsbool, &rcb_info->rcb_data.MoreSegmentsFollow, NULL, SD_FALSE)) == NULL) return (SD_FAILURE); if ((rcb_info->rcb_var.EntryID = mvl_var_create(&dummyvar_objname, rpt_typeids->ostring8, &rcb_info->rcb_data.EntryID, NULL, SD_FALSE)) == NULL) return (SD_FAILURE); if ((rcb_info->rcb_var.ConfRev = mvl_var_create(&dummyvar_objname, rpt_typeids->int32u, &rcb_info->rcb_data.ConfRev, NULL, SD_FALSE)) == NULL) return (SD_FAILURE); incSize = BSTR_NUMBITS_TO_NUMBYTES(rcb_info->numDsVar); /* Note: rcb_info->rcb_data.Inclusion is a "ptr" to data, so don't add "&". */ if ((rcb_info->rcb_var.Inclusion = mvl_var_create(&dummyvar_objname, rcb_info->InclusionTypeid, rcb_info->rcb_data.Inclusion, NULL, SD_FALSE)) == NULL) return (SD_FAILURE); /* Allocate array of DataRefName (vstring65) */ /* & array of (MVL_VAR_ASSOC *). */ /* Can't alloc array of strings, so we just allocate one big buffer */ /* and use [j*66] to find postion for each string in the buffer. */ /* Create separate variable for each array entry. */ for (j = 0; j < rcb_info->numDsVar; j++) { if ((rcb_info->rcb_var.dataRefName[j] = mvl_var_create(&dummyvar_objname, rpt_typeids->vstring65, &rcb_info->rcb_data.dataRefName[j * 66], NULL, SD_FALSE)) == NULL) return (SD_FAILURE); } /* Create variable for each DataSet variable. */ for (j = 0; j < rcb_info->numDsVar; j++) { ST_VOID* remote_data; /* buffer to store remote data */ MVL_TYPE_CTRL* type_ctrl; type_ctrl = mvl_type_ctrl_find(rcb_info->typeIdArr[j]); assert(type_ctrl); /* find should never fail */ /* Allocate buffer to store remote data. */ remote_data = chk_malloc(type_ctrl->data_size); if ((rcb_info->rcb_var.dataValue[j] = mvl_var_create(&dummyvar_objname, rcb_info->typeIdArr[j], /* Use type just created */ remote_data, /* buffer for data */ NULL, /* proc funs */ SD_FALSE)) /* DON'T copy name */ == NULL) { /* couldn't create this variable, so stop */ return (SD_FAILURE); } } /* Allocate array of Reason (bstr6)(one byte for each Reason) */ /* & array of (MVL_VAR_ASSOC *). */ /* Create separate variable for each array entry. */ for (j = 0; j < rcb_info->numDsVar; j++) { /* Use bvstring8 because IEC sends bstr6 and UCA sends bstr8. */ if ((rcb_info->rcb_var.Reason[j] = mvl_var_create(&dummyvar_objname, rpt_typeids->bvstring8, &rcb_info->rcb_data.Reason[j], NULL, SD_FALSE)) == NULL) return (SD_FAILURE); } /* If we get this far, everything was successful. */ return (SD_SUCCESS); } /************************************************************************/ /* rcb_info_var_destroy */ /* Destroy everything created in "rcb_info_var_create". */ /* Check that each was successfully creating before destroying. Any one */ /* of the "mvl_var_create" calls in "rcb_info_var_create" may have failed.*/ /************************************************************************/ static ST_VOID rcb_info_var_destroy(RCB_INFO* rcb_info) { ST_INT j; if (rcb_info->rcb_var.RptID) mvl_var_destroy(rcb_info->rcb_var.RptID); if (rcb_info->rcb_var.OptFlds) mvl_var_destroy(rcb_info->rcb_var.OptFlds); if (rcb_info->rcb_var.SqNum) mvl_var_destroy(rcb_info->rcb_var.SqNum); if (rcb_info->rcb_var.TimeOfEntry) mvl_var_destroy(rcb_info->rcb_var.TimeOfEntry); if (rcb_info->rcb_var.DatSetNa) mvl_var_destroy(rcb_info->rcb_var.DatSetNa); if (rcb_info->rcb_var.BufOvfl) mvl_var_destroy(rcb_info->rcb_var.BufOvfl); if (rcb_info->rcb_var.SubSeqNum) mvl_var_destroy(rcb_info->rcb_var.SubSeqNum); if (rcb_info->rcb_var.MoreSegmentsFollow) mvl_var_destroy(rcb_info->rcb_var.MoreSegmentsFollow); if (rcb_info->rcb_var.EntryID) mvl_var_destroy(rcb_info->rcb_var.EntryID); if (rcb_info->rcb_var.ConfRev) mvl_var_destroy(rcb_info->rcb_var.ConfRev); if (rcb_info->rcb_var.Inclusion) mvl_var_destroy(rcb_info->rcb_var.Inclusion); /* Destroy "dataRefName" variables. */ for (j = 0; j < rcb_info->numDsVar; j++) { if (rcb_info->rcb_var.dataRefName[j]) mvl_var_destroy(rcb_info->rcb_var.dataRefName[j]); } /* Destroy "dataValue" variables. */ for (j = 0; j < rcb_info->numDsVar; j++) { if (rcb_info->rcb_var.dataValue[j] != NULL) { chk_free(rcb_info->rcb_var.dataValue[j]->data); mvl_var_destroy(rcb_info->rcb_var.dataValue[j]); } } /* Destroy "Reason" variables. */ for (j = 0; j < rcb_info->numDsVar; j++) { if (rcb_info->rcb_var.Reason[j]) mvl_var_destroy(rcb_info->rcb_var.Reason[j]); } } /************************************************************************/ /* This sample function sets some options and enables the RCB. */ /* If any write fails, stop. */ /* If more options needed, add more arguments to this function. */ /************************************************************************/ ST_RET rcb_enable(MVL_NET_INFO* netInfo, ST_CHAR* domName, ST_CHAR* rcbName, ST_UCHAR* OptFlds, ST_UCHAR* TrgOps, ST_UINT32 IntgPd, RPT_TYPEIDS* rpt_typeids, ST_INT timeOut) { ST_BOOLEAN RptEna = 1; /* 1 = enable the report */ ST_RET ret = SD_SUCCESS; ST_CHAR varName[MAX_IDENT_LEN + 1]; //if (ret == SD_SUCCESS) //{ // apr_snprintf (varName,sizeof(varName),"%s$IntgPd", rcbName); // ret = mms_named_var_write (netInfo, varName, DOM_SPEC, domName, rpt_typeids->int32u, (ST_CHAR *) &IntgPd, timeOut); //} if (ret == SD_SUCCESS) { /* NOTE: only write 9 bits. 10th bit (segmentation) is read-only. */ apr_snprintf(varName, sizeof(varName), "%s$OptFlds", rcbName); ret = mms_named_var_write(netInfo, varName, DOM_SPEC, domName, rpt_typeids->bstr9, OptFlds, timeOut); } if (ret == SD_SUCCESS) { apr_snprintf(varName, sizeof(varName), "%s$TrgOps", rcbName); ret = mms_named_var_write(netInfo, varName, DOM_SPEC, domName, rpt_typeids->bstr6, TrgOps, timeOut); if (ret != SD_SUCCESS) { printf("%s Write Error!!!", varName); echo_warn1("Report注册 %s Write Error!!!", varName); } } #if 0 /* Add something like this if other options needed. ???????? BufTm 等??*/ if (ret == SD_SUCCESS) { apr_snprintf(varName, sizeof(varName), "%s$Trgs", rcbName); ret = mms_named_var_write(netInfo, varName, DOM_SPEC, domName, rpt_typeids->int16u, (ST_CHAR*)&Trgs, timeOut); } #endif if (ret == SD_SUCCESS) { apr_snprintf(varName, sizeof(varName), "%s$RptEna", rcbName); ret = mms_named_var_write(netInfo, varName, DOM_SPEC, domName, rpt_typeids->mmsbool, (ST_CHAR*)&RptEna, timeOut); } return (ret); } ST_RET rcb_disable(MVL_NET_INFO* netInfo, ST_CHAR* domName, ST_CHAR* rcbName, RPT_TYPEIDS* rpt_typeids, ST_INT timeOut) { ST_BOOLEAN RptEna = 0; /* 0 = disable the report */ ST_UINT32 IntgPd = 0; ST_RET ret = SD_SUCCESS; ST_CHAR varName[MAX_IDENT_LEN + 1]; if (ret == SD_SUCCESS) { apr_snprintf(varName, sizeof(varName), "%s$RptEna", rcbName); ret = mms_named_var_write(netInfo, varName, DOM_SPEC, domName, rpt_typeids->mmsbool, (ST_CHAR*)&RptEna, timeOut); } if (ret == SD_SUCCESS) { apr_snprintf(varName, sizeof(varName), "%s$IntgPd", rcbName); ret = mms_named_var_write(netInfo, varName, DOM_SPEC, domName, rpt_typeids->int32u, (ST_CHAR*)&IntgPd, timeOut); } return (ret); } /************************************************************************/ /************************************************************************/ static ST_VOID log_var_data(MVL_VAR_ASSOC* var, MMS_DECODE_DATA* data) { ST_CHAR tdl_buf[500]; /* increase size if complex TDL expected*/ MVL_TYPE_CTRL* type_ctrl; type_ctrl = mvl_type_ctrl_find(var->type_id); if (type_ctrl) { /* If the TDL produced is longer than max_tdl_len, this function */ /* "gracefully" fails (i.e. returns 0). */ if (ms_runtime_to_tdl(type_ctrl->rt, type_ctrl->num_rt, tdl_buf, sizeof(tdl_buf)) > 0) ;//SLOGCALWAYS1 (" TYPE: %s", tdl_buf); else echo_warn(" TYPE: unknown"); //printf ("\nTYPE: %s \n", tdl_buf); //printf("type_ctrl->num_rt %d %x %x \n", type_ctrl->num_rt , &data, &(var->data)); my_local_to_data((ST_CHAR*)var->data, type_ctrl->rt, type_ctrl->num_rt, data); if (data->item_num == 0) { echo_warn("!!!!!!!!!!!!!!!!!!!data num is 0 !!!!!!!!!!!!!!!!\n"); } } else echo_warn(" ERR: type_id is invalid"); } /************************************************************************/ /* u_iec_rpt_ind_data */ /* User function to process the received report data. This example */ /* function simply writes the data to the log file. */ /* */ /* It should be easy to modify or rewrite this function to do whatever */ /* is appropriate for your application. */ /************************************************************************/ ST_VOID u_iec_rpt_ind_data_by_devtype(MVL_VAR_ASSOC** info_va, ST_UINT8* OptFldsData, /* ptr to data part of OptFlds bvstring */ ST_UINT8* InclusionData, /* ptr to Inclusion bstring */ RCB_INFO* rcb_info, ST_INT va_total, MVL_NET_INFO* net_info) { ST_INT va_num = 0; ST_INT j; MMS_DECODE_DATA mms_dec_data; //uint32_t add_mms_dec_data = &mms_dec_data; ied_t* ied; rptinfo_t* rptinfo; // element_t* pDataOMSObject; LD_info_t* LD_info; chnl_usr_t* chnl_usr; char** DataObjectFullName; // LD_info_t* LD_info_of_Data; ST_INT not_set_rpt_TimeID_this; ST_INT not_set_rpt_q_this; //printf("Var# %02d: RptId", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); rptinfo = find_rptinfo_from_net_rpt_info_name(net_info, rcb_info); //rptinfo->m_LastDataTime = sGetMsTime();//WW 2023-08-29 去除 LD_info = rptinfo->LD_info; chnl_usr = net_info->user_ext; ied = chnl_usr->chnl->ied; not_set_rpt_TimeID_this = TRUE; not_set_rpt_q_this = TRUE; //g_db_inf_clear_data(RPT_IDX); rptinfo->count++; printf("[BEGIND Process] Received Report From %s:%d %s %s ,va_total = %i ,【count = %i】 \n", chnl_usr->ip_str, chnl_usr->chnl->port, LD_info->LD_name, rcb_info->RptID, va_total, rptinfo->count); //apr_time_t previousTime = apr_time_now();// //apr_time_exp_t localTime; //apr_time_exp_gmt(&localTime, previousTime); //printf("\n ------>>>>>>> begind time %d %d:%d:%d.%d \n", // localTime.tm_mday, localTime.tm_hour, localTime.tm_min, localTime.tm_sec, localTime.tm_usec); va_num++; // SLOGCALWAYS1("Var# %02d: OptFlds", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; /* NOTE: Don't change initial entries in "info_va". Add these right after "OptFlds".*/ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SQNUM)) { // SLOGCALWAYS1("Var# %02d: SqNum", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); printf("\n ------>>>>>>> SqNum received in Report From %s %s %s ,SqNum = %d \n", chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID, mms_dec_data.data_item[0].u.data_uint); va_num++; } if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_TIMESTAMP)) { // SLOGCALWAYS1("Var# %02d: TimeOfEntry", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; //set_rpt_TimeID(convert_btime6_to_apr_time(&(mms_dec_data.data_item[0].u.data_bTime6)) ); } if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATSETNAME)) { // SLOGCALWAYS1("Var# %02d: DatSetNa", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; } if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_BUFOVFL)) { // SLOGCALWAYS1("Var# %02d: BufOvfl", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; } if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_ENTRYID)) { char* EntryIDStr; int i; log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); EntryIDStr = mms_dec_data.data_item[0].u.data_str; printf("\n ------>>>>>>> EntryID received in Report From %s %s %s ,EntryID = %s\n\n\n", chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID, EntryIDStr); for (i = 0; i < 8; i++) { EntryIDStr[2] = '\0'; rptinfo->m_EntryID[i] = (byte_t)strtol(EntryIDStr, NULL, 16); EntryIDStr += 3; //skip a blank } va_num++; } printf("\n -------------rptinfo->m_EntryID %02x %02x %02x %02x %02x %02x %02x %02x -------- EntryID\n\n\n", *rptinfo->m_EntryID, *(rptinfo->m_EntryID + 1), *(rptinfo->m_EntryID + 2), *(rptinfo->m_EntryID + 3), *(rptinfo->m_EntryID + 4), *(rptinfo->m_EntryID + 5), *(rptinfo->m_EntryID + 6), *(rptinfo->m_EntryID + 7)); if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_CONFREV)) { // SLOGCALWAYS1("Var# %02d: ConfRev", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; } //printf("\n ----1--va_num %d -\n", va_num); if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SUBSEQNUM)) { // SLOGCALWAYS1("Var# %02d: SubSeqNum", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; // SLOGCALWAYS1("Var# %02d: MoreSegmentsFollow", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; } //printf("\n ----2---va_num %d \n", va_num); // SLOGCALWAYS1("Var# %02d: Inclusion", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; /* If data-Ref enabled, check "Inclusion" to figure out what is being received.*/ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATAREF)) { for (j = 0; j < rcb_info->numDsVar; ++j) { if (BSTR_BIT_GET(InclusionData, j)) { // SLOGCALWAYS2("Var# %02d: DataRefName# %d", va_num, j); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; } } } //printf("\n ----3---%d \n", va_num); //rcb_info->numDsVar+1 just to avoid rcb_info->numDsVar==0 ,waste a little memory DataObjectFullName = apr_pcalloc(g_pt61850app->tmp_pool, (rcb_info->numDsVar + 1) * sizeof(char*)); //RWCStringVec DataName(rcb_info->numDsVar+1); //RWCStringVec AttrName(rcb_info->numDsVar+1); //RWTValVector pDataOMSObjects(rcb_info->numDsVar+1); //printf("\n ----4--%d rcb_info->numDsVar %d -\n", va_num, rcb_info->numDsVar); for (j = 0; j < rcb_info->numDsVar; ++j) { if (BSTR_BIT_GET(InclusionData, j)) { DataObjectFullName[j] = apr_pstrdup(g_pt61850app->tmp_pool, rcb_info->varNameArray[j]->obj_name.vmd_spec); } } //printf("\n ----5--%d-\n", va_num); // if (g_pt61850app->IsCallEvtDes ) // cout<<"pEquipment->m_OMSObject_FULL_FCDA_Map.entries() = "<m_OMSObject_FULL_FCDA_Map.entries()<line_id > 0) { if (strstr(rcb_info->RptID, "QVVR"))//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR processQVVR_start(LD_info); else if (strstr(rcb_info->RptID, "RDRE"))//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbRDRE processRDRE_start(LD_info); else { ied_t* ied; ied = find_ied_from_dev_code(LD_info->terminal_code); ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext; if (rptinfo->flickerflag==1)//CZY 2023-08-17 WW 2022-11-14 只有闪变和第一次进入才会初始化 json_block_create_start(LD_info->line_id); json_block_create_start( LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); else if(rptinfo->flickerflag == 0) { if (LD_info->rptRecvCheckFlag == 0) json_block_create_start( LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); LD_info->rptRecvCheckFlag |= 0x01 << rptinfo->rptNo; } else if (rptinfo->flickerflag == 2) { if (LD_info->rptPstRecvCheckFlag == 0) json_block_create_start(LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); LD_info->rptPstRecvCheckFlag |= 0x01 << rptinfo->rptNo; } } } /* HERE'S THE DATA. Check "Inclusion" to figure out what is being received.*/ for (j = 0; j < rcb_info->numDsVar; ++j) { /*if (rcb_info->numDsVar==13) { printf("bbbbbbbbbbbbbbbbbbbbbbbbb\n"); }*/ if (BSTR_BIT_GET(InclusionData, j)) { int ii; // SLOGCALWAYS3("Var# %02d: DataSet Var# %d: Name=%s", va_num, j, // rcb_info->varNameArray[j]->obj_name.vmd_spec); //printf("\n ----5.0--%d-\n", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; //printf("\n ----5.1--%d-%d\n", va_num,mms_dec_data.item_num); // if ( !pDataOMSObjects[j] ) continue; //cout<tmp_pool, DataObjectFullName[j]); else FULL_FCDA_Name = apr_pstrcat(g_pt61850app->tmp_pool, DataObjectFullName[j], "$", mms_dec_data.data_item[ii].comp_name, NULL); // cout<<" FULL_FCDA_Name "<< FULL_FCDA_Name <RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR //need do nothing! not_set_rpt_q_this = FALSE; } else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14修改判断 LLN0$BR$brcbRDRE //need do nothing! not_set_rpt_q_this = FALSE; } else { json_block_create_flag(LD_info->mp_id, flag, rptinfo->flickerflag); not_set_rpt_q_this = FALSE; } } } else if (('$' == FULL_FCDA_Name[length_FCDA - 2]) && ('t' == FULL_FCDA_Name[length_FCDA - 1])) { if (not_set_rpt_TimeID_this) { apr_time_t t = convert_btime6_to_apr_time(&(mms_dec_data.data_item[ii].u.data_bTime6)); if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR if (strstr(FULL_FCDA_Name, "VarStr$t")) { processQVVR_time(LD_info, t / 1000); not_set_rpt_TimeID_this = FALSE; } } else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14修改判断 LLN0$BR$brcbRDRE //need do nothing! not_set_rpt_TimeID_this = FALSE; } else { json_block_create_time(LD_info->mp_id, t / 1000, rptinfo->flickerflag); printf("rcb_info->RptID=%s ,LineId=%d , Timestamp= %lld \n", rcb_info->RptID, LD_info->line_id, t / 1000); not_set_rpt_TimeID_this = FALSE; if (strstr(rcb_info->RptID, "LLN0$RP$urcbRealData")) { //20241223lnk添加终端号参数 ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); if (urcbRealDataHasReceived(ied_usr->dev_idx,LD_info, t / 1000)) return; } } } } else { double v = 0.0; if (mms_dec_data.data_item[ii].type == DATA_INT_TYPE) v = mms_dec_data.data_item[ii].u.data_int; else if (mms_dec_data.data_item[ii].type == DATA_UINT_TYPE) v = mms_dec_data.data_item[ii].u.data_uint; else if (mms_dec_data.data_item[ii].type == DATA_INT64_TYPE) v = (double)mms_dec_data.data_item[ii].u.data_int64; else if (mms_dec_data.data_item[ii].type == DATA_UINT64_TYPE) v = (double)mms_dec_data.data_item[ii].u.data_uint64; else if (mms_dec_data.data_item[ii].type == DATA_DOUBLE_TYPE) v = mms_dec_data.data_item[ii].u.data_double; else if (mms_dec_data.data_item[ii].type == DATA_STR_TYPE) v = strtol(mms_dec_data.data_item[ii].u.data_str, NULL, 2); //set_db_value(RPT_IDX,FULL_FCDA_Name,v, is_rpt_Time_exact_hour() ); if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR processQVVR_data(LD_info, FULL_FCDA_Name, v); } else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbRDRE processRDRE_data(LD_info, FULL_FCDA_Name, v); } else json_block_create_data(LD_info->mp_id, FULL_FCDA_Name, v, rptinfo->flickerflag); }//else } } } if (LD_info->line_id > 0) { //set_rpt_LineID(LD_info->line_id); //set_line_info(RPT_IDX,LD_info->line_id,LD_info->SubV_Index,LD_info->Dev_Index,LD_info->Sub_Index,LD_info->GD_Index); //write_updatetime_to_db(chnl_usr->chnl->addr); if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR processQVVR_end(LD_info); } else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbRDRE processRDRE_end(LD_info); } else { printf("%d : %d", LD_info->rptRecvFlag, LD_info->rptRecvCheckFlag); //append_db_records(RPT_IDX); if (rptinfo->flickerflag==1)//CZY 2023-08-17 WW 2022-11-14 增加闪变标志 { //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持 //int devkind = ied_usr->dev_flag; json_block_create_end(LD_info->mp_id, rptinfo->flickerflag); } else if(rptinfo->flickerflag == 0){//CZY 2023-08-17 WW 2022-11-14 增加多个报告判断 if (LD_info->rptRecvFlag == LD_info->rptRecvCheckFlag) { //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持 //int devkind = ied_usr->dev_flag; json_block_create_end(LD_info->mp_id, rptinfo->flickerflag); LD_info->rptRecvCheckFlag = 0; } } else if (rptinfo->flickerflag == 2) {//CZY 2023-08-17 WW 2022-11-14 增加多个报告判断 if (LD_info->rptPstRecvFlag == LD_info->rptPstRecvCheckFlag) { //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持 //int devkind = ied_usr->dev_flag; json_block_create_end(LD_info->mp_id, rptinfo->flickerflag); LD_info->rptPstRecvCheckFlag = 0; } } } } else { echo_err3("Ignore this report due to line_id invalid , Report From %s %s %s !!!", APR_EGENERAL, chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID); } printf("[END Process] Report From %s:%d %s %s ,va_total = %i ,【count = %i】 \n", chnl_usr->ip_str, chnl_usr->chnl->port, LD_info->LD_name, rcb_info->RptID, va_total, rptinfo->count); //apr_time_t previousTimeend = apr_time_now();// //apr_time_exp_t localTimeend; //apr_time_exp_gmt(&localTimeend, previousTimeend); //printf("\n ------>>>>>>> end time %d %d:%d:%d.%d \n", // localTimeend.tm_mday, localTimeend.tm_hour, localTimeend.tm_min, localTimeend.tm_sec, localTimeend.tm_usec); //printf("\n ----6-%d--\n", va_num); /* If "reason" enabled, check "Inclusion" to figure out what is being received.*/ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_REASON)) { for (j = 0; j < rcb_info->numDsVar; ++j) { if (BSTR_BIT_GET(InclusionData, j)) { // SLOGCALWAYS2("Var# %02d: Reason# %d", va_num, j); //log_var_data (info_va[va_num],&mms_dec_data); va_num++; } } } //设置响应时间,避免频繁召唤装置名称,导致丢包 add on Aug 3 for testing of guangdong CRITICAL chnl_usr->m_LastPosRespTime = sGetMsTime(); //assert (va_num==va_total); /* Did we count right? */ if (va_num != va_total) echo_err5("va_num!=va_total! Report From %s %s %s , %d!=%d !!!", APR_EGENERAL, chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID, va_num, va_total); } ST_VOID u_iec_rpt_ind_data(MVL_VAR_ASSOC** info_va, ST_UINT8* OptFldsData, /* ptr to data part of OptFlds bvstring */ ST_UINT8* InclusionData, /* ptr to Inclusion bstring */ RCB_INFO* rcb_info, ST_INT va_total, MVL_NET_INFO* net_info) { ST_INT va_num = 0; ST_INT j; MMS_DECODE_DATA mms_dec_data; //uint32_t add_mms_dec_data = &mms_dec_data; ied_t* ied; rptinfo_t* rptinfo; // element_t* pDataOMSObject; LD_info_t* LD_info; chnl_usr_t* chnl_usr; char** DataObjectFullName; // LD_info_t* LD_info_of_Data; ST_INT not_set_rpt_TimeID_this; ST_INT not_set_rpt_q_this; //printf("Var# %02d: RptId", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); rptinfo = find_rptinfo_from_net_rcb_info(net_info, rcb_info); //rptinfo->m_LastDataTime = sGetMsTime();//WW 2023-08-29 去除 LD_info = rptinfo->LD_info; chnl_usr = net_info->user_ext; ied = chnl_usr->chnl->ied; not_set_rpt_TimeID_this = TRUE; not_set_rpt_q_this = TRUE; //g_db_inf_clear_data(RPT_IDX); rptinfo->count++; printf("[BEGIND Process] Received Report From %s:%d %s %s ,va_total = %i ,【count = %i】 mp_id=%s\n", chnl_usr->ip_str, chnl_usr->chnl->port, LD_info->LD_name, rcb_info->RptID, va_total, rptinfo->count, LD_info->mp_id); //apr_time_t previousTime = apr_time_now();// //apr_time_exp_t localTime; //apr_time_exp_gmt(&localTime, previousTime); //printf("\n ------>>>>>>> begind time %d %d:%d:%d.%d \n", // localTime.tm_mday, localTime.tm_hour, localTime.tm_min, localTime.tm_sec, localTime.tm_usec); va_num++; // SLOGCALWAYS1("Var# %02d: OptFlds", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; /* NOTE: Don't change initial entries in "info_va". Add these right after "OptFlds".*/ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SQNUM)) { // SLOGCALWAYS1("Var# %02d: SqNum", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); printf("\n ------>>>>>>> SqNum received in Report From %s %s %s ,SqNum = %d \n", chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID, mms_dec_data.data_item[0].u.data_uint); va_num++; } if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_TIMESTAMP)) { // SLOGCALWAYS1("Var# %02d: TimeOfEntry", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; //set_rpt_TimeID(convert_btime6_to_apr_time(&(mms_dec_data.data_item[0].u.data_bTime6)) ); } if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATSETNAME)) { // SLOGCALWAYS1("Var# %02d: DatSetNa", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; } if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_BUFOVFL)) { // SLOGCALWAYS1("Var# %02d: BufOvfl", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; } if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_ENTRYID)) { char* EntryIDStr; int i; log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); EntryIDStr = mms_dec_data.data_item[0].u.data_str; printf("\n ------>>>>>>> EntryID received in Report From %s %s %s ,EntryID = %s\n\n\n", chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID, EntryIDStr); for (i = 0; i < 8; i++) { EntryIDStr[2] = '\0'; rptinfo->m_EntryID[i] = (byte_t)strtol(EntryIDStr, NULL, 16); EntryIDStr += 3; //skip a blank } va_num++; } printf("\n -------------rptinfo->m_EntryID %02x %02x %02x %02x %02x %02x %02x %02x -------- EntryID\n\n\n", *rptinfo->m_EntryID, *(rptinfo->m_EntryID + 1), *(rptinfo->m_EntryID + 2), *(rptinfo->m_EntryID + 3), *(rptinfo->m_EntryID + 4), *(rptinfo->m_EntryID + 5), *(rptinfo->m_EntryID + 6), *(rptinfo->m_EntryID + 7)); if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_CONFREV)) { // SLOGCALWAYS1("Var# %02d: ConfRev", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; } //printf("\n ----1--va_num %d -\n", va_num); if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SUBSEQNUM)) { // SLOGCALWAYS1("Var# %02d: SubSeqNum", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; // SLOGCALWAYS1("Var# %02d: MoreSegmentsFollow", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; } //printf("\n ----2---va_num %d \n", va_num); // SLOGCALWAYS1("Var# %02d: Inclusion", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; /* If data-Ref enabled, check "Inclusion" to figure out what is being received.*/ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATAREF)) { for (j = 0; j < rcb_info->numDsVar; ++j) { if (BSTR_BIT_GET(InclusionData, j)) { // SLOGCALWAYS2("Var# %02d: DataRefName# %d", va_num, j); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; } } } //printf("\n ----3---%d \n", va_num); //rcb_info->numDsVar+1 just to avoid rcb_info->numDsVar==0 ,waste a little memory DataObjectFullName = apr_pcalloc(g_pt61850app->tmp_pool, (rcb_info->numDsVar + 1) * sizeof(char*)); //RWCStringVec DataName(rcb_info->numDsVar+1); //RWCStringVec AttrName(rcb_info->numDsVar+1); //RWTValVector pDataOMSObjects(rcb_info->numDsVar+1); //printf("\n ----4--%d rcb_info->numDsVar %d -\n", va_num, rcb_info->numDsVar); for (j = 0; j < rcb_info->numDsVar; ++j) { if (BSTR_BIT_GET(InclusionData, j)) { DataObjectFullName[j] = apr_pstrdup(g_pt61850app->tmp_pool, rcb_info->varNameArray[j]->obj_name.vmd_spec); } } //printf("\n ----5--%d-\n", va_num); // if (g_pt61850app->IsCallEvtDes ) // cout<<"pEquipment->m_OMSObject_FULL_FCDA_Map.entries() = "<m_OMSObject_FULL_FCDA_Map.entries()<line_id > 0) { if (strstr(rcb_info->RptID, "QVVR"))//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR processQVVR_start(LD_info);//上送的报告里面的监测点号 else if (strstr(rcb_info->RptID, "RDRE"))//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbRDRE processRDRE_start(LD_info); else { ied_t* ied; ied = find_ied_from_dev_code(LD_info->terminal_code); ied_usr_t* ied_usr = (ied_usr_t*)ied->usr_ext; if (rptinfo->flickerflag == 1)//CZY 2023-08-17 WW 2022-11-14 只有闪变和第一次进入才会初始化 json_block_create_start(LD_info->line_id); json_block_create_start(LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); else if (rptinfo->flickerflag == 0) { if (LD_info->rptRecvCheckFlag == 0) json_block_create_start(LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); LD_info->rptRecvCheckFlag |= 0x01 << rptinfo->rptNo; } else if (rptinfo->flickerflag == 2) { if (LD_info->rptPstRecvCheckFlag == 0) json_block_create_start(LD_info->voltage_level, LD_info->mp_id, rptinfo->flickerflag, ied_usr->dev_type, LD_info->line_id); LD_info->rptPstRecvCheckFlag |= 0x01 << rptinfo->rptNo; } } } /* HERE'S THE DATA. Check "Inclusion" to figure out what is being received.*/ for (j = 0; j < rcb_info->numDsVar; ++j) { /*if (rcb_info->numDsVar==13) { printf("bbbbbbbbbbbbbbbbbbbbbbbbb\n"); }*/ if (BSTR_BIT_GET(InclusionData, j)) { int ii; // SLOGCALWAYS3("Var# %02d: DataSet Var# %d: Name=%s", va_num, j, // rcb_info->varNameArray[j]->obj_name.vmd_spec); //printf("\n ----5.0--%d-\n", va_num); log_var_data(info_va[va_num], &mms_dec_data); //assert(add_mms_dec_data== (uint32_t)&mms_dec_data); va_num++; //printf("\n ----5.1--%d-%d\n", va_num,mms_dec_data.item_num); // if ( !pDataOMSObjects[j] ) continue; //cout<tmp_pool, DataObjectFullName[j]); else FULL_FCDA_Name = apr_pstrcat(g_pt61850app->tmp_pool, DataObjectFullName[j], "$", mms_dec_data.data_item[ii].comp_name, NULL); length_FCDA = strlen(FULL_FCDA_Name); if (('$' == FULL_FCDA_Name[length_FCDA - 2]) && ('t' == FULL_FCDA_Name[length_FCDA - 1])) { apr_time_t t = convert_btime6_to_apr_time(&(mms_dec_data.data_item[ii].u.data_bTime6)); time = t / 1000; break; } } for (ii = 0; ii < mms_dec_data.item_num; ++ii)//遍历FCDA { char* FULL_FCDA_Name; int length_FCDA; //printf("\n ----5.11--%d-%s\n", va_num, mms_dec_data.data_item[ii].comp_name); if (strcmp(mms_dec_data.data_item[ii].comp_name, "") == 0) FULL_FCDA_Name = apr_pstrdup(g_pt61850app->tmp_pool, DataObjectFullName[j]); else FULL_FCDA_Name = apr_pstrcat(g_pt61850app->tmp_pool, DataObjectFullName[j], "$", mms_dec_data.data_item[ii].comp_name, NULL); // cout<<" FULL_FCDA_Name "<< FULL_FCDA_Name <RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR //need do nothing! not_set_rpt_q_this = FALSE; } else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14修改判断 LLN0$BR$brcbRDRE //need do nothing! not_set_rpt_q_this = FALSE; } else if (strstr(FULL_FCDA_Name, "GGIO")) { not_set_rpt_q_this = FALSE; } else { json_block_create_flag(LD_info->mp_id, flag, rptinfo->flickerflag); not_set_rpt_q_this = FALSE; } } } else if (('$' == FULL_FCDA_Name[length_FCDA - 2]) && ('t' == FULL_FCDA_Name[length_FCDA - 1])) { if (not_set_rpt_TimeID_this) { apr_time_t t = convert_btime6_to_apr_time(&(mms_dec_data.data_item[ii].u.data_bTime6)); if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR if (strstr(FULL_FCDA_Name, "VarStr$t")) { processQVVR_time(LD_info, t / 1000); not_set_rpt_TimeID_this = FALSE; } } else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14修改判断 LLN0$BR$brcbRDRE //need do nothing! not_set_rpt_TimeID_this = FALSE; } else if (strstr(FULL_FCDA_Name, "GGIO")) {//CZY 2023-08-17 WW 2022-11-14修改判断 LLN0$BR$brcbRDRE //need do nothing! not_set_rpt_TimeID_this = FALSE; } else { json_block_create_time(LD_info->mp_id, t / 1000, rptinfo->flickerflag); printf("rcb_info->RptID=%s ,LineId=%d , Timestamp= %lld \n", rcb_info->RptID, LD_info->line_id, t / 1000); not_set_rpt_TimeID_this = FALSE; if (strstr(rcb_info->RptID, "LLN0$RP$urcbRealData")) { //20241223lnk添加终端号参数 ied_usr_t *ied_usr = GET_IEDEXT_ADDR(ied); if (urcbRealDataHasReceived(ied_usr->dev_idx,LD_info, t / 1000))//判断时间重复 return; } } } } else { double v = 0.0; if (mms_dec_data.data_item[ii].type == DATA_INT_TYPE) v = mms_dec_data.data_item[ii].u.data_int; else if (mms_dec_data.data_item[ii].type == DATA_UINT_TYPE) v = mms_dec_data.data_item[ii].u.data_uint; else if (mms_dec_data.data_item[ii].type == DATA_INT64_TYPE) v = (double)mms_dec_data.data_item[ii].u.data_int64; else if (mms_dec_data.data_item[ii].type == DATA_UINT64_TYPE) v = (double)mms_dec_data.data_item[ii].u.data_uint64; else if (mms_dec_data.data_item[ii].type == DATA_DOUBLE_TYPE) v = mms_dec_data.data_item[ii].u.data_double; else if (mms_dec_data.data_item[ii].type == DATA_STR_TYPE) v = strtol(mms_dec_data.data_item[ii].u.data_str, NULL, 2); //set_db_value(RPT_IDX,FULL_FCDA_Name,v, is_rpt_Time_exact_hour() ); if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR processQVVR_data(LD_info, FULL_FCDA_Name, v); } else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbRDRE processRDRE_data(LD_info, FULL_FCDA_Name, v); } else if (strstr(FULL_FCDA_Name, "GGIO")) { ied_t* ied = LD_info->ied; ied_usr_t* ied_usr = GET_IEDEXT_ADDR(ied); processGGIO_start_data_end(LD_info->mp_id, FULL_FCDA_Name, v, time, ied_usr->dev_type, LD_info->line_id);//GGIO数据全套处理流程 } else json_block_create_data(LD_info->mp_id, FULL_FCDA_Name, v, rptinfo->flickerflag); }//else } } } if (LD_info->line_id > 0) { //set_rpt_LineID(LD_info->line_id); //set_line_info(RPT_IDX,LD_info->line_id,LD_info->SubV_Index,LD_info->Dev_Index,LD_info->Sub_Index,LD_info->GD_Index); //write_updatetime_to_db(chnl_usr->chnl->addr); if (strstr(rcb_info->RptID, "QVVR")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbQVVR processQVVR_end(LD_info); } else if (strstr(rcb_info->RptID, "RDRE")) {//CZY 2023-08-17 WW 2022-11-14 修改判断LLN0$BR$brcbRDRE processRDRE_end(LD_info); } else { printf("%d : %d", LD_info->rptRecvFlag, LD_info->rptRecvCheckFlag); //append_db_records(RPT_IDX); if (rptinfo->flickerflag == 1)//CZY 2023-08-17 WW 2022-11-14 增加闪变标志 { //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持 //int devkind = ied_usr->dev_flag; json_block_create_end(LD_info->mp_id, rptinfo->flickerflag); } else if (rptinfo->flickerflag == 0) {//CZY 2023-08-17 WW 2022-11-14 增加多个报告判断 if (LD_info->rptRecvFlag == LD_info->rptRecvCheckFlag) { //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持 //int devkind = ied_usr->dev_flag; json_block_create_end(LD_info->mp_id, rptinfo->flickerflag); LD_info->rptRecvCheckFlag = 0; } } else if (rptinfo->flickerflag == 2) {//CZY 2023-08-17 WW 2022-11-14 增加多个报告判断 if (LD_info->rptPstRecvFlag == LD_info->rptPstRecvCheckFlag) { //ied_usr_t* ied_usr = ied->usr_ext;//CZY 2023-08-17 WW 2022年12月6日14:09:08 增加多个ICD支持 //int devkind = ied_usr->dev_flag; json_block_create_end(LD_info->mp_id, rptinfo->flickerflag); LD_info->rptPstRecvCheckFlag = 0; } } } } else { echo_err3("Ignore this report due to line_id invalid , Report From %s %s %s !!!", APR_EGENERAL, chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID); } printf("[END Process] Report From %s:%d %s %s ,va_total = %i ,【count = %i】 \n", chnl_usr->ip_str, chnl_usr->chnl->port, LD_info->LD_name, rcb_info->RptID, va_total, rptinfo->count); //apr_time_t previousTimeend = apr_time_now();// //apr_time_exp_t localTimeend; //apr_time_exp_gmt(&localTimeend, previousTimeend); //printf("\n ------>>>>>>> end time %d %d:%d:%d.%d \n", // localTimeend.tm_mday, localTimeend.tm_hour, localTimeend.tm_min, localTimeend.tm_sec, localTimeend.tm_usec); //printf("\n ----6-%d--\n", va_num); /* If "reason" enabled, check "Inclusion" to figure out what is being received.*/ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_REASON)) { for (j = 0; j < rcb_info->numDsVar; ++j) { if (BSTR_BIT_GET(InclusionData, j)) { // SLOGCALWAYS2("Var# %02d: Reason# %d", va_num, j); //log_var_data (info_va[va_num],&mms_dec_data); va_num++; } } } //设置响应时间,避免频繁召唤装置名称,导致丢包 add on Aug 3 for testing of guangdong CRITICAL chnl_usr->m_LastPosRespTime = sGetMsTime(); //assert (va_num==va_total); /* Did we count right? */ if (va_num != va_total) echo_err5("va_num!=va_total! Report From %s %s %s , %d!=%d !!!", APR_EGENERAL, chnl_usr->ip_str, LD_info->LD_name, rcb_info->RptID, va_num, va_total); } /************************************************************************/ /* object_name_clone_create */ /* Create clone of OBJECT_NAME struct. Can't just copy struct because */ /* struct contains pointers to strings. */ /* The function "object_name_clone_destroy" should be called to destroy */ /* the clone. */ /************************************************************************/ OBJECT_NAME* object_name_clone_create(OBJECT_NAME* srcobj) { OBJECT_NAME* dstobj; size_t extended_size; ST_CHAR* extended_ptr; /* Allocate OBJECT_NAME structure plus extra room for additional data. * This effectively combines 3 allocations into one. * Set pointers in OBJECT_NAME structure to point into the extra space. */ extended_size = sizeof(OBJECT_NAME) + MAX_IDENT_LEN + 1 /* dstobj->obj_name.vmd_spec */ + MAX_IDENT_LEN + 1; /* dstobj->domain_id */ dstobj = (OBJECT_NAME*)chk_malloc(extended_size); /* Copy old struct to new struct (before setting ptrs in new struct). */ memcpy(dstobj, srcobj, sizeof(OBJECT_NAME)); /* Fix ptrs to strings in new struct */ extended_ptr = (ST_CHAR*)(dstobj + 1); /* point after dstobj struct */ dstobj->obj_name.vmd_spec = extended_ptr; extended_ptr += (MAX_IDENT_LEN + 1); /* point after dstobj->obj_name.vmd_spec*/ dstobj->domain_id = extended_ptr; /* Copy strings to the new struct. */ strcpy(dstobj->obj_name.vmd_spec, srcobj->obj_name.vmd_spec); if (dstobj->object_tag == DOM_SPEC) strcpy(dstobj->domain_id, srcobj->domain_id); return (dstobj); } /************************************************************************/ /* object_name_clone_destroy */ /* Destroy OBJECT_NAME clone created by "object_name_clone_create". */ /************************************************************************/ ST_VOID object_name_clone_destroy(OBJECT_NAME* obj) { /* allocated by object_name_clone_create using chk_malloc, so use chk_free.*/ chk_free(obj); } ST_RET check_va_count_too_big(ST_INT va_current_count, ST_INT va_total) { if (va_current_count < va_total) { return SD_SUCCESS; } else { echo_warn1("report va total %d is so small,may be error\n", va_total); return SD_FAILURE; } } /************************************************************************/ /* u_iec_rpt_ind */ /* This function processes ONLY IEC-61850 and UCA Reports. If any */ /* other InformationReport is received, it logs an error message and */ /* ignores it. */ /* CRITICAL: this function assumes that a pointer to an ALL_RCB_INFO */ /* structure has been saved in the */ /* user_info member of the MVL_NET_INFO structure for this conn. */ /************************************************************************/ ST_RET u_iec_rpt_ind_by_devtype(MVL_COMM_EVENT* event) { INFO_REQ_INFO* info_ptr; ST_INT j, va_num, va_total; VAR_ACC_SPEC* va_spec; MVL_VAR_ASSOC** info_va; RCB_INFO* rcb_info; ST_UINT8* OptFldsData; /* ptr to data part of OptFlds bvstring */ ST_UINT8* InclusionData; /* ptr to Inclusion bstring */ ST_CHAR saveRptID[66]; ALL_RCB_INFO* all_rcb_info; ST_RET retcode = SD_SUCCESS; info_ptr = (INFO_REQ_INFO*)event->u.mms.dec_rslt.data_ptr; va_spec = &info_ptr->va_spec; va_total = info_ptr->num_of_acc_result; /* An IEC-61850 or UCA report must be a NamedVariableList named "RPT". * Ignore any other InformationReport. */ if (va_spec->var_acc_tag != VAR_ACC_NAMEDLIST || strcmp(va_spec->vl_name.obj_name.vmd_spec, "RPT") != 0) { echo_warn("Received InformationReport is not a IEC-61850 Report or UCA Report. Ignored."); return (SD_FAILURE); } ////////////////// //WW 2023-08-29 增加终端类型与报告rcb_info绑定代码 int port; //端口 RCB_INFO *rcb_info1; ST_CHAR rptID[MVL61850_MAX_RPTID_LEN + 1] = { 0 }; //报告ID 66 ST_ULONG a_ip = get_rem_ip_addr_inline(event->net_info->acse_conn_id, &port); //WW 2023-08-29 获取装置IP、端口号 ST_CHAR *p_ip = _convert_ip_2_char(htonl(a_ip)); //WW 2023-08-29 将IP转为字符串指针 例:192.168.1.238 if (gDev_rcb_list.dev_rcb_info_Head == NULL) //全局报告控制块指针 || gDev_rcb_list->rcb_info_list == NULL { //SLOGALWAYS0 ("Received InformationReport. No IEC-61850 or UCA RCB enabled. Ignored."); //LOG_INFO("收到报告,未启用IEC-61850或UCA RCB使能。忽略!"); //仅调试使用! zl 2019-1-23 09:10:39 return (SD_FAILURE); } //逻辑:根据装置IP、端口号,先找到装置类型,再匹配报告信息,再解析报告!2019-12-24 17:27:29 //装置类型查找判断------------------------------------------------------------------------------------------------------------------------------ Dev_RCB_INFO *dev_rcb = NULL;//装置报告结构指针 Dev_IP_Port_INFO *dev_info = NULL; //装置IP、端口号结构指针 ST_BOOLEAN bFindIpPort = 0; //是否在链表中匹配到装置IP、端口号 for (dev_rcb = gDev_rcb_list.dev_rcb_info_Head; dev_rcb != NULL; dev_rcb = (Dev_RCB_INFO *)list_get_next(gDev_rcb_list.dev_rcb_info_Head, dev_rcb)) //①遍历 全局装置报告控制块链表 { //LOG_INFO("(报告解析)遍历gDev_rcb_list链表, dev_type_name= %s", dev_rcb->dev_type_name); //仅调试使用! zl 2019-12-24 00:16:31 //装置IP、端口号查找判断------------------------------------------------------------------------------------------------------------------------------------------------------------------- for (dev_info = dev_rcb->dev_ip_port_list; dev_info != NULL; dev_info = (Dev_IP_Port_INFO *)list_get_next(dev_rcb->dev_ip_port_list, dev_info)) //②遍历 全局装置IP、端口链表 { //LOG_INFO("(报告解析)遍历dev_ip_port_list链表, dev_type_name= %s, ip= %s, port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //仅调试使用! zl 2019-12-24 00:16:31 if ((strcmp(dev_info->IP, p_ip) == 0) && (dev_info->Port == port)) //匹配 装置IP && 端口号 { bFindIpPort = 1; //查找到装置IP && 端口号 //LOG_INFO("(报告解析)匹配到装置dev_type_name= %s, IP= %s,Port= %d", dev_rcb->dev_type_name, dev_info->IP, dev_info->Port); //仅调试使用! zl 2019-12-24 00:23:55 //strcpy(dev_rcb->dev_type_name, dev_rcb->dev_type_name); //匹配 装置类型 break; } } //遍历 装置IP、端口链表 结束 if (bFindIpPort) //在链表中匹配到装置IP、端口号 break; } //遍历 全局装置报告控制块链表 结束 if (!bFindIpPort) //未查找到装置IP、端口 { //LOG_INFO("(报告解析)dev_type_name= %s未匹配到IP= %s,Port= %d的装置类型,goto CLEANUP跳出!", dev_rcb->dev_type_name, p_ip, port); //仅调试使用! zl 2019-12-24 00:23:55 retcode = SD_FAILURE; goto END; //跳转至 CLEANUP,即:返回retcode结束 } rcb_info = dev_rcb->rcb_info_list; //根据装置类型,匹配报告控制块信息 //WW 2023-08-29 end ////////////////////////////// /* Get "all_rcb_info" from "user_info". User must set "user_info" when conn established.*/ ////////////////////// //WW 2023-08-29注释 //all_rcb_info = (ALL_RCB_INFO*)event->net_info->user_info; ///* Check "all_rcb_info" to see if any RCB has been enabled. */ //if (all_rcb_info == NULL || all_rcb_info->rcb_info_list == NULL) //{ // echo_warn("Received InformationReport. No IEC-61850 or UCA RCB enabled. Ignored."); // return (SD_FAILURE); //} //WW 2023-08-29 end //////////////////////// /* Create array of (MVL_VAR_ASSOC *) needed for converting the received * data to local format. * Use variables created earlier to fill in the array. These variables will * hold the decoded data. * NOTE: any return after this must free info_va (see CLEANUP label). */ info_va = (MVL_VAR_ASSOC**)chk_calloc(va_total, sizeof(MVL_VAR_ASSOC*)); ////////////////// //WW 2023-08-29 增加终端类型与报告rcb_info绑定代码 rcb_info = dev_rcb->rcb_info_list; //根据装置类型,匹配报告控制块信息 va_num = 0; info_va[va_num++] = rcb_info->rcb_var.RptID; //LOG_INFO("va_num = %d", va_num); //仅调试使用! zl 2019-1-23 09:10:39 all_rcb_info = (ALL_RCB_INFO*)chk_calloc(1, sizeof(ALL_RCB_INFO)); all_rcb_info->rpt_typeids = &g_rpt_typeids; all_rcb_info->rcb_info_list = dev_rcb->rcb_info_list; event->net_info->user_info = all_rcb_info; rcb_info = all_rcb_info->rcb_info_list; rcb_info->rcb_data.RptID[0] = '\0'; /* start with empty string */ mvl_info_data_to_local(event, va_num, info_va); //将报告数据转换为本地格式 /* NOTE: decoded RptID is now in "rcb_info->rcb_data.RptID". Save it.*/ strcpy(saveRptID, rcb_info->rcb_data.RptID); //装置上送报告ID 例:PQM2/LLN0$BR$brcbStatisticData01 //LOG_INFO("装置上送报告saveRptID:%s", saveRptID); //仅调试使用! zl 2019-1-23 09:10:39 chk_free(all_rcb_info); event->net_info->user_info = NULL; /* Search list of "rcb_info" to find one with matching RptID. If not found, rcb_info will be == NULL. */ //装置报告控制块查找判断----------------------------------------------------------------------------------------------------------------------------------------------------- for (rcb_info = dev_rcb->rcb_info_list; rcb_info != NULL; rcb_info = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info)) //遍历 全局报告控制块链表 { //LOG_INFO("遍历报告控制块链表RptID:%s,saveRptID:%s", rcb_info->RptID, saveRptID); //仅调试使用! zl 2019-1-23 09:10:39 if (strcmp(rcb_info->RptID, saveRptID) == 0) break; /* rcb_info now points to right structure */ } if (!rcb_info) //报告控制块指针为空! { //SLOGALWAYS1 ("RptID '%s' not recognized on this connection. Received report ignored.", saveRptID); //LOG_INFO("(报告解析)报告控制块链表查找不到RptID= '%s',goto CLEANUP跳出!", saveRptID); //仅调试使用! zl 2019-12-23 15:09:36 retcode = SD_FAILURE; goto CLEANUP; //跳转至 CLEANUP,即:返回retcode结束 } //WW 2023-08-29 end ////////////////////////////// ////////////////////// //WW 2023-08-29注释 ///* Must decode the RptID first to find the correct RCB_INFO. Could decode into //* any "vstring65" variable. We just use the RptID variable from the first //* rcb_info on the list. //*/ //rcb_info = all_rcb_info->rcb_info_list; /* use first rcb_info on list*/ //va_num = 0; //info_va[va_num++] = rcb_info->rcb_var.RptID; //rcb_info->rcb_data.RptID[0] = '\0'; /* start with empty string */ //mvl_info_data_to_local(event, va_num, info_va); ///* NOTE: decoded RptID is now in "rcb_info->rcb_data.RptID". Save it.*/ //strcpy(saveRptID, rcb_info->rcb_data.RptID); ///* Search list of "rcb_info" to find one with matching RptID. */ ///* If not found, rcb_info will be == NULL. */ //for (rcb_info = all_rcb_info->rcb_info_list; // rcb_info != NULL; // rcb_info = (RCB_INFO*)list_get_next(all_rcb_info->rcb_info_list, rcb_info)) //{ // if (strcmp(rcb_info->RptID, saveRptID) == 0) // break; /* rcb_info now points to right structure */ //} //if (!rcb_info) //{ // echo_warn1("RptID '%s' not recognized on this connection. Received report ignored.", saveRptID); // retcode = SD_FAILURE; // goto CLEANUP; //} //WW 2023-08-29 end //////////////////////// va_num = 0; info_va[va_num++] = rcb_info->rcb_var.RptID; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; info_va[va_num++] = rcb_info->rcb_var.OptFlds; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; /* Perform 1st decode (up through "OptFlds"). Need "OptFlds" to figure * out what comes next. */ mvl_info_data_to_local(event, va_num, info_va); /* Examine "OptFlds", and set up 2nd decode to decode all options */ OptFldsData = rcb_info->rcb_data.OptFlds.data_1; /* use local var */ // printf ("OptFlds = 0x%02x 0x%02x\n", OptFldsData[0],OptFldsData[1]); /* 9 bit bstr (2 bytes) */ /* NOTE: Don't change initial entries in "info_va". Add these right after "OptFlds".*/ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SQNUM)) info_va[va_num++] = rcb_info->rcb_var.SqNum; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_TIMESTAMP)) info_va[va_num++] = rcb_info->rcb_var.TimeOfEntry; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATSETNAME)) { info_va[va_num++] = rcb_info->rcb_var.DatSetNa; /////////////////// //WW 2023-08-29 log_var_to_data(rcb_info->rcb_var.DatSetNa, rptID); //for (rcb_info1 = all_rcb_info->rcb_info_list; // rcb_info1 != NULL; // rcb_info1 = (RCB_INFO *) list_get_next (all_rcb_info->rcb_info_list, rcb_info1)) //遍历 装置报告控制块链表 for (rcb_info1 = dev_rcb->rcb_info_list; rcb_info1 != NULL; rcb_info1 = (RCB_INFO *)list_get_next(dev_rcb->rcb_info_list, rcb_info1)) //遍历 报告控制块链表 { if (strcmp(rcb_info1->ds_Nam, rptID) == 0) //报告ID,作为不同报告间的唯一标识符 { //SLOGALWAYS3 ("Num of var received in RPT (%d) does not match expected (%d)dateSet=%s ", va_total, va_num,rptID); //LOG_INFO("(报告解析)接收报告RptID= '%s'数据集rptID= %s,大小(%d)与预期大小(%d)不匹配,brak跳出!", saveRptID, rptID, va_total, va_num); //仅调试使用! zl 2019-12-23 15:09:30 rcb_info = rcb_info1; break; } } //WW 2023-08-29 en /////////////////////////// } if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; /* The following optional vars are supported by IEC-61850 but they are * NOT supported by UCA. This client must NOT set these OptFlds bits * when connected to a UCA server, and these variables will NOT be * included in a report received from a UCA server. */ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_BUFOVFL)) info_va[va_num++] = rcb_info->rcb_var.BufOvfl; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_ENTRYID)) info_va[va_num++] = rcb_info->rcb_var.EntryID; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_CONFREV)) info_va[va_num++] = rcb_info->rcb_var.ConfRev; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SUBSEQNUM)) { info_va[va_num++] = rcb_info->rcb_var.SubSeqNum; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; info_va[va_num++] = rcb_info->rcb_var.MoreSegmentsFollow; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; } info_va[va_num++] = rcb_info->rcb_var.Inclusion; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; assert(va_num < va_total); /* Perform 2nd decode (up through "Inclusion"). */ mvl_info_data_to_local(event, va_num, info_va); /* Examine "Inclusion", and set up 3rd decode to decode all data. */ InclusionData = rcb_info->rcb_data.Inclusion; /* use local var */ // printf ("\nThe 1st byte Inclusion = 0x%02X\n", InclusionData[0]); /* Just print 1st byte */ /* NOTE: Don't change initial entries in "info_va". Add these right after "Inclusion".*/ /* If "data-Ref" enabled, check "Inclusion" to figure out what is being received.*/ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATAREF)) { for (j = 0; j < rcb_info->numDsVar; ++j) { if (BSTR_BIT_GET(InclusionData, j)) { info_va[va_num++] = rcb_info->rcb_var.dataRefName[j]; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; } } } /* HERE'S THE DATA. Check "Inclusion" to figure out what is being received.*/ for (j = 0; j < rcb_info->numDsVar; ++j) { if (BSTR_BIT_GET(InclusionData, j)) { info_va[va_num++] = rcb_info->rcb_var.dataValue[j]; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; } } /* If "reason" enabled, check "Inclusion" to figure out what is being received.*/ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_REASON)) { for (j = 0; j < rcb_info->numDsVar; ++j) { if (BSTR_BIT_GET(InclusionData, j)) { info_va[va_num++] = rcb_info->rcb_var.Reason[j]; } } } /* Does num of variables received match expected num.*/ if (va_num != va_total) { echo_warn2("Num of var received in RPT (%d) does not match expected (%d). Possibly incorrect OptFlds or inclusion bitstring", va_total, va_num); // printf ("Num of var received in RPT (%d) does not match expected (%d). Possibly incorrect OptFlds or inclusion bitstring\n", va_total, va_num); } else { /* Perform 3rd decode (everything). */ mvl_info_data_to_local(event, va_num, info_va); u_iec_rpt_ind_data_by_devtype(info_va, OptFldsData, InclusionData, rcb_info, va_total, event->net_info); } CLEANUP: chk_free(info_va); END: return (retcode); } ST_RET u_iec_rpt_ind(MVL_COMM_EVENT* event) { INFO_REQ_INFO* info_ptr; ST_INT j, va_num, va_total; VAR_ACC_SPEC* va_spec; MVL_VAR_ASSOC** info_va; RCB_INFO* rcb_info, * rcb_info1; ST_UINT8* OptFldsData; /* ptr to data part of OptFlds bvstring */ ST_UINT8* InclusionData; /* ptr to Inclusion bstring */ ST_CHAR saveRptID[66]; ALL_RCB_INFO* all_rcb_info; ST_RET retcode = SD_SUCCESS; info_ptr = (INFO_REQ_INFO*)event->u.mms.dec_rslt.data_ptr; va_spec = &info_ptr->va_spec; va_total = info_ptr->num_of_acc_result; /* An IEC-61850 or UCA report must be a NamedVariableList named "RPT". * Ignore any other InformationReport. */ if (va_spec->var_acc_tag != VAR_ACC_NAMEDLIST || strcmp(va_spec->vl_name.obj_name.vmd_spec, "RPT") != 0) { echo_warn("Received InformationReport is not a IEC-61850 Report or UCA Report. Ignored."); return (SD_FAILURE); } /* Get "all_rcb_info" from "user_info". User must set "user_info" when conn established.*/ all_rcb_info = (ALL_RCB_INFO*)event->net_info->user_info; /* Check "all_rcb_info" to see if any RCB has been enabled. */ if (all_rcb_info == NULL || all_rcb_info->rcb_info_list == NULL) { echo_warn("Received InformationReport. No IEC-61850 or UCA RCB enabled. Ignored."); return (SD_FAILURE); } /* Create array of (MVL_VAR_ASSOC *) needed for converting the received * data to local format. * Use variables created earlier to fill in the array. These variables will * hold the decoded data. * NOTE: any return after this must free info_va (see CLEANUP label). */ info_va = (MVL_VAR_ASSOC**)chk_calloc(va_total, sizeof(MVL_VAR_ASSOC*)); /* Must decode the RptID first to find the correct RCB_INFO. Could decode into * any "vstring65" variable. We just use the RptID variable from the first * rcb_info on the list. */ rcb_info = all_rcb_info->rcb_info_list; /* use first rcb_info on list*/ va_num = 0; info_va[va_num++] = rcb_info->rcb_var.RptID; rcb_info->rcb_data.RptID[0] = '\0'; /* start with empty string */ mvl_info_data_to_local(event, va_num, info_va); /* NOTE: decoded RptID is now in "rcb_info->rcb_data.RptID". Save it.*/ strcpy(saveRptID, rcb_info->rcb_data.RptID); /* Search list of "rcb_info" to find one with matching RptID. */ /* If not found, rcb_info will be == NULL. */ for (rcb_info = all_rcb_info->rcb_info_list; rcb_info != NULL; rcb_info = (RCB_INFO*)list_get_next(all_rcb_info->rcb_info_list, rcb_info)) { if (strcmp(rcb_info->RptID, saveRptID) == 0) break; /* rcb_info now points to right structure */ } if (!rcb_info) { echo_warn1("RptID '%s' not recognized on this connection. Received report ignored.", saveRptID); retcode = SD_FAILURE; goto CLEANUP; } va_num = 0; info_va[va_num++] = rcb_info->rcb_var.RptID; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; info_va[va_num++] = rcb_info->rcb_var.OptFlds; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; /* Perform 1st decode (up through "OptFlds"). Need "OptFlds" to figure * out what comes next. */ mvl_info_data_to_local(event, va_num, info_va); /* Examine "OptFlds", and set up 2nd decode to decode all options */ OptFldsData = rcb_info->rcb_data.OptFlds.data_1; /* use local var */ // printf ("OptFlds = 0x%02x 0x%02x\n", OptFldsData[0],OptFldsData[1]); /* 9 bit bstr (2 bytes) */ /* NOTE: Don't change initial entries in "info_va". Add these right after "OptFlds".*/ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SQNUM)) info_va[va_num++] = rcb_info->rcb_var.SqNum; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_TIMESTAMP)) info_va[va_num++] = rcb_info->rcb_var.TimeOfEntry; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; //WW 2024-09-02 数据集名称确认 if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATSETNAME)) info_va[va_num++] = rcb_info->rcb_var.DatSetNa; mvl_info_data_to_local(event, va_num, info_va); //WW 2024-09-02 endss if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATSETNAME)) { //info_va[va_num++] = rcb_info->rcb_var.DatSetNa; //WW 2024-09-02 注释 /////////////////// //WW 2023-08-29 log_var_to_data(rcb_info->rcb_var.DatSetNa, saveRptID); for (rcb_info1 = all_rcb_info->rcb_info_list; rcb_info1 != NULL; rcb_info1 = (RCB_INFO*)list_get_next(all_rcb_info->rcb_info_list, rcb_info1)) //遍历 报告控制块链表 { if (strcmp(rcb_info1->ds_Nam, saveRptID) == 0) //报告ID,作为不同报告间的唯一标识符 { printf("ds_name '%s' ! Recive name %s WWTest \n", rcb_info1->ds_Nam, saveRptID); //SLOGALWAYS3 ("Num of var received in RPT (%d) does not match expected (%d)dateSet=%s ", va_total, va_num,rptID); //LOG_INFO("(报告解析)接收报告RptID= '%s'数据集rptID= %s,大小(%d)与预期大小(%d)不匹配,brak跳出!", saveRptID, rptID, va_total, va_num); //仅调试使用! zl 2019-12-23 15:09:30 rcb_info = rcb_info1; break; } } //WW 2023-08-29 en /////////////////////////// } if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; /* The following optional vars are supported by IEC-61850 but they are * NOT supported by UCA. This client must NOT set these OptFlds bits * when connected to a UCA server, and these variables will NOT be * included in a report received from a UCA server. */ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_BUFOVFL)) info_va[va_num++] = rcb_info->rcb_var.BufOvfl; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_ENTRYID)) info_va[va_num++] = rcb_info->rcb_var.EntryID; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_CONFREV)) info_va[va_num++] = rcb_info->rcb_var.ConfRev; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_SUBSEQNUM)) { info_va[va_num++] = rcb_info->rcb_var.SubSeqNum; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; info_va[va_num++] = rcb_info->rcb_var.MoreSegmentsFollow; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; } info_va[va_num++] = rcb_info->rcb_var.Inclusion; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; assert(va_num < va_total); /* Perform 2nd decode (up through "Inclusion"). */ mvl_info_data_to_local(event, va_num, info_va); /* Examine "Inclusion", and set up 3rd decode to decode all data. */ InclusionData = rcb_info->rcb_data.Inclusion; /* use local var */ // printf ("\nThe 1st byte Inclusion = 0x%02X\n", InclusionData[0]); /* Just print 1st byte */ /* NOTE: Don't change initial entries in "info_va". Add these right after "Inclusion".*/ /* If "data-Ref" enabled, check "Inclusion" to figure out what is being received.*/ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_DATAREF)) { for (j = 0; j < rcb_info->numDsVar; ++j) { if (BSTR_BIT_GET(InclusionData, j)) { info_va[va_num++] = rcb_info->rcb_var.dataRefName[j]; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; } } } /* HERE'S THE DATA. Check "Inclusion" to figure out what is being received.*/ for (j = 0; j < rcb_info->numDsVar; ++j) { if (BSTR_BIT_GET(InclusionData, j)) { info_va[va_num++] = rcb_info->rcb_var.dataValue[j]; if ((retcode = check_va_count_too_big(va_num, va_total)) == SD_FAILURE) goto CLEANUP; } } /* If "reason" enabled, check "Inclusion" to figure out what is being received.*/ if (BSTR_BIT_GET(OptFldsData, OPTFLD_BITNUM_REASON)) { for (j = 0; j < rcb_info->numDsVar; ++j) { if (BSTR_BIT_GET(InclusionData, j)) { info_va[va_num++] = rcb_info->rcb_var.Reason[j]; } } } /* Does num of variables received match expected num.*/ if (va_num != va_total) { echo_warn2("Num of var received in RPT (%d) does not match expected (%d). Possibly incorrect OptFlds or inclusion bitstring", va_total, va_num); // printf ("Num of var received in RPT (%d) does not match expected (%d). Possibly incorrect OptFlds or inclusion bitstring\n", va_total, va_num); } else { /* Perform 3rd decode (everything). */ mvl_info_data_to_local(event, va_num, info_va); //报告处理加锁lnk20250114 pthread_mutex_lock(&mtx); u_iec_rpt_ind_data(info_va, OptFldsData, InclusionData, rcb_info, va_total, event->net_info); pthread_mutex_unlock(&mtx); } CLEANUP: chk_free(info_va); return (retcode); } /************************************************************************/ //61850报告解析为本地数据 /************************************************************************/ void log_var_to_data(MVL_VAR_ASSOC *var, char *pdata) { static char text_buf[30000]; /* increase size if ms_local_to_text fails */ // ST_CHAR tdl_buf [500]; /* increase size if complex TDL expected*/ MVL_TYPE_CTRL *type_ctrl; ST_CHAR *data_text; /* var data converted to text */ text_buf[0] = 0; type_ctrl = mvl_type_ctrl_find(var->type_id); if (type_ctrl) { //if (ms_runtime_to_tdl(type_ctrl->rt,type_ctrl->num_rt,tdl_buf,sizeof(tdl_buf))>0) // RTP_PRI (" TYPE: %s\r\n", tdl_buf); //else RTP_PRI (" TYPE: unknown\r\n"); data_text = ms_local_to_text((char *)var->data, type_ctrl->rt, type_ctrl->num_rt, text_buf, sizeof(text_buf)); if (data_text) { strcpy(pdata, data_text); } else *pdata = '0'; } else *pdata = '0'; } /************************************************************************/ /* LocToTextBs */ /************************************************************************/ #define TEMP_DATA_BUF_SIZE 1024 static ST_RET myLocToTextBs(ST_UCHAR* pSrc, RUNTIME_TYPE* rt, ST_CHAR* text) { int i; int j; int k; int numBits; ST_INT16* sp; ST_CHAR* destBuf; ST_UCHAR mask; //printf("%s text_len %d %d pSrc %d %d \n", text, strlen(text), rt->u.p.el_len, pSrc[0], pSrc[1]); text[0] = 0; numBits = rt->u.p.el_len; /* We take 1 dest byte per bit, make sure it fits */ if (numBits > TEMP_DATA_BUF_SIZE - 1) { MLOG_NERR1("Bit String (%d bits) too long to encode", numBits); return (SD_FAILURE); } if (numBits < 0) /* a variable length bit string */ { sp = (ST_INT16*)pSrc; numBits = *sp; //printf("numBits %d \n", numBits); if ((numBits > TEMP_DATA_BUF_SIZE - 1) || (numBits <= 0)) { if (numBits != 0) //add by lzm @2018.11.1,to avoid too many print message!!! echo_warn1("Bit String (%d bits) too long to encode\n", numBits); return (SD_FAILURE); } k = 2; } else k = 0; destBuf = text; for (i = 0; i < numBits; ++k) /* for each byte, while bits remain */ { mask = 0x80; for (j = 0; j < 8 && i < numBits; ++i, ++j) { if (pSrc[k] & mask) destBuf[i] = '1'; else destBuf[i] = '0'; mask >>= 1; } } destBuf[i] = 0; return (SD_SUCCESS); } /************************************************************************/ /* LocToTextOct */ /************************************************************************/ static ST_RET myLocToTextOct(ST_UCHAR* pSrc, RUNTIME_TYPE* rt, ST_CHAR* text) { int i, k; int numBytes; ST_INT16* sp; ST_CHAR* destBuf; text[0] = 0; numBytes = rt->u.p.el_len; if (numBytes < 0) /* a variable length octet string */ { sp = (ST_INT16*)pSrc; numBytes = *sp; k = 2; } else k = 0; /* We take 3 bytes per octet, make sure it fits */ if (numBytes > TEMP_DATA_BUF_SIZE / 3) { MLOG_NERR1("Octet String (%d bytes) too long to encode", numBytes); return SD_FAILURE; } destBuf = text; for (i = 0; i < numBytes; ++i, ++k) { apr_snprintf(destBuf, sizeof(destBuf), "%02x ", (unsigned int)pSrc[k]); destBuf += 3; } /* Eliminate the trailing space */ *(destBuf - 1) = 0; return (SD_SUCCESS); } /************************************************************************/ /* asn1_convert_utc_to_btod */ /* This function converts MMS_UTC_TIME (time relative to 1/1/1970) to */ /* the MMS_BTOD (time relative to 1/1/1984). */ /* The form field in the MMS_BTOD is set to MMS_BTOD6 by this function. */ /* Parameters: */ /* utc pointer to MMS_UTC_TIME struct that should be converted */ /* to the MMS_BTOD */ /* btod pointer to MMS_BTOD struct where the result of the */ /* conversion will be placed */ /* Return: */ /* SD_SUCCESS if function successful */ /* SD_FAILURE otherwise */ /************************************************************************/ ST_RET my_asn1_convert_utc_to_btod(MMS_UTC_TIME* utc, MMS_BTOD* btod) { time_t tJan84 = TIME_T_1984_JAN_1; /* Now compute the MMS_BTOD time */ btod->day = (long)(utc->secs - tJan84) / SECONDS_PER_DAY; /* num of days since 1/1/1984 */ btod->ms = (long)((utc->secs - tJan84) % SECONDS_PER_DAY) * 1000; /* num milliseconds since midnight */ /* NOTE: use 0x01000000 (2**24) in fraction computations. */ // 要四舍五入到毫秒数,比如 28.9999应该是29ms btod->ms += (ST_INT32)(0.5 + (ST_DOUBLE)utc->fraction * 1000.0 / (ST_DOUBLE)0x01000000); /* add the milliseconds left in a sec */ btod->form = MMS_BTOD6; return (SD_SUCCESS); } /************************************************************************/ /* ms_local_to_text */ /* NOTE: tmpBuf is passed to most "LocToText.." static functions. These */ /* functions must NOT write past end of tmpBuf. */ /************************************************************************/ void my_local_to_data(ST_CHAR* datptr, SD_CONST RUNTIME_TYPE* rt_head, ST_INT rt_num, MMS_DECODE_DATA* data) { RUNTIME_TYPE* rt_ptr; RUNTIME_TYPE* rt_end; ST_RET uDataRet; ST_INT arr_loop_level = 0; ST_INT arr_loops[ASN1_MAX_LEVEL]; //ST_CHAR *ret_ptr; ST_CHAR tmpBuf[TEMP_DATA_BUF_SIZE]; //ST_UINT nStrLen = 0; /* Current text total length */ ST_UINT valid_item_num = 0; SD_CONST ST_CHAR* comp_name; /* component name *///add by lzm //ST_INT comp_name_len; /* len of component name*/ ST_UINT deep = 0; // deep of structure unsigned int jjj; char attr_str[256]; char comp_str[32][256]; int cur_array_deep = -1; ST_UINT cur_array_idx; if (data == NULL) { echo_warn("error ~~~~~~~ my_local_to_data MMS_DECODE_DATA data is NULL return \n"); return; } if (rt_num <= 0) { echo_warn1("error !!!!!!! my_local_to_data rt_num %d = return \n", rt_num); return; } if (rt_head->el_tag > RT_ARR_END) { echo_warn2("error @@@@@@@ my_local_to_data rt_head->el_tag %d size %d = return \n", rt_head->el_tag, rt_head->el_size); return; } data->item_num = 0; rt_ptr = (RUNTIME_TYPE*)rt_head; /* point to head rt_block */ rt_end = rt_ptr + rt_num; /* done when pointer is here */ if (rt_end == NULL) { echo_warn("error XXXXXX my_local_to_data rt_end \n"); return; } // SLOGCALWAYS1(" rt_num = %i",rt_num); uDataRet = SD_SUCCESS; while (rt_ptr < rt_end && uDataRet == SD_SUCCESS) { if (rt_ptr == NULL) { echo_warn("error !!!!!!! my_local_to_data rt_ptr is NULL error,return \n"); return; } if (valid_item_num >= MAX_DATA_ITEMS_IN_ONE_DATA) { echo_warn2("my_local_to_data RUNTIME_TYPE valid_item_num % >= %d \n", valid_item_num, MAX_DATA_ITEMS_IN_ONE_DATA); return; } if (rt_ptr->el_tag == RT_ARR_END) /* treat case of array ending */ { if (--arr_loops[arr_loop_level] > 0) /* if need to do next ar elmnt */ rt_ptr -= rt_ptr->u.arr.num_rt_blks; /* mv rt_ptr to start of arr */ else --arr_loop_level; } if (rt_ptr->el_tag == RT_ARR_START) /* treat case of array starting */ { /* initialize the loop counter for the array */ ++arr_loop_level; arr_loops[arr_loop_level] = rt_ptr->u.arr.num_elmnts; } comp_name = ms_comp_name_find(rt_ptr);//add by lzm //printf ("\n %i, comp_name = %s cur_array_deep/deep: %d/%d \n",rt_ptr->el_tag,comp_name,cur_array_deep,deep); // if (comp_name != NULL && comp_name[0] != 0) // SLOGCALWAYS2 (" comp_name= %s, rt_ptr->el_tag =%i ",comp_name,rt_ptr->el_tag); // add by lzm memset(attr_str, 0, sizeof(attr_str)); if (deep == (cur_array_deep + 1)) cur_array_idx++; for (jjj = 0; jjj < deep; jjj++) { if (strcmp(comp_str[jjj], "")) { strcat(attr_str, comp_str[jjj]); } if (jjj == cur_array_deep) { char tmp_str[8]; apr_snprintf(tmp_str, sizeof(tmp_str), "[%d]", cur_array_idx); strcat(attr_str, tmp_str); } if (strcmp(comp_str[jjj], "")) { strcat(attr_str, "$"); } //if (strcmp (comp_str[jjj], "")) { //} } strcat(attr_str, comp_name); switch (rt_ptr->el_tag) { case RT_ARR_START: strcpy(comp_str[deep], comp_name); cur_array_deep = deep; cur_array_idx = -1; assert(++deep < 32); break; /* do nothing */ case RT_ARR_END: /* array done */ assert(--deep >= 0); memset(comp_str[deep], 0, sizeof(comp_str[deep])); cur_array_deep = -1; cur_array_idx = -1; break; /* do nothing */ case RT_STR_START: strcpy(comp_str[deep], comp_name); assert(++deep < 32); //uDataRet = AddString ("{", textBuf, textBufSize, &nStrLen); break; case RT_STR_END: /* structure done */ assert(--deep >= 0); memset(comp_str[deep], 0, sizeof(comp_str[deep])); //uDataRet = AddString ("}", textBuf, textBufSize, &nStrLen); break; case RT_BOOL: strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = 1; data->data_item[valid_item_num].type = DATA_INT_TYPE; data->data_item[valid_item_num].u.data_int = *((ST_BOOLEAN*)datptr); valid_item_num++; // SLOGCALWAYS2("valid_item_num = %i , value=%i",valid_item_num, *((ST_BOOLEAN *) datptr) ); data->item_num = valid_item_num; break; case RT_BIT_STRING: myLocToTextBs((ST_UCHAR*)datptr, rt_ptr, tmpBuf); strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = abs(rt_ptr->u.p.el_len); data->data_item[valid_item_num].type = DATA_STR_TYPE; strcpy(data->data_item[valid_item_num].u.data_str, tmpBuf); valid_item_num++; // SLOGCALWAYS2("valid_item_num = %i , value=%s",valid_item_num, tmpBuf ); data->item_num = valid_item_num; break; case RT_INTEGER: case RT_BCD: switch (rt_ptr->u.p.el_len) /* determine length */ { case 1: /* one byte int */ case 2: /* two byte int */ case 4: /* four byte integer */ strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = (unsigned char)rt_ptr->u.p.el_len; data->data_item[valid_item_num].type = DATA_INT_TYPE; if (rt_ptr->u.p.el_len == 1) data->data_item[valid_item_num].u.data_int = *((ST_INT8*)datptr); else if (rt_ptr->u.p.el_len == 2) data->data_item[valid_item_num].u.data_int = *((ST_INT16*)datptr); else if (rt_ptr->u.p.el_len == 4) data->data_item[valid_item_num].u.data_int = *((ST_INT32*)datptr); // SLOGCALWAYS1("value=%i",data->data_item[valid_item_num].u.data_int ); valid_item_num++; // SLOGCALWAYS1("valid_item_num = %i ",valid_item_num ); data->item_num = valid_item_num; break; #ifdef INT64_SUPPORT case 8: /* eight byte integer */ strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = (unsigned char)rt_ptr->u.p.el_len; data->data_item[valid_item_num].type = DATA_INT64_TYPE; data->data_item[valid_item_num].u.data_int64 = *((ST_INT64*)datptr); // SLOGCALWAYS1(" value=%lld ",data->data_item[valid_item_num].u.data_int64 ); valid_item_num++; // SLOGCALWAYS1("valid_item_num = %i ",valid_item_num ); data->item_num = valid_item_num; break; #endif default: echo_warn1("未处理的RT_INTEGER或RT_BCD 整数 size = %i \n", rt_ptr->u.p.el_len); break; } break; case RT_UNSIGNED: switch (rt_ptr->u.p.el_len) /* determine length */ { case 1: /* one byte int */ case 2: /* two byte int */ case 4: /* four byte integer */ strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = (unsigned char)rt_ptr->u.p.el_len; data->data_item[valid_item_num].type = DATA_UINT_TYPE; if (rt_ptr->u.p.el_len == 1) data->data_item[valid_item_num].u.data_uint = *((ST_UCHAR*)datptr); else if (rt_ptr->u.p.el_len == 2) data->data_item[valid_item_num].u.data_uint = *((ST_UINT16*)datptr); else if (rt_ptr->u.p.el_len == 4) data->data_item[valid_item_num].u.data_uint = *((ST_UINT32*)datptr); // SLOGCALWAYS1("value=%u",data->data_item[valid_item_num].u.data_uint ); valid_item_num++; // SLOGCALWAYS1("valid_item_num = %i ",valid_item_num ); data->item_num = valid_item_num; break; #ifdef INT64_SUPPORT case 8: /* eight byte integer */ strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = (unsigned char)rt_ptr->u.p.el_len; data->data_item[valid_item_num].type = DATA_UINT64_TYPE; data->data_item[valid_item_num].u.data_int64 = *((ST_UINT64*)datptr); // SLOGCALWAYS1(" value=%llu ",data->data_item[valid_item_num].u.data_uint64 ); valid_item_num++; // SLOGCALWAYS1("valid_item_num = %i ",valid_item_num ); data->item_num = valid_item_num; break; #endif /* INT64_SUPPORT */ default: echo_warn1("未处理的 无符号整数 size = %i \n", rt_ptr->u.p.el_len); break; } break; #ifdef FLOAT_DATA_SUPPORT case RT_FLOATING_POINT: strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = (unsigned char)rt_ptr->u.p.el_len; data->data_item[valid_item_num].type = DATA_DOUBLE_TYPE; if (rt_ptr->u.p.el_len != sizeof(ST_FLOAT)) data->data_item[valid_item_num].u.data_double = *((ST_DOUBLE*)datptr); else data->data_item[valid_item_num].u.data_double = *((ST_FLOAT*)datptr); // SLOGCALWAYS1(" value=%.16g ",data->data_item[valid_item_num].u.data_double ); valid_item_num++; // SLOGCALWAYS1("valid_item_num = %i ",valid_item_num ); data->item_num = valid_item_num; break; #endif case RT_OCTET_STRING: myLocToTextOct((ST_UCHAR*)datptr, rt_ptr, tmpBuf); strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = abs(rt_ptr->u.p.el_len); data->data_item[valid_item_num].type = DATA_STR_TYPE; strcpy(data->data_item[valid_item_num].u.data_str, tmpBuf); valid_item_num++; //SLOGCALWAYS2("valid_item_num = %i , value=%s",valid_item_num, tmpBuf ); data->item_num = valid_item_num; break; case RT_VISIBLE_STRING: /* No conversion needed. Just add to working text*/ strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = abs(rt_ptr->u.p.el_len); data->data_item[valid_item_num].type = DATA_STR_TYPE; strcpy(data->data_item[valid_item_num].u.data_str, datptr); valid_item_num++; // SLOGCALWAYS2("valid_item_num = %i , value=%s",valid_item_num, datptr ); data->item_num = valid_item_num; break; #ifdef TIME_DATA_SUPPORT case RT_GENERAL_TIME: strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = abs(rt_ptr->u.p.el_len); data->data_item[valid_item_num].type = DATA_TIME_TYPE; asn1_convert_timet_to_btime6(*((time_t*)datptr), &(data->data_item[valid_item_num].u.data_bTime6)); valid_item_num++; data->item_num = valid_item_num; break; #endif #ifdef BTOD_DATA_SUPPORT case RT_BINARY_TIME: switch (rt_ptr->u.p.el_len) /* determine length */ { MMS_BTIME6 btime6; case 4: asn1_convert_timet_to_btime6(time(NULL), &btime6); btime6.ms = *((ST_INT32*)datptr); strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = 4; data->data_item[valid_item_num].type = DATA_TIME_TYPE; data->data_item[valid_item_num].u.data_bTime6 = btime6; valid_item_num++; data->item_num = valid_item_num; break; case 6: strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = 6; data->data_item[valid_item_num].type = DATA_TIME_TYPE; data->data_item[valid_item_num].u.data_bTime6 = *((MMS_BTIME6*)datptr); valid_item_num++; data->item_num = valid_item_num; break; } break; #endif case RT_UTC_TIME: { MMS_BTOD btod; //cout<<"((MMS_UTC_TIME *) datptr)->fraction = "<<((MMS_UTC_TIME *) datptr)->fraction; //cout<<"((MMS_UTC_TIME *)datptr)->qflags = "<<((MMS_UTC_TIME *)datptr)->qflags<data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = 1; data->data_item[valid_item_num].type = DATA_TIME_TYPE; data->data_item[valid_item_num].u.data_bTime6.day = btod.day; data->data_item[valid_item_num].u.data_bTime6.ms = btod.ms; valid_item_num++; // SLOGALWAYS3("valid_item_num = %i , UTC TIME seconds=%lu, fraction=%lu", // valid_item_num, ((MMS_UTC_TIME *) datptr)->fraction, // ((MMS_UTC_TIME *) datptr)->secs ); data->item_num = valid_item_num; } break; case RT_UTF8_STRING: strcpy(data->data_item[valid_item_num].comp_name, (const char*)attr_str); data->data_item[valid_item_num].size = abs(rt_ptr->u.p.el_len); data->data_item[valid_item_num].type = DATA_STR_TYPE; strcpy(data->data_item[valid_item_num].u.data_str, datptr); valid_item_num++; // SLOGCALWAYS2("valid_item_num = %i , value=%s",valid_item_num, datptr ); data->item_num = valid_item_num; break; default: /* should not be any other tag */ MLOG_ERR1("Invalid tag: %d", (int)rt_ptr->el_tag); uDataRet = SD_FAILURE; break; } assert(strlen(tmpBuf) < sizeof(tmpBuf)); /* Must not exceed buffer*/ datptr += rt_ptr->el_size; /* Adjust data pointer */ rt_ptr++; /* point to next rt element */ } }