1、增加信号id属性,在展示或生成文件时,按id排序;
2、61850应用中,数据回调中及时设置信号值
<修改>
1、webserver中调整上送ctrl_type为枚举数值,web_root前端文件中识别枚举展示对应中文;
2、调整mms的配置文件中的短地址
This commit is contained in:
ypc 2026-05-19 20:18:13 +08:00
parent 5e4ab10439
commit 04e16ef7bc
6 changed files with 147 additions and 48 deletions

View File

@ -11,6 +11,7 @@
typedef struct stru_signal
{
uint32_t id;
XXH128_hash_t hash; // 128位哈希
std::string saddr; // 短地址
std::string desc; // 描述

View File

@ -42,6 +42,7 @@ typedef std::unordered_map<XXH128_hash_t, stru_signal, XXH128Hash, XXH128Equal>
typedef struct
{
std::mutex mtx;
uint32_t signal_id;
hash_signal_map map_signals;
std::unordered_map<XXH128_hash_t, std::vector<stru_signal*>, XXH128Hash, XXH128Equal> hash_conflict_table;
std::unordered_map<XXH128_hash_t, std::string, XXH128Hash, XXH128Equal> hash_index;
@ -59,7 +60,7 @@ typedef struct
}stru_datacenter;
static stru_datacenter g_datacenter;
static stru_datacenter g_datacenter = {};
LOCAL bool g_param_cfg_change = false;
LOCAL std::mutex g_param_cfg_change_mutex;
@ -208,7 +209,7 @@ int dc_get_param_signal_info(const std::string &saddr, std::string &desc, uint8_
return -1;
}
vec_p_data.push_back(&p_signal->vec_p_data[i]);
vec_p_data.push_back(p_signal->vec_p_data[i]);
}
for(size_t i = 0; i < p_signal->vec_p_default_data.size(); i++)
@ -219,7 +220,7 @@ int dc_get_param_signal_info(const std::string &saddr, std::string &desc, uint8_
return -1;
}
vec_p_default_data.push_back(&p_signal->vec_p_default_data[i]);
vec_p_default_data.push_back(p_signal->vec_p_default_data[i]);
}
return 0;
@ -236,7 +237,7 @@ int dc_get_yk_signal_info(const std::string &saddr, std::string &desc, uint8_t &
desc = p_signal->desc;
data_type = p_signal->data_type;
ctrl_type = p_signal->ctrl_type;
vec_p_data.push_back(&p_signal->vec_p_data[0]);
vec_p_data.push_back(p_signal->vec_p_data[0]);
return 0;
}
@ -927,13 +928,18 @@ LOCAL int dc_signal_add_to_map(stru_signal &signal, stru_signal_map &dc_signal_m
{
if(exist_signal->saddr == signal.saddr)
{
uint32_t old_id = exist_signal->id;
*exist_signal = signal;
exist_signal->id = old_id;
return 0;
}
}
auto [it, inserted] = signal_map.emplace(signal.hash, signal);
stru_signal *new_sig = &it->second;
new_sig->id = dc_signal_map.signal_id++;
conflict_it->second.push_back(new_sig);
stru_signal new_signal = signal;
conflict_it->second.push_back(&new_signal);
dc_update_global_index(*new_sig, dc_signal_map);
}
else
{
@ -944,22 +950,36 @@ LOCAL int dc_signal_add_to_map(stru_signal &signal, stru_signal_map &dc_signal_m
{
std::vector<stru_signal*> conficts;
conficts.push_back(&map_it->second);
conficts.push_back(&signal);
auto [it, inserted] = signal_map.emplace(signal.hash, signal);
stru_signal *new_sig = &it->second;
new_sig->id = dc_signal_map.signal_id++;
conficts.push_back(new_sig);
dc_signal_map.hash_conflict_table[signal.hash] = conficts;
dc_update_global_index(*new_sig, dc_signal_map);
return 0;
}
else
{
auto old_id = map_it->second.id;
map_it->second = signal;
map_it->second.id = old_id;
return 0;
}
}
else
{
signal_map.emplace(signal.hash, signal);
auto [it, inserted] = signal_map.emplace(signal.hash, signal);
stru_signal &new_sig = it->second;
new_sig.id = dc_signal_map.signal_id++;
dc_update_global_index(new_sig, dc_signal_map);
return 0;
}
}
dc_update_global_index(signal, dc_signal_map);
return 0;
}
@ -2142,6 +2162,18 @@ void dc_delete_signal_data(void *p_data, uint8_t data_type)
}
LOCAL stru_signal *dc_find_signal_by_id(uint32_t id, stru_signal_map &dc_signal_map)
{
for(auto it = dc_signal_map.map_signals.begin(); it != dc_signal_map.map_signals.end(); ++it)
{
if(it->second.id == id)
{
return &it->second;
}
}
return nullptr;
}
void dc_param_cfg_check()
{
@ -2159,11 +2191,18 @@ void dc_param_cfg_check()
XMLElement *ao_elem = doc.NewElement("Ao");
for(auto it = g_datacenter.signal_ao.map_signals.begin(); it != g_datacenter.signal_ao.map_signals.end(); it++)
// for(auto it = g_datacenter.signal_ao.map_signals.begin(); it != g_datacenter.signal_ao.map_signals.end(); it++)
for(uint32_t i = 0; i < g_datacenter.signal_ao.signal_id; i++)
{
stru_signal *p_ao = &it->second;
stru_signal *p_ao = dc_find_signal_by_id(i, g_datacenter.signal_ao);
if(nullptr == p_ao)
{
MY_LOG_E("ao id %d not found", i);
continue;
}
XMLElement *sig_elem = doc.NewElement("Signal");
sig_elem->SetAttribute("id", p_ao->id);
sig_elem->SetAttribute("saddr", p_ao->saddr.c_str());
sig_elem->SetAttribute("desc", p_ao->desc.c_str());
sig_elem->SetAttribute("type", dc_get_data_type_str_by_id(p_ao->data_type).c_str());
@ -2179,9 +2218,15 @@ void dc_param_cfg_check()
XMLElement *param_elem = doc.NewElement("Param");
for(auto it = g_datacenter.signal_param.map_signals.begin(); it != g_datacenter.signal_param.map_signals.end(); it++)
// for(auto it = g_datacenter.signal_param.map_signals.begin(); it != g_datacenter.signal_param.map_signals.end(); it++)
for(uint32_t i = 0; i < g_datacenter.signal_param.signal_id; i++)
{
stru_signal *p_param = &it->second;
stru_signal *p_param = dc_find_signal_by_id(i, g_datacenter.signal_param);
if(nullptr == p_param)
{
MY_LOG_E("param id %d not found", i);
continue;
}
XMLElement *sig_elem = doc.NewElement("Signal");
sig_elem->SetAttribute("saddr", p_param->saddr.c_str());
@ -2229,6 +2274,7 @@ LOCAL void dc_show_signals(stru_signal_map &dc_signal_map)
hash_signal_map &signal_map = dc_signal_map.map_signals;
// 定义列宽(单位:字符,考虑中英文混合)
const int COL_ID = 12;
const int COL_SADDR = 48;
const int COL_DESC = 64;
const int COL_TYPE = 12;
@ -2237,7 +2283,9 @@ LOCAL void dc_show_signals(stru_signal_map &dc_signal_map)
// 打印表头严格对齐使用left对齐
cout << "\t"
<< left << setw(COL_SADDR) << "saddr"
<< left
<< setw(COL_ID) << "id"
<< setw(COL_SADDR) << "saddr"
<< setw(COL_DESC) << "desc"
<< setw(COL_TYPE) << "data_type"
<< setw(COL_VAL) << "val"
@ -2249,14 +2297,21 @@ LOCAL void dc_show_signals(stru_signal_map &dc_signal_map)
cout << "\t" << string(total_width, '-') << endl;
// 遍历信号表
for(auto it = signal_map.begin(); it != signal_map.end(); ++it)
// for(auto it = signal_map.begin(); it != signal_map.end(); ++it)
for(uint32_t i = 0; i < dc_signal_map.signal_id; i++)
{
const stru_signal &signal = it->second;
// const stru_signal *p_signal = &it->second;
stru_signal *p_signal = dc_find_signal_by_id(i, dc_signal_map);
if(nullptr == p_signal)
{
MY_LOG_E("signal id %d not found", i);
continue;
}
// 1. 先把所有列的内容拼接成字符串再一次性输出避免中间打断setw对齐
string link_str;
bool first = true;
for (const auto &link : signal.link_saddrs)
for (const auto &link : p_signal->link_saddrs)
{
if (!first) link_str += ", ";
link_str += link;
@ -2265,15 +2320,19 @@ LOCAL void dc_show_signals(stru_signal_map &dc_signal_map)
// 2. 输出所有列严格使用setw控制宽度
cout << "\t"
<< left << setw(COL_SADDR) << signal.saddr
<< setw(COL_DESC) << signal.desc
<< setw(COL_TYPE) << dc_get_data_type_str_by_id(signal.data_type)
<< setw(COL_VAL) << dc_get_signal_val(signal.vec_p_data[0], signal.data_type)
<< left
<< setw(COL_ID) << p_signal->id
<< setw(COL_SADDR) << p_signal->saddr
<< setw(COL_DESC) << p_signal->desc
<< setw(COL_TYPE) << dc_get_data_type_str_by_id(p_signal->data_type)
<< setw(COL_VAL) << dc_get_signal_val(p_signal->vec_p_data[0], p_signal->data_type)
<< setw(COL_LINK) << link_str
<< endl;
}
cout << endl;
cout << "signal_id: " << dc_signal_map.signal_id << endl;
cout << "signal count: " << signal_map.size() << endl;
cout << "conflict count: " << dc_signal_map.hash_conflicts.size() << endl;

View File

@ -114,6 +114,32 @@ LOCAL void mms_data_back(stru_mms_m_out_value *p)
}
stru_mms_m_time *t = &p->time;
printf("%d-%d-%d %02d:%02d:%02d:%d\n", t->year, t->mon, t->day, t->hour, t->min, t->sec, t->msec);
for(uint32_t i = 0; i < g_vec_iec61850m_info.size(); i++)
{
if(g_vec_iec61850m_info[i].fd == p->app_fd)
{
stru_mms_m_config *p_config = &g_vec_iec61850m_info[i].mms_config;
for(uint32_t j = 0; j < p_config->st_num; j++)
{
if(strcmp(p_config->p_st_sig[j].saddr, p->name) == 0)
{
*(uint8_t *)p_config->p_st_sig[j].vec_p_data[0] = MY_GET_DATA_WITH_TYPE(p->p_value, uint8_t);
}
}
for(uint32_t j = 0; j < p_config->mx_num; j++)
{
if(strcmp(p_config->p_mx_sig[j].saddr, p->name) == 0)
{
if(p->type == MMS_FLOAT)
*(float *)p_config->p_mx_sig[j].vec_p_data[0] = MY_GET_DATA_WITH_TYPE(p->p_value, float);
else if(p->type == MMS_INTEGER)
*(int32_t *)p_config->p_mx_sig[j].vec_p_data[0] = MY_GET_DATA_WITH_TYPE(p->p_value, int32_t);
}
}
}
}
}
LOCAL void iec61850m_connect_status(int fd, int status)

View File

@ -560,7 +560,7 @@ void ws_task()
return;
}
const char ctrl_type_str[][16] = {"NONE", "DIRECT_NORMAL", "SBO_NORMAL"};
const char ctrl_type_str[][16] = {"0", "1", "2"};
cJSON *root = cJSON_CreateObject();
if(nullptr == root)
@ -632,7 +632,7 @@ void ws_task()
cJSON_AddItemToObject(item, "type", cJSON_CreateString(dc_get_data_type_str_by_id(p_signal->data_type).c_str()));
std::string val = dc_get_signal_val(p_signal->vec_p_data[0], p_signal->data_type);
cJSON_AddItemToObject(item, "val", cJSON_CreateString(val.c_str()));
cJSON_AddItemToObject(item, "ctrl_type", cJSON_CreateString(ctrl_type_str[p_signal->ctrl_type]));
cJSON_AddItemToObject(item, "ctrl_type", cJSON_CreateNumber(p_signal->ctrl_type));
cJSON_AddItemToArray(yk_arr, item);
}
@ -655,7 +655,7 @@ void ws_task()
cJSON_AddItemToObject(item, "type", cJSON_CreateString(dc_get_data_type_str_by_id(p_signal->data_type).c_str()));
// std::string val = dc_get_signal_val(p_signal->vec_p_data[0], p_signal->data_type);
// cJSON_AddItemToObject(item, "val", cJSON_CreateString(val.c_str()));
cJSON_AddItemToObject(item, "ctrl_type", cJSON_CreateString(ctrl_type_str[p_signal->ctrl_type]));
cJSON_AddItemToObject(item, "ctrl_type", cJSON_CreateNumber(p_signal->ctrl_type));
if(p_signal->p_param)
{
cJSON_AddItemToObject(item, "min", cJSON_CreateString(std::to_string(p_signal->p_param->min).c_str()));
@ -693,7 +693,7 @@ void ws_task()
cJSON_AddItemToObject(item, "type", cJSON_CreateString(dc_get_data_type_str_by_id(p_signal->data_type).c_str()));
// std::string val = dc_get_signal_val(p_signal->vec_p_data[0], p_signal->data_type);
// cJSON_AddItemToObject(item, "val", cJSON_CreateString(val.c_str()));
cJSON_AddItemToObject(item, "ctrl_type", cJSON_CreateString(ctrl_type_str[p_signal->ctrl_type]));
cJSON_AddItemToObject(item, "ctrl_type", cJSON_CreateNumber(p_signal->ctrl_type));
if(p_signal->p_param)
{
cJSON_AddItemToObject(item, "min", cJSON_CreateString(std::to_string(p_signal->p_param->min).c_str()));

View File

@ -5,31 +5,31 @@
<Para desc="参数" host_ip="198.121.0.30" host_port="102" ied="TEMPLATE" />
<Point desc="点表" >
<St desc="遥信">
<Item no="0" type="2" name="iec61850m.prj.st0" desc="遥信01" LDev="PROT" LNode="GGIO7" DoName="Ind5" fc="0"/>
<Item no="1" type="2" name="iec61850m.prj.st1" desc="遥信02" LDev="PROT" LNode="GGIO7" DoName="Ind2" fc="0"/>
<Item no="2" type="2" name="st2" desc="遥信03" LDev="PROT" LNode="GGIO7" DoName="Ind3" fc="0"/>
<Item no="3" type="2" name="st4" desc="遥信04" LDev="CTRL" LNode="TC1CSWI1" DoName="Pos" fc="0"/>
<Item no="4" type="2" name="st5" desc="低频保护软压板" LDev="PROT" LNode="GGIO1" DoName="SPCSO1" fc="0"/>
<Item no="0" type="2" name="iec61850m.prj.st.0" desc="遥信01" LDev="PROT" LNode="GGIO7" DoName="Ind5" fc="0"/>
<Item no="1" type="2" name="iec61850m.prj.st.1" desc="遥信02" LDev="PROT" LNode="GGIO7" DoName="Ind2" fc="0"/>
<Item no="2" type="2" name="iec61850m.prj.st.2" desc="遥信03" LDev="PROT" LNode="GGIO7" DoName="Ind3" fc="0"/>
<Item no="3" type="2" name="iec61850m.prj.st.3" desc="遥信04" LDev="CTRL" LNode="TC1CSWI1" DoName="Pos" fc="0"/>
<Item no="4" type="2" name="iec61850m.prj.st.4" desc="低频保护软压板" LDev="PROT" LNode="GGIO1" DoName="SPCSO1" fc="0"/>
</St>
<Mx desc="遥测">
<Item no="0" type="6" name="mx0" desc="遥测01" LDev="PROT" LNode="PMMXU1" DoName="Hz.mag.f" fc="1"/>
<Item no="1" type="6" name="mx1" desc="遥测02" LDev="PROT" LNode="PMMXU1" DoName="PhV.phsA.cVal.mag.f" fc="1"/>
<Item no="2" type="6" name="mx2" desc="遥测03" LDev="PROT" LNode="PMMXU1" DoName="PhV.phsB.cVal.mag.f" fc="1"/>
<Item no="3" type="6" name="mx3" desc="遥测04" LDev="PROT" LNode="PMMXU1" DoName="PhV.phsC.cVal.mag.f" fc="1"/>
<Item no="0" type="6" name="iec61850m.prj.mx.0" desc="遥测01" LDev="PROT" LNode="PMMXU1" DoName="Hz.mag.f" fc="1"/>
<Item no="1" type="6" name="iec61850m.prj.mx.1" desc="遥测02" LDev="PROT" LNode="PMMXU1" DoName="PhV.phsA.cVal.mag.f" fc="1"/>
<Item no="2" type="6" name="iec61850m.prj.mx.2" desc="遥测03" LDev="PROT" LNode="PMMXU1" DoName="PhV.phsB.cVal.mag.f" fc="1"/>
<Item no="3" type="6" name="iec61850m.prj.mx.3" desc="遥测04" LDev="PROT" LNode="PMMXU1" DoName="PhV.phsC.cVal.mag.f" fc="1"/>
</Mx>
<Co desc="遥控">
<Item no="0" type="2" ctlModel="4" name="co0" desc="遥控01" LDev="CTRL" LNode="TC1CSWI1" DoName="Pos" fc="0"/>
<Item no="1" type="2" ctlModel="4" name="co1" desc="遥控02" LDev="CTRL" LNode="TC2CSWI1" DoName="Pos" fc="0"/>
<Item no="2" type="2" ctlModel="4" name="co2" desc="遥控03" LDev="CTRL" LNode="TC3CSWI1" DoName="Pos" fc="0"/>
<Item no="3" type="2" ctlModel="4" name="co3" desc="遥控04" LDev="CTRL" LNode="TC4CSWI1" DoName="Pos" fc="0"/>
<Item no="4" type="2" ctlModel="4" name="co4" desc="低频保护软压板" LDev="PROT" LNode="GGIO1" DoName="SPCSO1" fc="0"/>
<Item no="0" type="2" ctlModel="4" name="iec61850m.prj.co.0" desc="遥控01" LDev="CTRL" LNode="TC1CSWI1" DoName="Pos" fc="0"/>
<Item no="1" type="2" ctlModel="4" name="iec61850m.prj.co.1" desc="遥控02" LDev="CTRL" LNode="TC2CSWI1" DoName="Pos" fc="0"/>
<Item no="2" type="2" ctlModel="4" name="iec61850m.prj.co.2" desc="遥控03" LDev="CTRL" LNode="TC3CSWI1" DoName="Pos" fc="0"/>
<Item no="3" type="2" ctlModel="4" name="iec61850m.prj.co.3" desc="遥控04" LDev="CTRL" LNode="TC4CSWI1" DoName="Pos" fc="0"/>
<Item no="4" type="2" ctlModel="4" name="iec61850m.prj.co.4" desc="低频保护软压板" LDev="PROT" LNode="GGIO1" DoName="SPCSO1" fc="0"/>
</Co>
<Ao desc="参数">
<Item no="0" type="5" ctlModel="4" name="ao0" desc="参数01" LDev="PROT" LNode="LPHD1" DoName="SettingGrp" fc="2" min="1" max="30" step="1" unit="" value="1" default="1"/>
<Item no="1" type="5" ctlModel="4" name="ao1" desc="参数02" LDev="PROT" LNode="LPHD1" DoName="DeviceName" fc="2" min="" max="" step="" unit="" value="1" default="1"/>
<Item no="0" type="5" ctlModel="4" name="iec61850m.prj.ao.0" desc="参数01" LDev="PROT" LNode="LPHD1" DoName="SettingGrp" fc="2" min="1" max="30" step="1" unit="" value="1" default="1"/>
<Item no="1" type="5" ctlModel="4" name="iec61850m.prj.ao.1" desc="参数02" LDev="PROT" LNode="LPHD1" DoName="DeviceName" fc="2" min="" max="" step="" unit="" value="1" default="1"/>
</Ao>
<Param desc="定值">
<Item no="0" type="5" ctlModel="4" name="param0" desc="定值01" LDev="PROT" LNode="LPHD1" DoName="SettingGrp" fc="2" min="0.05" max="150" step="0.001" unit="A" num="2">
<Item no="0" type="5" ctlModel="4" name="iec61850m.prj.param.0" desc="定值01" LDev="PROT" LNode="LPHD1" DoName="SettingGrp" fc="2" min="0.05" max="150" step="0.001" unit="A" num="2">
<SubItem value="15" default="15"/>
<SubItem value="27" default="27"/>
</Item>

View File

@ -160,6 +160,13 @@
param: document.getElementById('paramBody')
};
// 控制类型数字转文字映射
const ctrlTypeMap = {
0: "只读",
1: "直控",
2: "选控"
};
const log = document.getElementById('log');
const status = document.getElementById('status');
@ -205,7 +212,13 @@
});
}
// 新增行不再维护本地map
// 转换控制类型
function getCtrlText(val){
if(val === undefined || val === null) return "-";
return ctrlTypeMap[val] || val;
}
// 新增行
function addRow(type, item, index) {
const body = tableBodies[type];
const tr = body.insertRow();
@ -216,15 +229,15 @@
<td>${item.type || '-'}</td>
<td>${item.val || '-'}</td>
`;
// yk 增加 ctrl_type
// yk 增加控制权限文字
if (type === 'yk') {
html += `<td>${item.ctrl_type || '-'}</td>`;
html += `<td>${getCtrlText(item.ctrl_type)}</td>`;
}
// ao 增加完整参数列
if (type === 'ao') {
html += `
<td>${item.ctrl_type || '-'}</td>
<td>${getCtrlText(item.ctrl_type)}</td>
<td>${item.min || '-'}</td>
<td>${item.max || '-'}</td>
<td>${item.step || '-'}</td>
@ -236,7 +249,7 @@
// param 增加完整参数列
if (type === 'param') {
html += `
<td>${item.ctrl_type || '-'}</td>
<td>${getCtrlText(item.ctrl_type)}</td>
<td>${item.min || '-'}</td>
<td>${item.max || '-'}</td>
<td>${item.step || '-'}</td>