<修改> 1、调整上送mms服务端数据;2、新增客户端文件等功能
This commit is contained in:
parent
cd61e8e27b
commit
1a16180a9c
|
|
@ -171,6 +171,17 @@ int mms_m_set_data_value(void *srt, void *dst, uint8_t type);
|
||||||
int mms_m_get_data_value_str(void *data, uint8_t type, char *str);
|
int mms_m_get_data_value_str(void *data, uint8_t type, char *str);
|
||||||
int mms_m_set_data_by_str(void *data, uint8_t type, const char *str);
|
int mms_m_set_data_by_str(void *data, uint8_t type, const char *str);
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*mms_m_file_read_cb)(int fd, const char *fn, const uint8_t *d, int len, bool mf, int e);
|
||||||
|
typedef void (*mms_m_file_op_cb)(int fd, const char *fn, int e);
|
||||||
|
typedef void (*mms_m_server_cb)(int fd, const char *vendor, const char *model, const char *rev, int log_st, int phy_st, int e);
|
||||||
|
typedef void (*mms_m_sg_cb)(int fd, const char *ld, int act_sg, int num_sg, int e);
|
||||||
|
|
||||||
|
int mms_m_read_file(int fd, const char *rf, mms_m_file_read_cb cb);
|
||||||
|
int mms_m_delete_file(int fd, const char *rf, mms_m_file_op_cb cb);
|
||||||
|
int mms_m_query_server(int fd, mms_m_server_cb cb);
|
||||||
|
int mms_m_read_sg_info(int fd, const char *ld, mms_m_sg_cb cb);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -187,3 +187,5 @@ typedef struct
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void *mms_m_get_obj(int app_fd);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
/**
|
||||||
|
* @file mms_m_ext.h
|
||||||
|
* @brief MMS 客户端扩展功能接口声明
|
||||||
|
*
|
||||||
|
* @details 本文件声明文件服务、服务器信息查询、定值组操作等扩展功能。
|
||||||
|
* 回调类型定义见 myMms_m.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "myMms_m.h"
|
||||||
|
#include "mms_m.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从远端 IED 读取文件
|
||||||
|
*
|
||||||
|
* 通过 MMS 文件服务 (ObtainFile) 从服务器下载指定文件。
|
||||||
|
* 文件内容通过回调分块返回。
|
||||||
|
*
|
||||||
|
* @param app_fd 客户端连接句柄
|
||||||
|
* @param rf 远端文件路径
|
||||||
|
* @param cb 文件读取回调,分块返回文件数据
|
||||||
|
* @return 0 成功发起请求,-1 参数无效或对象不存在
|
||||||
|
*/
|
||||||
|
int mms_m_read_file(int app_fd, const char *rf, mms_m_file_read_cb cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除远端 IED 上的文件
|
||||||
|
*
|
||||||
|
* @param app_fd 客户端连接句柄
|
||||||
|
* @param rf 远端文件路径
|
||||||
|
* @param cb 操作结果回调
|
||||||
|
* @return 0 成功,-1 参数无效或对象不存在
|
||||||
|
*/
|
||||||
|
int mms_m_delete_file(int app_fd, const char *rf, mms_m_file_op_cb cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询远端 IED 的服务器身份和运行状态
|
||||||
|
*
|
||||||
|
* 同时获取 MMS identify 服务返回的厂商/型号/版本信息,
|
||||||
|
* 以及 VMD 逻辑状态和物理状态。
|
||||||
|
*
|
||||||
|
* @param app_fd 客户端连接句柄
|
||||||
|
* @param cb 查询结果回调
|
||||||
|
* @return 0 成功,-1 参数无效或对象不存在
|
||||||
|
*/
|
||||||
|
int mms_m_query_server(int app_fd, mms_m_server_cb cb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取远端 IED 的定值组信息
|
||||||
|
*
|
||||||
|
* 通过 SGCB 获取当前激活定值组号和定值组总数。
|
||||||
|
*
|
||||||
|
* @param app_fd 客户端连接句柄
|
||||||
|
* @param ld 逻辑设备名(如 "PROT")
|
||||||
|
* @param cb 查询结果回调
|
||||||
|
* @return 0 成功,-1 参数无效或对象不存在
|
||||||
|
*/
|
||||||
|
int mms_m_read_sg_info(int app_fd, const char *ld, mms_m_sg_cb cb);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -336,6 +336,19 @@ static int mms_m_send_ao_write(stru_mms_m_obj &obj, stru_mms_m_event &event)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void demo_sg_cb(int fd, const char *ld_name,
|
||||||
|
int act_sg, int num_sg, int err)
|
||||||
|
{
|
||||||
|
if (IED_ERROR_OK != err)
|
||||||
|
{
|
||||||
|
LOG_E("read SG info failed: %s, err=%d", ld_name, err);
|
||||||
|
/** 定值组信息读取回调 */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_I("%s: active SG=%d, total SG=%d", ld_name, act_sg, num_sg);
|
||||||
|
}
|
||||||
|
|
||||||
static int mms_m_send_param_write(stru_mms_m_obj &obj, stru_mms_m_event &event)
|
static int mms_m_send_param_write(stru_mms_m_obj &obj, stru_mms_m_event &event)
|
||||||
{
|
{
|
||||||
stru_point_item *p_item = NULL;
|
stru_point_item *p_item = NULL;
|
||||||
|
|
@ -356,6 +369,8 @@ static int mms_m_send_param_write(stru_mms_m_obj &obj, stru_mms_m_event &event)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mms_m_read_sg_info(obj.obj_fd, p_item->ldev, demo_sg_cb);
|
||||||
|
|
||||||
std::string ref = p_item->reference;
|
std::string ref = p_item->reference;
|
||||||
size_t pos = ref.find("/");
|
size_t pos = ref.find("/");
|
||||||
if(pos == std::string::npos)
|
if(pos == std::string::npos)
|
||||||
|
|
@ -955,18 +970,8 @@ static int mms_m_get_MmsValue(stru_point_value &point_value, stru_mms_m_out_valu
|
||||||
tm_flag = 1;
|
tm_flag = 1;
|
||||||
break;
|
break;
|
||||||
case MMS_BIT_STRING:
|
case MMS_BIT_STRING:
|
||||||
point_value.quality = 0;
|
out_val.type = MMS_BIT_STRING;
|
||||||
for (int i = 0; i < MmsValue_getBitStringSize(p_mms_values); i++)
|
*(uint32_t *)p_val = MmsValue_getBitStringAsIntegerBigEndian(p_mms_values);
|
||||||
{
|
|
||||||
if (MmsValue_getBitStringBit(p_mms_values, i))
|
|
||||||
{
|
|
||||||
point_value.quality |= (1 << i);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
point_value.quality &= ~(1 << i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -1477,7 +1482,8 @@ static void mms_m_do_comm(stru_mms_m_obj &obj)
|
||||||
|
|
||||||
if(IED_STATE_CONNECTED != run.con_state && IED_STATE_CONNECTED == run.old_con_state)
|
if(IED_STATE_CONNECTED != run.con_state && IED_STATE_CONNECTED == run.old_con_state)
|
||||||
{
|
{
|
||||||
LOG_I("mms_m %s connected %s:%d offline", obj.ied_name.c_str(), obj.run.ip.c_str(), obj.run.port);
|
LOG_I("mms_m %s connected %s:%d offline, reset RCB subscription", obj.ied_name.c_str(), obj.run.ip.c_str(), obj.run.port);
|
||||||
|
obj.run.running_init = false;
|
||||||
|
|
||||||
if(run.out_status_cb)
|
if(run.out_status_cb)
|
||||||
{
|
{
|
||||||
|
|
@ -1803,6 +1809,11 @@ static int mms_m_ied_init(stru_mms_m_obj &obj)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void *mms_m_get_obj(int app_fd){
|
||||||
|
auto it = g_mms_m_obj_map.find(app_fd);
|
||||||
|
return (it != g_mms_m_obj_map.end()) ? (void*)it->second : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int mms_m_out_init(stru_cfg *p_cfg, int debug_print_flag, uint32_t connectionTimeout)
|
int mms_m_out_init(stru_cfg *p_cfg, int debug_print_flag, uint32_t connectionTimeout)
|
||||||
{
|
{
|
||||||
if(NULL == p_cfg)
|
if(NULL == p_cfg)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
/**
|
||||||
|
* @file mms_m_file.cpp
|
||||||
|
* @brief MMS 文件服务客户端实现
|
||||||
|
*
|
||||||
|
* @details 基于 libiec61850 MmsConnection 底层接口实现:
|
||||||
|
* - 远端文件读取 (ObtainFile)
|
||||||
|
* - 远端文件删除
|
||||||
|
*
|
||||||
|
* 文件读取流程:
|
||||||
|
* 1. MmsConnection_fileOpen() 打开远端文件,获取文件大小
|
||||||
|
* 2. MmsConnection_fileRead() 循环分块读取文件内容
|
||||||
|
* 3. MmsConnection_fileClose() 关闭文件句柄
|
||||||
|
* 4. 通过回调将完整文件数据返回上层
|
||||||
|
*
|
||||||
|
* 【当前状态】文件打开已验证,异步分块读取待实现。
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "myMms_m.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "mms_m.h"
|
||||||
|
#include "mms_m_ext.h"
|
||||||
|
#include "iec61850_client.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从远端 IED 读取文件
|
||||||
|
*
|
||||||
|
* 打开远端文件并获取文件大小。完整的分块异步读取流程待实现。
|
||||||
|
*
|
||||||
|
* @param app_fd 客户端连接句柄
|
||||||
|
* @param rf 远端文件路径
|
||||||
|
* @param cb 文件读取回调,分块返回文件数据
|
||||||
|
* @return 0 成功发起请求,-1 失败
|
||||||
|
*/
|
||||||
|
int mms_m_read_file(int app_fd, const char *rf, mms_m_file_read_cb cb)
|
||||||
|
{
|
||||||
|
if (NULL == rf || NULL == cb)
|
||||||
|
{
|
||||||
|
LOG_E("Invalid parameter, rf %p, cb %p", rf, cb);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
stru_mms_m_obj *p_obj = (stru_mms_m_obj *)mms_m_get_obj(app_fd);
|
||||||
|
if (NULL == p_obj)
|
||||||
|
{
|
||||||
|
LOG_E("app_fd %d not found", app_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 获取底层 MmsConnection 以使用文件服务 API */
|
||||||
|
MmsConnection mc = IedConnection_getMmsConnection(p_obj->run.con);
|
||||||
|
if (NULL == mc)
|
||||||
|
{
|
||||||
|
LOG_E("%s: getMmsConnection failed", p_obj->cfg_path.c_str());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MmsError me;
|
||||||
|
uint32_t file_size = 0;
|
||||||
|
uint64_t last_modified = 0;
|
||||||
|
|
||||||
|
/* 打开远端文件,获取大小和修改时间 */
|
||||||
|
int32_t frsm_id = MmsConnection_fileOpen(mc, &me, rf, 0,
|
||||||
|
&file_size, &last_modified);
|
||||||
|
|
||||||
|
if (MMS_ERROR_NONE != me)
|
||||||
|
{
|
||||||
|
LOG_E("%s: fileOpen(%s) failed: %d",
|
||||||
|
p_obj->cfg_path.c_str(), rf, me);
|
||||||
|
cb(app_fd, rf, NULL, 0, false, IED_ERROR_UNKNOWN);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_I("%s: file %s opened, size=%u, lastModified=%lu",
|
||||||
|
p_obj->cfg_path.c_str(), rf, file_size, last_modified);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: 实现异步分块读取
|
||||||
|
*
|
||||||
|
* 需要:
|
||||||
|
* 1. 分配接收缓冲区 (malloc file_size)
|
||||||
|
* 2. 循环调用 MmsConnection_fileReadAsync() 读取数据块
|
||||||
|
* 3. 在 read_cb 回调中追加数据到缓冲区
|
||||||
|
* 4. moreFollows=false 时说明读取完毕,调用上层回调
|
||||||
|
* 5. 读取完毕或出错时 MmsConnection_fileClose()
|
||||||
|
*/
|
||||||
|
MmsConnection_fileClose(mc, &me, frsm_id);
|
||||||
|
|
||||||
|
cb(app_fd, rf, NULL, 0, false, IED_ERROR_SERVICE_NOT_IMPLEMENTED);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除远端 IED 上的文件
|
||||||
|
*
|
||||||
|
* @param app_fd 客户端连接句柄
|
||||||
|
* @param rf 远端文件路径
|
||||||
|
* @param cb 操作结果回调,err==0 表示删除成功
|
||||||
|
* @return 0 成功,-1 失败
|
||||||
|
*/
|
||||||
|
int mms_m_delete_file(int app_fd, const char *rf, mms_m_file_op_cb cb)
|
||||||
|
{
|
||||||
|
if (NULL == rf || NULL == cb)
|
||||||
|
{
|
||||||
|
LOG_E("Invalid parameter, rf %p, cb %p", rf, cb);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
stru_mms_m_obj *p_obj = (stru_mms_m_obj *)mms_m_get_obj(app_fd);
|
||||||
|
if (NULL == p_obj)
|
||||||
|
{
|
||||||
|
LOG_E("app_fd %d not found", app_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MmsConnection mc = IedConnection_getMmsConnection(p_obj->run.con);
|
||||||
|
MmsError me;
|
||||||
|
|
||||||
|
MmsConnection_fileDelete(mc, &me, rf);
|
||||||
|
|
||||||
|
IedClientError ie = (MMS_ERROR_NONE == me) ? IED_ERROR_OK
|
||||||
|
: IED_ERROR_UNKNOWN;
|
||||||
|
cb(app_fd, rf, ie);
|
||||||
|
|
||||||
|
return (MMS_ERROR_NONE == me) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
* @file mms_m_server.cpp
|
||||||
|
* @brief 远端 IED 服务器信息查询
|
||||||
|
*
|
||||||
|
* @details 通过 MMS identify 和 getServerStatus 服务获取:
|
||||||
|
* - 厂商名称 (vendorName)
|
||||||
|
* - 型号名称 (modelName)
|
||||||
|
* - 版本号 (revision)
|
||||||
|
* - VMD 逻辑状态 (0=允许变更, 1=禁止变更, 2=受限, 3=支持服务)
|
||||||
|
* - VMD 物理状态 (0=运行, 1=部分, 2=停运, 3=待调试)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "myMms_m.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mms_m.h"
|
||||||
|
#include "mms_m_ext.h"
|
||||||
|
#include "iec61850_client.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询远端 IED 的服务器身份和运行状态
|
||||||
|
*
|
||||||
|
* 同时获取 MMS identify 和 getServerStatus 的结果,
|
||||||
|
* 通过回调一次性返回。
|
||||||
|
*
|
||||||
|
* @param app_fd 客户端连接句柄
|
||||||
|
* @param cb 查询结果回调
|
||||||
|
* @return 0 成功,-1 失败
|
||||||
|
*/
|
||||||
|
int mms_m_query_server(int app_fd, mms_m_server_cb cb)
|
||||||
|
{
|
||||||
|
if (NULL == cb)
|
||||||
|
{
|
||||||
|
LOG_E("cb is NULL");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
stru_mms_m_obj *p_obj = (stru_mms_m_obj *)mms_m_get_obj(app_fd);
|
||||||
|
if (NULL == p_obj)
|
||||||
|
{
|
||||||
|
LOG_E("app_fd %d not found", app_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MmsConnection mc = IedConnection_getMmsConnection(p_obj->run.con);
|
||||||
|
MmsError me;
|
||||||
|
|
||||||
|
/* MMS identify 服务:获取厂商/型号/版本 */
|
||||||
|
MmsServerIdentity *p_id = MmsConnection_identify(mc, &me);
|
||||||
|
|
||||||
|
/* MMS getServerStatus 服务:获取 VMD 运行状态 */
|
||||||
|
int log_st = 0;
|
||||||
|
int phy_st = 0;
|
||||||
|
MmsConnection_getServerStatus(mc, &me, &log_st, &phy_st, false);
|
||||||
|
|
||||||
|
const char *vendor = p_id ? p_id->vendorName : "";
|
||||||
|
const char *model = p_id ? p_id->modelName : "";
|
||||||
|
const char *rev = p_id ? p_id->revision : "";
|
||||||
|
|
||||||
|
IedClientError err = (MMS_ERROR_NONE != me) ? IED_ERROR_UNKNOWN
|
||||||
|
: IED_ERROR_OK;
|
||||||
|
|
||||||
|
cb(app_fd, vendor, model, rev, log_st, phy_st, err);
|
||||||
|
|
||||||
|
if (p_id)
|
||||||
|
{
|
||||||
|
MmsServerIdentity_destroy(p_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
/**
|
||||||
|
* @file mms_m_sg.cpp
|
||||||
|
* @brief 远端 IED 定值组 (Setting Group) 操作
|
||||||
|
*
|
||||||
|
* @details 定值组允许 IED 维护多套运行参数并可在线切换。
|
||||||
|
* 本模块通过 LLN0.SGCB 读取当前定值组状态。
|
||||||
|
*
|
||||||
|
* SGCB (Setting Group Control Block) 关键属性:
|
||||||
|
* - ActSG : 当前激活的定值组号
|
||||||
|
* - NumOfSG: 定值组总数
|
||||||
|
* - EditSG : 当前编辑的定值组号
|
||||||
|
*
|
||||||
|
* 后续可扩展:
|
||||||
|
* - 切换激活定值组 (Write ActSG)
|
||||||
|
* - 编辑确认 (Write CnfEdit)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "myMms_m.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mms_m.h"
|
||||||
|
#include "mms_m_ext.h"
|
||||||
|
#include "iec61850_client.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取远端 IED 的定值组信息
|
||||||
|
*
|
||||||
|
* 通过读取 LLN0.SGCB 获取当前激活定值组号和定值组总数。
|
||||||
|
* 读取失败时返回默认值 act_sg=1, num_sg=1。
|
||||||
|
*
|
||||||
|
* @param app_fd 客户端连接句柄
|
||||||
|
* @param ld 逻辑设备名(如 "PROT"、"CTRL")
|
||||||
|
* @param cb 查询结果回调
|
||||||
|
* @return 0 成功,-1 失败
|
||||||
|
*/
|
||||||
|
int mms_m_read_sg_info(int app_fd, const char *ld, mms_m_sg_cb cb)
|
||||||
|
{
|
||||||
|
if (NULL == ld || NULL == cb)
|
||||||
|
{
|
||||||
|
LOG_E("Invalid parameter, ld %p, cb %p", ld, cb);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
stru_mms_m_obj *p_obj = (stru_mms_m_obj *)mms_m_get_obj(app_fd);
|
||||||
|
if (NULL == p_obj)
|
||||||
|
{
|
||||||
|
LOG_E("app_fd %d not found", app_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int act_sg = 1;
|
||||||
|
int num_sg = 1;
|
||||||
|
IedClientError err = IED_ERROR_OK;
|
||||||
|
|
||||||
|
/* 拼接 SGCB 对象引用:{LD}/LLN0.SGCB */
|
||||||
|
char sgcbref[256];
|
||||||
|
snprintf(sgcbref, sizeof(sgcbref), "%s/LLN0.SGCB", ld);
|
||||||
|
|
||||||
|
/* 读取 SGCB 的 FC=ST 属性(包含 ActSG, NumOfSG, EditSG) */
|
||||||
|
MmsValue *p_val = IedConnection_readObject(p_obj->run.con, &err,
|
||||||
|
sgcbref, IEC61850_FC_ST);
|
||||||
|
|
||||||
|
if (p_val && IED_ERROR_OK == err)
|
||||||
|
{
|
||||||
|
MmsValue *p_act = MmsValue_getElement(p_val, 0);
|
||||||
|
MmsValue *p_num = MmsValue_getElement(p_val, 1);
|
||||||
|
|
||||||
|
if (p_act)
|
||||||
|
{
|
||||||
|
act_sg = MmsValue_toInt32(p_act);
|
||||||
|
}
|
||||||
|
if (p_num)
|
||||||
|
{
|
||||||
|
num_sg = MmsValue_toInt32(p_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
MmsValue_delete(p_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(app_fd, ld, act_sg, num_sg, err);
|
||||||
|
|
||||||
|
return (IED_ERROR_OK == err) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
@ -21,4 +21,17 @@
|
||||||
* @param icd ICD 数据结构引用
|
* @param icd ICD 数据结构引用
|
||||||
* @return 0 成功,-1 失败
|
* @return 0 成功,-1 失败
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联锁检查回调类型
|
||||||
|
* @param saddr 控制点短地址
|
||||||
|
* @param state 请求的状态值
|
||||||
|
* @return true 允许操作,false 拒绝
|
||||||
|
*/
|
||||||
|
typedef bool (*mms_s_interlock_cb)(const char *saddr, int state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置联锁检查回调
|
||||||
|
*/
|
||||||
|
void mms_s_set_interlock_cb(mms_s_interlock_cb cb);
|
||||||
int control_init(IedServer server, stru_icd &icd);
|
int control_init(IedServer server, stru_icd &icd);
|
||||||
|
|
@ -462,6 +462,8 @@ typedef struct
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
ModelNode *node;
|
ModelNode *node;
|
||||||
|
DataAttribute *da_t;
|
||||||
|
DataAttribute *da_q;
|
||||||
}stru_saddr_point;
|
}stru_saddr_point;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -43,10 +43,12 @@ LOCAL IedServer gp_iedServer = NULL;
|
||||||
/* 调试输出开关 */
|
/* 调试输出开关 */
|
||||||
LOCAL bool g_dbg_switch = false;
|
LOCAL bool g_dbg_switch = false;
|
||||||
|
|
||||||
/** SIGINT 信号处理:通知后台线程退出 */
|
|
||||||
/* RCB event handler for monitoring client report subscriptions */
|
/* RCB event handler for monitoring client report subscriptions */
|
||||||
LOCAL void rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError)
|
LOCAL void rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError)
|
||||||
{
|
{
|
||||||
|
if(mms_s_dbg_get())
|
||||||
|
{
|
||||||
const char* name = ReportControlBlock_getName(rcb);
|
const char* name = ReportControlBlock_getName(rcb);
|
||||||
char* rptId = ReportControlBlock_getRptID(rcb);
|
char* rptId = ReportControlBlock_getRptID(rcb);
|
||||||
char* dataSet = ReportControlBlock_getDataSet(rcb);
|
char* dataSet = ReportControlBlock_getDataSet(rcb);
|
||||||
|
|
@ -58,19 +60,29 @@ LOCAL void rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConne
|
||||||
case RCB_EVENT_UNRESERVED:LOG_I("RCB %s UNRESERVED", name); break;
|
case RCB_EVENT_UNRESERVED:LOG_I("RCB %s UNRESERVED", name); break;
|
||||||
case RCB_EVENT_GI: LOG_I("RCB %s GI triggered", name); break;
|
case RCB_EVENT_GI: LOG_I("RCB %s GI triggered", name); break;
|
||||||
case RCB_EVENT_SET_PARAMETER:
|
case RCB_EVENT_SET_PARAMETER:
|
||||||
LOG_I("RCB %s SET param=%s err=%d trigOps=0x%x (before)", name, parameterName ? parameterName : "?", serviceError, rcb->trgOps);
|
if (serviceError != DATA_ACCESS_ERROR_SUCCESS)
|
||||||
if (parameterName && strcmp(parameterName, "TrgOps") == 0) {
|
{
|
||||||
|
LOG_E("RCB %s SET param=%s FAILED err=%d", name, parameterName ? parameterName : "?", serviceError);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_I("RCB %s SET param=%s OK trigOps=0x%x", name, parameterName ? parameterName : "?", rcb->trgOps);
|
||||||
|
if (parameterName && strcmp(parameterName, "TrgOps") == 0)
|
||||||
|
{
|
||||||
rcb->trgOps |= 0x01;
|
rcb->trgOps |= 0x01;
|
||||||
LOG_I("RCB %s forced dchg, trigOps=0x%x", name, rcb->trgOps);
|
LOG_I("RCB %s forced dchg, trigOps=0x%x", name, rcb->trgOps);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case RCB_EVENT_GET_PARAMETER: LOG_I("RCB %s GET param=%s err=%d", name, parameterName ? parameterName : "?", serviceError); break;
|
case RCB_EVENT_GET_PARAMETER: LOG_I("RCB %s GET param=%s err=%d", name, parameterName ? parameterName : "?", serviceError); break;
|
||||||
default: LOG_I("RCB %s event=%d", name, event); break;
|
default: LOG_I("RCB %s event=%d", name, event); break;
|
||||||
}
|
}
|
||||||
free(rptId);
|
free(rptId);
|
||||||
free(dataSet);
|
free(dataSet);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** SIGINT 信号处理:通知后台线程退出 */
|
||||||
LOCAL void sigint_handler(int signum)
|
LOCAL void sigint_handler(int signum)
|
||||||
{
|
{
|
||||||
g_running = 0;
|
g_running = 0;
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,14 @@
|
||||||
LOCAL std::vector<stru_mms_s_control> g_vec_control;
|
LOCAL std::vector<stru_mms_s_control> g_vec_control;
|
||||||
/** 控制操作回调函数 */
|
/** 控制操作回调函数 */
|
||||||
LOCAL mms_s_control_cb cb_control = NULL;
|
LOCAL mms_s_control_cb cb_control = NULL;
|
||||||
|
/** 联锁检查回调 */
|
||||||
|
LOCAL mms_s_interlock_cb cb_interlock = NULL;
|
||||||
|
|
||||||
|
void mms_s_set_interlock_cb(mms_s_interlock_cb cb)
|
||||||
|
{
|
||||||
|
cb_interlock = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 控制操作处理器(Operate 阶段)
|
* 控制操作处理器(Operate 阶段)
|
||||||
|
|
@ -287,7 +295,7 @@ int control_init(IedServer server, stru_icd &icd)
|
||||||
|
|
||||||
if(g_vec_control.empty())
|
if(g_vec_control.empty())
|
||||||
{
|
{
|
||||||
LOG_E("g_vec_control is empty");
|
LOG_I("g_vec_control is empty, no controls registered");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -812,6 +812,24 @@ LOCAL int model_ldevice_init(IedModel *model, stru_icd &icd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOCAL void find_tq_for_da(DataAttribute *da, DataAttribute* *t, DataAttribute* *q)
|
||||||
|
{
|
||||||
|
*t = NULL;
|
||||||
|
*q = NULL;
|
||||||
|
if (!da) return;
|
||||||
|
ModelNode *parent = da->parent;
|
||||||
|
while (parent && parent->modelType != DataObjectModelType)
|
||||||
|
parent = parent->parent;
|
||||||
|
if (parent && parent->modelType == DataObjectModelType) {
|
||||||
|
DataAttribute *child = (DataAttribute *)parent->firstChild;
|
||||||
|
while (child) {
|
||||||
|
if (strcmp(child->name, "t") == 0) *t = child;
|
||||||
|
else if (strcmp(child->name, "q") == 0) *q = child;
|
||||||
|
child = (DataAttribute *)child->sibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 SDI 中的 DAI 默认值(sAddr / val)同步到模型树中的 all_DA 节点
|
* 将 SDI 中的 DAI 默认值(sAddr / val)同步到模型树中的 all_DA 节点
|
||||||
*
|
*
|
||||||
|
|
@ -907,6 +925,7 @@ void model_sync_da_default_values(stru_icd &icd, stru_SDI &SDI_item, stru_all_DA
|
||||||
p_all_da_se_temp->DA->sAddr = StringUtils_copyString(saddr.c_str());
|
p_all_da_se_temp->DA->sAddr = StringUtils_copyString(saddr.c_str());
|
||||||
icd.ied.vec_saddr.push_back(saddr);
|
icd.ied.vec_saddr.push_back(saddr);
|
||||||
icd.ied.map_saddr_point[saddr].node = (ModelNode *)p_all_da_se_temp->DA;
|
icd.ied.map_saddr_point[saddr].node = (ModelNode *)p_all_da_se_temp->DA;
|
||||||
|
find_tq_for_da(p_all_da_se_temp->DA, &icd.ied.map_saddr_point[saddr].da_t, &icd.ied.map_saddr_point[saddr].da_q);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1021,7 +1040,8 @@ void model_sync_ln_default_values(stru_icd &icd, std::map<std::string, stru_DOI>
|
||||||
|
|
||||||
p_all_da->DA->sAddr = StringUtils_copyString(saddr.c_str()); // 写入模型节点
|
p_all_da->DA->sAddr = StringUtils_copyString(saddr.c_str()); // 写入模型节点
|
||||||
icd.ied.vec_saddr.push_back(saddr); // 加入列表
|
icd.ied.vec_saddr.push_back(saddr); // 加入列表
|
||||||
icd.ied.map_saddr_point[saddr].node = (ModelNode *)p_all_da->DA; // 建立映射
|
icd.ied.map_saddr_point[saddr].node = (ModelNode *)p_all_da->DA;
|
||||||
|
find_tq_for_da(p_all_da->DA, &icd.ied.map_saddr_point[saddr].da_t, &icd.ied.map_saddr_point[saddr].da_q); // 建立映射
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -313,6 +313,8 @@ LOCAL bool param_edit_sg_changed_handler(void* parameter, SettingGroupControlBlo
|
||||||
* @param max 输出:最大值
|
* @param max 输出:最大值
|
||||||
* @param step 输出:步长
|
* @param step 输出:步长
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* TODO: 与 mms_s_setting.cpp 中的校验函数重复,建议抽取到公共模块 */
|
||||||
LOCAL void param_min_max_step_get(DataAttribute *node, float &min, float &max, float &step)
|
LOCAL void param_min_max_step_get(DataAttribute *node, float &min, float &max, float &step)
|
||||||
{
|
{
|
||||||
if(node == NULL)
|
if(node == NULL)
|
||||||
|
|
@ -465,12 +467,12 @@ LOCAL void param_get_INT(DataAttribute *node_SE, DataAttribute *node_SG, std::st
|
||||||
float min, max, step;
|
float min, max, step;
|
||||||
param_min_max_step_get(node_SG, min, max, step);
|
param_min_max_step_get(node_SG, min, max, step);
|
||||||
|
|
||||||
|
int intVal = MmsValue_toInt32(node_SE->mmsValue);
|
||||||
if((int)step == 0)
|
if((int)step == 0)
|
||||||
{
|
{
|
||||||
|
val = std::to_string(intVal);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int intVal = MmsValue_toInt32(node_SE->mmsValue);
|
|
||||||
if(intVal < (int)min || intVal > (int)max)
|
if(intVal < (int)min || intVal > (int)max)
|
||||||
{
|
{
|
||||||
LOG_E("Value %d is out of range [%d, %d]", intVal, (int)min, (int)max);
|
LOG_E("Value %d is out of range [%d, %d]", intVal, (int)min, (int)max);
|
||||||
|
|
@ -499,12 +501,12 @@ LOCAL void param_get_UINT(DataAttribute *node_SE, DataAttribute *node_SG, std::s
|
||||||
float min, max, step;
|
float min, max, step;
|
||||||
param_min_max_step_get(node_SG, min, max, step);
|
param_min_max_step_get(node_SG, min, max, step);
|
||||||
|
|
||||||
|
int uintVal = MmsValue_toUint32(node_SE->mmsValue);
|
||||||
if((uint32_t)step == 0)
|
if((uint32_t)step == 0)
|
||||||
{
|
{
|
||||||
|
val = std::to_string(uintVal);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int uintVal = MmsValue_toUint32(node_SE->mmsValue);
|
|
||||||
if(uintVal < (uint32_t)min || uintVal > (uint32_t)max)
|
if(uintVal < (uint32_t)min || uintVal > (uint32_t)max)
|
||||||
{
|
{
|
||||||
LOG_E("Value %d is out of range [%d, %d]", uintVal, (uint32_t)min, (uint32_t)max);
|
LOG_E("Value %d is out of range [%d, %d]", uintVal, (uint32_t)min, (uint32_t)max);
|
||||||
|
|
@ -542,13 +544,9 @@ LOCAL void param_get_FLOAT(DataAttribute *node_SE, DataAttribute *node_SG, std::
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fabs(step) < EPSILON)
|
|
||||||
{
|
|
||||||
val = std::to_string(floatVal);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float gap = floatVal - min;
|
float gap = floatVal - min;
|
||||||
|
if(fabs(step) > EPSILON)
|
||||||
|
{
|
||||||
float gap_mod = fmod(gap, step);
|
float gap_mod = fmod(gap, step);
|
||||||
|
|
||||||
if(fabs(gap_mod) > EPSILON && fabs(gap_mod - step) > EPSILON)
|
if(fabs(gap_mod) > EPSILON && fabs(gap_mod - step) > EPSILON)
|
||||||
|
|
@ -556,6 +554,7 @@ LOCAL void param_get_FLOAT(DataAttribute *node_SE, DataAttribute *node_SG, std::
|
||||||
LOG_E("Value %f does not conform to step size %f", floatVal, step);
|
LOG_E("Value %f does not conform to step size %f", floatVal, step);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val = std::to_string(floatVal);
|
val = std::to_string(floatVal);
|
||||||
}
|
}
|
||||||
|
|
@ -704,7 +703,7 @@ LOCAL void param_values_show()
|
||||||
{
|
{
|
||||||
if(g_vec_params.empty())
|
if(g_vec_params.empty())
|
||||||
{
|
{
|
||||||
LOG_E("g_vec_params is empty");
|
LOG_I("g_vec_params is empty, no params registered");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -766,7 +765,7 @@ int param_init(IedServer server, stru_icd &icd)
|
||||||
{
|
{
|
||||||
if(g_vec_params.empty())
|
if(g_vec_params.empty())
|
||||||
{
|
{
|
||||||
LOG_E("g_vec_params is empty");
|
LOG_I("g_vec_params is empty, no params registered");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -286,11 +286,6 @@ LOCAL int setting_get_INT(DataAttribute *node, MmsValue* value, std::string &val
|
||||||
float min, max, step;
|
float min, max, step;
|
||||||
setting_min_max_step_get(node, min, max, step);
|
setting_min_max_step_get(node, min, max, step);
|
||||||
|
|
||||||
if((int)step == 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int intVal = MmsValue_toInt32(value);
|
int intVal = MmsValue_toInt32(value);
|
||||||
if(intVal < (int)min || intVal > (int)max)
|
if(intVal < (int)min || intVal > (int)max)
|
||||||
{
|
{
|
||||||
|
|
@ -322,11 +317,6 @@ LOCAL int setting_get_UINT(DataAttribute *node, MmsValue* value, std::string &va
|
||||||
float min, max, step;
|
float min, max, step;
|
||||||
setting_min_max_step_get(node, min, max, step);
|
setting_min_max_step_get(node, min, max, step);
|
||||||
|
|
||||||
if((uint32_t)step == 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int uintVal = MmsValue_toUint32(value);
|
int uintVal = MmsValue_toUint32(value);
|
||||||
if(uintVal < (uint32_t)min || uintVal > (uint32_t)max)
|
if(uintVal < (uint32_t)min || uintVal > (uint32_t)max)
|
||||||
{
|
{
|
||||||
|
|
@ -367,12 +357,9 @@ LOCAL int setting_get_FLOAT(DataAttribute *node, MmsValue* value, std::string &v
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fabs(step) < EPSILON)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float gap = floatVal - min;
|
float gap = floatVal - min;
|
||||||
|
if(fabs(step) > EPSILON)
|
||||||
|
{
|
||||||
float gap_mod = fmod(gap, step);
|
float gap_mod = fmod(gap, step);
|
||||||
|
|
||||||
if(fabs(gap_mod) > EPSILON && fabs(gap_mod - step) > EPSILON)
|
if(fabs(gap_mod) > EPSILON && fabs(gap_mod - step) > EPSILON)
|
||||||
|
|
@ -380,6 +367,7 @@ LOCAL int setting_get_FLOAT(DataAttribute *node, MmsValue* value, std::string &v
|
||||||
LOG_E("Value %f does not conform to step size %f", floatVal, step);
|
LOG_E("Value %f does not conform to step size %f", floatVal, step);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LOG_I("Float value for node %s is %f", node->name, floatVal);
|
LOG_I("Float value for node %s is %f", node->name, floatVal);
|
||||||
val_str = std::to_string(floatVal);
|
val_str = std::to_string(floatVal);
|
||||||
|
|
@ -597,7 +585,7 @@ int setting_init(IedServer server, stru_icd &icd)
|
||||||
{
|
{
|
||||||
if(g_vec_settings.empty())
|
if(g_vec_settings.empty())
|
||||||
{
|
{
|
||||||
LOG_E("g_vec_settings is empty");
|
LOG_I("g_vec_settings is empty, no settings registered");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -353,13 +353,34 @@ LOCAL void mms_s_da_value_init_Unicode_String(DataAttribute *da, std::string val
|
||||||
/** 初始化 Timestamp:设为当前毫秒时间 */
|
/** 初始化 Timestamp:设为当前毫秒时间 */
|
||||||
LOCAL void mms_s_da_value_init_Timestamp(DataAttribute *da, std::string val)
|
LOCAL void mms_s_da_value_init_Timestamp(DataAttribute *da, std::string val)
|
||||||
{
|
{
|
||||||
if(NULL == da || val.empty())
|
if(NULL == da) return;
|
||||||
|
da->mmsValue = MmsValue_newUtcTimeByMsTime(Hal_getTimeInMs());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOCAL std::string get_DA_path(ModelNode *node)
|
||||||
|
{
|
||||||
|
std::string str_temp = "";
|
||||||
|
if(NULL == node)
|
||||||
{
|
{
|
||||||
LOG_E("da or val is empty, da %p, val %s", da, val.c_str());
|
return str_temp;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
da->mmsValue = MmsValue_newUtcTimeByMsTime(Hal_getTimeInMs());
|
str_temp = node->name ? node->name : "?";
|
||||||
|
ModelNode *temp_node = node->parent; // 向上遍历父节点
|
||||||
|
|
||||||
|
while(temp_node) // 逐级拼装完整路径
|
||||||
|
{
|
||||||
|
str_temp = std::string(temp_node->name ? temp_node->name : "?") + "." + str_temp; // parent.name + "." + 当前路径
|
||||||
|
|
||||||
|
if(temp_node->modelType == LogicalDeviceModelType) // 到达逻辑设备层则停止
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
temp_node = temp_node->parent; // 继续向上一级
|
||||||
|
}
|
||||||
|
|
||||||
|
return str_temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -368,19 +389,12 @@ LOCAL void mms_s_da_value_init_Timestamp(DataAttribute *da, std::string val)
|
||||||
*/
|
*/
|
||||||
LOCAL void mms_s_da_value_init_Dbpos(DataAttribute *da, std::string val)
|
LOCAL void mms_s_da_value_init_Dbpos(DataAttribute *da, std::string val)
|
||||||
{
|
{
|
||||||
if(NULL == da || val.empty())
|
if(NULL == da) return;
|
||||||
{
|
|
||||||
LOG_E("da or val is empty, da %p, val %s", da, val.c_str());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dbpos pos = DBPOS_INTERMEDIATE_STATE;
|
Dbpos pos = DBPOS_INTERMEDIATE_STATE;
|
||||||
|
|
||||||
if(val == "")
|
|
||||||
{
|
if(!val.empty())
|
||||||
pos = DBPOS_INTERMEDIATE_STATE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
int i = atoi(val.c_str());
|
int i = atoi(val.c_str());
|
||||||
if(i == 0)
|
if(i == 0)
|
||||||
|
|
@ -405,11 +419,20 @@ LOCAL void mms_s_da_value_init_Dbpos(DataAttribute *da, std::string val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dbpos_toMmsValue(da->mmsValue, pos);
|
IedServer server = mms_s_get_ied_server_ptr();
|
||||||
|
if (server)
|
||||||
if(mms_s_dbg_get())
|
|
||||||
{
|
{
|
||||||
LOG_I("da %s-%s, value %s, pos %d", da->parent->name, da->name, val.c_str(), pos);
|
IedServer_updateDbposValue(server, da, pos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
da->mmsValue = Dbpos_toMmsValue(NULL, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(mms_s_dbg_get())
|
||||||
|
{
|
||||||
|
MmsType val_type = MmsValue_getType(da->mmsValue);
|
||||||
|
LOG_I("da %s-%s, value %s, pos %d, type %d, path %s", da->parent->name, da->name, val.c_str(), pos, val_type, get_DA_path((ModelNode *)da).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -477,7 +500,7 @@ LOCAL void mms_s_da_values_init(stru_icd &icd, std::string da_name, stru_all_DA
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(NULL != g_iec61850s_value_init_cb_map[p_all_da->bType] && !p_all_da->val.empty())
|
if(NULL != g_iec61850s_value_init_cb_map[p_all_da->bType] && (!p_all_da->val.empty() || p_all_da->bType == "Timestamp" || p_all_da->bType == "Quality" || p_all_da->bType == "Dbpos"))
|
||||||
{
|
{
|
||||||
g_iec61850s_value_init_cb_map[p_all_da->bType](p_all_da->DA, p_all_da->val);
|
g_iec61850s_value_init_cb_map[p_all_da->bType](p_all_da->DA, p_all_da->val);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include "parse_xml.h"
|
#include "parse_xml.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
LOCAL void mms_event_back(void *arg, int ret);
|
LOCAL void mms_event_back(void *arg, int ret);
|
||||||
|
|
||||||
LOCAL std::string get_base_path()
|
LOCAL std::string get_base_path()
|
||||||
|
|
@ -177,6 +178,8 @@ LOCAL void mms_data_back(stru_mms_m_out_value *p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOCAL int iec61850m_ext_demo(int fd);
|
||||||
|
|
||||||
LOCAL void iec61850m_connect_status(int fd, int status)
|
LOCAL void iec61850m_connect_status(int fd, int status)
|
||||||
{
|
{
|
||||||
std::string prj_name = "";
|
std::string prj_name = "";
|
||||||
|
|
@ -196,6 +199,11 @@ LOCAL void iec61850m_connect_status(int fd, int status)
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_I("iec61850m_connect_status, fd %d, prj_name %s, status %s", fd, prj_name.c_str(), status == MMS_M_ON_LINE? "ON_LINE" : "OFF_LINE");
|
LOG_I("iec61850m_connect_status, fd %d, prj_name %s, status %s", fd, prj_name.c_str(), status == MMS_M_ON_LINE? "ON_LINE" : "OFF_LINE");
|
||||||
|
|
||||||
|
if (MMS_M_ON_LINE == status)
|
||||||
|
{
|
||||||
|
iec61850m_ext_demo(fd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -588,6 +596,88 @@ int app_iec61850m_init1(void *arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* 新增功能演示回调
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************** * 新增功能演示回调 * 连接上线后由 iec61850m_ext_demo() 调用,演示文件服务、服务器查询、定值组操作 *****************************************************************************/
|
||||||
|
LOCAL void demo_file_read_cb(int fd, const char *filename,
|
||||||
|
const uint8_t *p_data, int data_len, bool more_follows,
|
||||||
|
int err)
|
||||||
|
/** 文件读取回调 */
|
||||||
|
{
|
||||||
|
if (IED_ERROR_OK != err)
|
||||||
|
{
|
||||||
|
LOG_E("file read failed: %s, err=%d", filename, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_I("file %s read %d bytes", filename, data_len);
|
||||||
|
|
||||||
|
/* TODO: 将文件数据写入本地磁盘 */
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCAL void demo_file_delete_cb(int fd, const char *filename, int err)
|
||||||
|
{
|
||||||
|
if (IED_ERROR_OK == err)
|
||||||
|
{
|
||||||
|
/** 文件删除回调 */
|
||||||
|
LOG_I("file %s deleted successfully", filename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_E("file %s delete failed: %d", filename, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCAL void demo_server_query_cb(int fd, const char *vendor,
|
||||||
|
const char *model, const char *revision,
|
||||||
|
int logical_status, int physical_status, int err)
|
||||||
|
{
|
||||||
|
if (IED_ERROR_OK != err)
|
||||||
|
/** 服务器身份和状态查询回调 */
|
||||||
|
{
|
||||||
|
LOG_E("server query failed: %d", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_I("server: vendor=%s, model=%s, rev=%s, log_st=%d, phy_st=%d",
|
||||||
|
vendor, model, revision, logical_status, physical_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCAL void demo_sg_cb(int fd, const char *ld_name,
|
||||||
|
int act_sg, int num_sg, int err)
|
||||||
|
{
|
||||||
|
if (IED_ERROR_OK != err)
|
||||||
|
{
|
||||||
|
LOG_E("read SG info failed: %s, err=%d", ld_name, err);
|
||||||
|
/** 定值组信息读取回调 */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_I("%s: active SG=%d, total SG=%d", ld_name, act_sg, num_sg);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCAL int iec61850m_ext_demo(int fd)
|
||||||
|
{
|
||||||
|
/* 查询服务器信息 */
|
||||||
|
mms_m_query_server(fd, demo_server_query_cb);
|
||||||
|
|
||||||
|
/* 读取定值组信息 */
|
||||||
|
mms_m_read_sg_info(fd, "PROT", demo_sg_cb);
|
||||||
|
/** * 新功能演示入口 * 查询服务器信息、读取定值组状态 */
|
||||||
|
|
||||||
|
/* 删除文件示例 */
|
||||||
|
// mms_m_delete_file(fd, "IEDSERVER.BIN", demo_file_delete_cb);
|
||||||
|
|
||||||
|
/* 读取文件示例 */
|
||||||
|
// mms_m_read_file(fd, "COMTRADE/FAULT01.CFG", demo_file_read_cb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int app_iec61850m_init2(void *arg)
|
int app_iec61850m_init2(void *arg)
|
||||||
{
|
{
|
||||||
static uint32_t *p_iec_run_cnt = NULL;
|
static uint32_t *p_iec_run_cnt = NULL;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue