1、调整数据中心获取信号内容的接口;
2、调整webserver中的处理函数,抽象成信号类型的方法;
3、调整web前端网页显示
This commit is contained in:
ypc 2026-05-28 13:23:01 +08:00
parent 3d59800656
commit ac5182ea14
10 changed files with 637 additions and 615 deletions

4
.gitignore vendored
View File

@ -22,8 +22,8 @@ tmp/
# vscode 缓存
.vscode/
release/x86/exe/FTU_cfg_parse
release/x86/exe/RTU
release/x86/
release/arm/
src/system/uart_trans/
src/system/FTU_cfg_parse/
libiec61850-1.5.3/

View File

@ -384,18 +384,18 @@ int dc_signal_yk_link_with_callback(const std::string &saddr, void **p_data, sig
int dc_signal_yk_set_status(const std::string &saddr, SIGNAL_CTRL_STEP step, stru_signal_ctrl &ctrl, void *p_data);
// 数据中心获取out信号信息接口
int dc_get_out_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, std::vector<void *> &vec_p_data);
int dc_get_out_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, void **p_data);
// 数据中心获取in信号信息接口
int dc_get_in_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, std::vector<void *> &vec_p_data);
int dc_get_in_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, void **p_data);
int dc_get_ao_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, stru_signal_param &param, uint8_t &ctrl_type, std::vector<void *> &vec_p_data, std::vector<void *> &vec_p_default_data);
int dc_get_ao_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, stru_signal_param *p_param, uint8_t &ctrl_type, void **p_data, void **p_default_data);
// 数据中心获取参数信号信息接口
int dc_get_param_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, stru_signal_param &param, uint8_t &ctrl_type, std::vector<void *> &vec_p_data, std::vector<void *> &vec_p_default_data);
int dc_get_param_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, stru_signal_param *p_param, uint8_t &ctrl_type, std::vector<void *> *p_vec_p_data, std::vector<void *> *p_vec_p_default_data);
// 数据中心获取遥控信号信息接口
int dc_get_yk_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, uint8_t &ctrl_type, std::vector<void *> &vec_p_data);
int dc_get_yk_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, uint8_t &ctrl_type, void **p_data);
// 数据中心获取信号值字符串接口
std::string dc_get_signal_val(void *p_data, uint8_t data_type);

View File

@ -1603,7 +1603,6 @@ static void *mms_m_run_thread(void *arg)
stru_mms_m_obj *obj = (stru_mms_m_obj *)arg;
LOG_I("obj %p", obj);
mms_m_timer_init(*obj);
stru_event_queue &queue = obj->run.event_queue;
@ -1807,8 +1806,6 @@ int mms_m_out_init(const char *cfg_path, int debug_print_flag, uint32_t connecti
return -1;
}
LOG_I("p_obj %p", p_obj);
memset(p_obj, 0, sizeof(stru_mms_m_obj));
p_obj->cfg_path = cfg_path;
p_obj->debug_print_flag = debug_print_flag;
@ -1848,8 +1845,6 @@ int mms_m_out_init(const char *cfg_path, int debug_print_flag, uint32_t connecti
return -1;
}
LOG_I("p_obj %p", p_obj);
if(0 != pthread_create(&p_obj->run.pthread_task, NULL, mms_m_run_thread, p_obj))
{
LOG_E("Failed to create IED thread, config file %s\n", cfg_path);

View File

@ -1324,7 +1324,10 @@ int model_init(stru_icd &icd)
continue;
}
LOG_I("sAddr %s, node type %d, name %s", it_saddr->c_str(), p_node->modelType, get_DA_path(p_node).c_str());
if(mms_s_dbg_get())
{
LOG_I("sAddr %s, node type %d, name %s", it_saddr->c_str(), p_node->modelType, get_DA_path(p_node).c_str());
}
}
model_search_control_DataObjects(icd); // 搜索所有控制 DO含 ctlModel 的 DO存入 vec_control_do

View File

@ -93,7 +93,7 @@ void dc_set_param_cfg_change(bool change)
int dc_get_out_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, std::vector<void *> &vec_p_data)
int dc_get_out_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, void **p_data)
{
stru_signal *p_signal = dc_find_out_signal(saddr);
if(p_signal == nullptr)
@ -117,12 +117,15 @@ int dc_get_out_signal_info(const std::string &saddr, std::string &desc, uint8_t
return -1;
}
vec_p_data.push_back(p_signal->vec_p_data[0]);
if(p_data != nullptr)
{
(*p_data) = p_signal->vec_p_data[0];
}
return 0;
}
int dc_get_in_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, std::vector<void *> &vec_p_data)
int dc_get_in_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, void **p_data)
{
stru_signal *p_signal = dc_find_in_signal(saddr);
if(p_signal == nullptr)
@ -136,7 +139,10 @@ int dc_get_in_signal_info(const std::string &saddr, std::string &desc, uint8_t &
if(!p_signal->vec_p_data.empty() && nullptr != p_signal->vec_p_data[0])
{
vec_p_data.push_back(p_signal->vec_p_data[0]);
if(p_data != nullptr)
{
(*p_data) = p_signal->vec_p_data[0];
}
return 0;
}
@ -145,7 +151,7 @@ int dc_get_in_signal_info(const std::string &saddr, std::string &desc, uint8_t &
return -1;
}
int dc_get_ao_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, stru_signal_param &param, uint8_t &ctrl_type, std::vector<void *> &vec_p_data, std::vector<void *> &vec_p_default_data)
int dc_get_ao_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, stru_signal_param *p_param, uint8_t &ctrl_type, void **p_data, void **p_default_data)
{
stru_signal *p_signal = dc_find_signal(XXH3_128bits(saddr.c_str(), saddr.length()), g_datacenter.signal_ao);
if(p_signal == nullptr)
@ -156,15 +162,21 @@ int dc_get_ao_signal_info(const std::string &saddr, std::string &desc, uint8_t &
desc = p_signal->desc;
data_type = p_signal->data_type;
param.min = p_signal->param.min;
param.max = p_signal->param.max;
param.step = p_signal->param.step;
param.unit = p_signal->param.unit;
if(p_param != nullptr)
{
p_param->min = p_signal->param.min;
p_param->max = p_signal->param.max;
p_param->step = p_signal->param.step;
p_param->unit = p_signal->param.unit;
}
ctrl_type = p_signal->ctrl_type;
if(!p_signal->vec_p_data.empty() && nullptr != p_signal->vec_p_data[0])
{
vec_p_data.push_back(p_signal->vec_p_data[0]);
if(p_data != nullptr)
{
(*p_data) = p_signal->vec_p_data[0];
}
}
else
{
@ -174,7 +186,10 @@ int dc_get_ao_signal_info(const std::string &saddr, std::string &desc, uint8_t &
if(!p_signal->vec_p_default_data.empty() && nullptr != p_signal->vec_p_default_data[0])
{
vec_p_default_data.push_back(p_signal->vec_p_default_data[0]);
if(p_default_data != nullptr)
{
(*p_default_data) = p_signal->vec_p_default_data[0];
}
}
else
{
@ -185,7 +200,7 @@ int dc_get_ao_signal_info(const std::string &saddr, std::string &desc, uint8_t &
return 0;
}
int dc_get_param_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, stru_signal_param &param, uint8_t &ctrl_type, std::vector<void *> &vec_p_data, std::vector<void *> &vec_p_default_data)
int dc_get_param_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, stru_signal_param *p_param, uint8_t &ctrl_type, std::vector<void *> *p_vec_p_data, std::vector<void *> *p_vec_p_default_data)
{
stru_signal *p_signal = dc_find_signal(XXH3_128bits(saddr.c_str(), saddr.length()), g_datacenter.signal_param);
if(p_signal == nullptr)
@ -195,10 +210,13 @@ int dc_get_param_signal_info(const std::string &saddr, std::string &desc, uint8_
}
desc = p_signal->desc;
data_type = p_signal->data_type;
param.min = p_signal->param.min;
param.max = p_signal->param.max;
param.step = p_signal->param.step;
param.unit = p_signal->param.unit;
if(p_param != nullptr)
{
p_param->min = p_signal->param.min;
p_param->max = p_signal->param.max;
p_param->step = p_signal->param.step;
p_param->unit = p_signal->param.unit;
}
ctrl_type = p_signal->ctrl_type;
for(size_t i = 0; i < p_signal->vec_p_data.size(); i++)
@ -208,8 +226,10 @@ int dc_get_param_signal_info(const std::string &saddr, std::string &desc, uint8_
MY_LOG_E("saddr %s vec_p_data[%ld] is nullptr", saddr.c_str(), i);
return -1;
}
vec_p_data.push_back(p_signal->vec_p_data[i]);
if(p_vec_p_data != nullptr)
{
p_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++)
@ -220,13 +240,16 @@ 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]);
if(p_vec_p_default_data != nullptr)
{
p_vec_p_default_data->push_back(p_signal->vec_p_default_data[i]);
}
}
return 0;
}
int dc_get_yk_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, uint8_t &ctrl_type, std::vector<void *> &vec_p_data)
int dc_get_yk_signal_info(const std::string &saddr, std::string &desc, uint8_t &data_type, uint8_t &ctrl_type, void **p_data)
{
stru_signal *p_signal = dc_find_signal(XXH3_128bits(saddr.c_str(), saddr.length()), g_datacenter.signal_yk);
if(p_signal == nullptr)
@ -237,7 +260,10 @@ 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]);
if(p_data != nullptr)
{
*p_data = p_signal->vec_p_data[0];
}
return 0;
}
@ -263,85 +289,6 @@ void dc_signal_out_change_check()
}
}
// LOCAL void dc_signal_ctrl_data_create(stru_signal_ctrl &ctrl)
// {
// switch(ctrl.data_type)
// {
// case DATA_TYPE_B:
// case DATA_TYPE_U8:
// ctrl.p_data = new uint8_t;
// *(uint8_t *)ctrl.p_data = 0;
// break;
// case DATA_TYPE_S8:
// ctrl.p_data = new int8_t;
// *(int8_t *)ctrl.p_data = 0;
// break;
// case DATA_TYPE_S16:
// ctrl.p_data = new int16_t;
// *(int16_t *)ctrl.p_data = 0;
// break;
// case DATA_TYPE_U16:
// ctrl.p_data = new uint16_t;
// *(uint16_t *)ctrl.p_data = 0;
// break;
// case DATA_TYPE_S32:
// ctrl.p_data = new int32_t;
// *(int32_t *)ctrl.p_data = 0;
// break;
// case DATA_TYPE_U32:
// ctrl.p_data = new uint32_t;
// *(uint32_t *)ctrl.p_data = 0;
// break;
// case DATA_TYPE_L64:
// ctrl.p_data = new int64_t;
// *(int64_t *)ctrl.p_data = 0;
// break;
// case DATA_TYPE_UL64:
// ctrl.p_data = new uint64_t;
// *(uint64_t *)ctrl.p_data = 0;
// break;
// case DATA_TYPE_F32:
// ctrl.p_data = new float;
// *(float *)ctrl.p_data = 0;
// break;
// case DATA_TYPE_D64:
// ctrl.p_data = new double;
// *(double *)ctrl.p_data = 0;
// break;
// case DATA_TYPE_IP:
// ctrl.p_data = new char[4];
// memset(ctrl.p_data, 0, 4);
// break;
// case DATA_TYPE_MAC:
// ctrl.p_data = new char[8];
// memset(ctrl.p_data, 0, 8);
// break;
// case DATA_TYPE_C1:
// ctrl.p_data = new char;
// *(char *)ctrl.p_data = 0;
// break;
// case DATA_TYPE_C8:
// ctrl.p_data = new char[8];
// memset(ctrl.p_data, 0, 8);
// break;
// case DATA_TYPE_C32:
// ctrl.p_data = new char[32];
// memset(ctrl.p_data, 0, 32);
// break;
// case DATA_TYPE_C64:
// ctrl.p_data = new char[64];
// memset(ctrl.p_data, 0, 64);
// break;
// case DATA_TYPE_C128:
// ctrl.p_data = new char[128];
// memset(ctrl.p_data, 0, 128);
// break;
// default:
// LOG_E("unsupported data type %d", ctrl.data_type);
// break;
// }
// }
LOCAL int dc_data_compare(uint8_t data_type, void *p_data, void *p_data2)
{
if(p_data == nullptr || p_data2 == nullptr)
@ -434,11 +381,6 @@ LOCAL bool dc_signal_ao_add_check(stru_signal *p_signal, const std::string &desc
change = true;
}
// if(0 != dc_data_compare(p_signal->data_type, p_data, p_signal->vec_p_data[0]))
// {
// change = true;
// }
if(0 != dc_data_compare(p_signal->data_type, p_default_data, p_signal->vec_p_default_data[0]))
{
change = true;
@ -1109,8 +1051,6 @@ int dc_signal_in(const std::string &saddr, const std::string &desc, const std::s
signal.link_saddrs.push_back(link_saddr);
MY_LOG_I("saddr %s, p_data %p, link_saddr %s", saddr.c_str(), (*p_data), link_saddr.c_str());
return dc_signal_add_to_map(signal, g_datacenter.signal_in);
}
@ -1163,7 +1103,6 @@ int dc_signal_in_with_callback(const std::string &saddr, const std::string &desc
return dc_signal_add_to_map(signal, g_datacenter.signal_in);
}
int dc_signal_ao(const std::string &saddr, const std::string &desc, uint8_t data_type, const stru_signal_param &param, uint8_t ctrl_type, void *p_data, void *p_default_data, signal_change_cb cb)
{
if(p_data == nullptr || p_default_data == nullptr)
@ -1356,6 +1295,15 @@ int dc_signal_param(const std::string &saddr, const std::string &desc, uint8_t d
return -1;
}
for(size_t i = 0; i < vec_p_data.size(); i++)
{
if(vec_p_data[i] == nullptr || vec_p_default_data[i] == nullptr)
{
MY_LOG_E("vec_p_data[%ld] or vec_p_default_data[%ld] is nullptr", i, i);
return -1;
}
}
XXH128_hash_t hash = XXH3_128bits(saddr.c_str(), saddr.length());
stru_signal *p_signal = dc_find_signal(hash, g_datacenter.signal_param);
if(p_signal != nullptr)
@ -1779,6 +1727,7 @@ std::string dc_get_signal_val(void *p_data, uint8_t data_type)
{
if(NULL == p_data)
{
MY_LOG_E("p_data is nullptr");
return "";
}
@ -1922,7 +1871,11 @@ LOCAL int dc_set_signal_val(void *p_data, uint8_t data_type, void *set_data)
void dc_set_signal_val_from_str(void *p_data, uint8_t data_type, const std::string &str)
{
if (str.empty() || p_data == nullptr) return;
if (str.empty() || p_data == nullptr)
{
MY_LOG_E("str is empty or p_data is nullptr");
return;
}
switch (data_type)
{

View File

@ -505,7 +505,7 @@ int app_iec61850m_init2(void *arg)
dc_signal_in("iec61850m.iec_run_cnt_in", "iec61850m.iec_run_cnt_in", "iec.run_cnt", (void **)&p_iec_run_cnt);
MY_LOG_I("p_iec_run_cnt %p", p_iec_run_cnt);
return 0;
}

View File

@ -189,20 +189,15 @@ int app_iec61850s_init2(void *arg)
{
for(std::vector<stru_mms_s_setting>::iterator it = vec_setting.begin(); it != vec_setting.end(); ++it)
{
if(0 != dc_signal_ao_link_with_callback(it->base.saddr, (void **)&it->data, NULL))
{
MY_LOG_E("dc_signal_ao_link_with_callback failed");
return -1;
}
std::string desc = "";
uint8_t data_type = 0;
stru_signal_param param = {};
uint8_t ctrl_type = 0;
std::vector<void *> vec_p_data = {};
std::vector<void *> vec_p_default_data = {};
dc_get_ao_signal_info(it->base.saddr, desc, data_type, param, ctrl_type, vec_p_data, vec_p_default_data);
if(0 != dc_get_ao_signal_info(it->base.saddr, desc, data_type, nullptr, ctrl_type, (void **)&it->data, nullptr))
{
MY_LOG_E("dc_get_ao_signal_info failed");
return -1;
}
strcpy(it->base.desc, desc.c_str());
it->base.type = data_type;
@ -211,21 +206,12 @@ int app_iec61850s_init2(void *arg)
for(std::vector<stru_mms_s_param>::iterator it = vec_param.begin(); it != vec_param.end(); ++it)
{
// std::vector<void *> vec_p_data = {};
// if(0 != dc_signal_param_link_with_callback(it->base.saddr, vec_p_data, NULL))
// {
// MY_LOG_E("dc_signal_param_link_with_callback failed");
// return -1;
// }
std::string desc = "";
uint8_t data_type = 0;
stru_signal_param param = {};
uint8_t ctrl_type = 0;
std::vector<void *> vec_p_data = {};
std::vector<void *> vec_p_default_data = {};
if(0 != dc_get_param_signal_info(it->base.saddr, desc, data_type, param, ctrl_type, vec_p_data, vec_p_default_data))
if(0 != dc_get_param_signal_info(it->base.saddr, desc, data_type, nullptr, ctrl_type, &vec_p_data, nullptr))
{
MY_LOG_E("dc_get_param_signal_info failed");
return -1;

View File

@ -960,7 +960,7 @@ int app_self_ptl_init2(void *arg)
{
dc_signal_in("self_ptl.iec_run_cnt_in", "self_ptl.iec_run_cnt_in", "iec.run_cnt", (void **)&p_iec_run_cnt_in);
MY_LOG_I("p_iec_run_cnt_in %p", p_iec_run_cnt_in);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -23,12 +23,11 @@
.log-send { color: #4CAF50; }
.log-error { color: #f44336; }
/* 表格容器:固定高度 + 滚动条最多显示8行 */
.table-container { margin-bottom: 20px; }
.table-title { font-size: 16px; font-weight: bold; margin-bottom: 8px; color: #2c3e50; }
.table-wrapper {
max-height: 320px; /* 刚好显示8行 */
overflow-y: auto; /* 超出自动滚动 */
max-height: 320px;
overflow-y: auto;
border: 1px solid #eee;
border-radius: 4px;
}
@ -45,7 +44,7 @@
.signalTable td { padding: 10px; border-bottom: 1px solid #eee; }
.signalTable tr:hover { background: #f5f5f5; }
.form-row { display: flex; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; }
.form-row { display: flex; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; align-items: flex-end; }
.form-group { display: flex; flex-direction: column; }
</style>
</head>
@ -77,6 +76,10 @@
<option value="del">del</option>
</select>
</div>
<div class="form-group">
<label>setting_zone</label>
<input id="setting_zone" value="0" placeholder="0">
</div>
<div class="form-group">
<label>signal_data</label>
<input id="signal_data" placeholder="(can empty)">
@ -92,7 +95,6 @@
<button onclick="connectWS()" class="secondary">Connect</button>
</div>
<!-- 4个独立信号表格 + 滚动容器 -->
<div class="card">
<div class="table-container">
<div class="table-title">OUT 信号</div>
@ -135,10 +137,10 @@
</div>
<div class="table-container">
<div class="table-title">PARAM 信号</div>
<div class="table-title">PARAM 信号(当前定值区:<span id="currentZone">0</span></div>
<div class="table-wrapper">
<table class="signalTable">
<thead><tr><th>#</th><th>saddr</th><th>desc</th><th>数据类型</th><th>val</th><th>ctrl_type</th><th>min</th><th>max</th><th>step</th><th>unit</th><th>default</th></tr></thead>
<thead><tr><th>#</th><th>saddr</th><th>desc</th><th>数据类型</th><th>val</th><th>ctrl_type</th><th>min</th><th>max</th><th>step</th><th>unit</th><th>default_val</th></tr></thead>
<tbody id="paramBody"></tbody>
</table>
</div>
@ -160,15 +162,10 @@
param: document.getElementById('paramBody')
};
// 控制类型数字转文字映射
const ctrlTypeMap = {
0: "只读",
1: "直控",
2: "选控"
};
const ctrlTypeMap = { 0: "只读", 1: "直控", 2: "选控" };
const log = document.getElementById('log');
const status = document.getElementById('status');
const currentZoneSpan = document.getElementById('currentZone');
function addLog(msg, type = 'info') {
const t = new Date().toLocaleTimeString();
@ -194,32 +191,47 @@
};
}
// 每次收到数据,直接清空对应表格,重新渲染
function parseData(root) {
const setting_zone = document.getElementById('setting_zone').value.trim();
currentZoneSpan.textContent = setting_zone;
const types = ['out', 'in', 'yk', 'ao', 'param'];
types.forEach(type => {
const arr = root[type];
const body = tableBodies[type];
// 每次先清空表格
body.innerHTML = '';
if (Array.isArray(arr)) {
arr.forEach((item, index) => {
if (item.saddr) {
addRow(type, item, index + 1);
}
});
}
if (!Array.isArray(arr)) return;
arr.forEach((item, index) => {
if (!item.saddr) return;
if (type === 'param') {
const zoneList = item.setting_zone_list || [];
const match = zoneList.find(z => z.id === setting_zone);
if (!match) return;
const tr = body.insertRow();
tr.innerHTML = `
<td>${index+1}</td>
<td>${item.saddr}</td>
<td>${item.desc || '-'}</td>
<td>${item.type || '-'}</td>
<td>${match.val || '-'}</td>
<td>${ctrlTypeMap[item.ctrl_type] || item.ctrl_type}</td>
<td>${item.min || '-'}</td>
<td>${item.max || '-'}</td>
<td>${item.step || '-'}</td>
<td>${item.unit || '-'}</td>
<td>${match.default_val || '-'}</td>
`;
} else {
addNormalRow(type, item, index+1);
}
});
});
}
// 转换控制类型
function getCtrlText(val){
if(val === undefined || val === null) return "-";
return ctrlTypeMap[val] || val;
}
// 新增行
function addRow(type, item, index) {
function addNormalRow(type, item, index) {
const body = tableBodies[type];
const tr = body.insertRow();
let html = `
@ -229,27 +241,10 @@
<td>${item.type || '-'}</td>
<td>${item.val || '-'}</td>
`;
// yk 增加控制权限文字
if (type === 'yk') {
html += `<td>${getCtrlText(item.ctrl_type)}</td>`;
}
// ao 增加完整参数列
if (type === 'yk') html += `<td>${ctrlTypeMap[item.ctrl_type] || item.ctrl_type}</td>`;
if (type === 'ao') {
html += `
<td>${getCtrlText(item.ctrl_type)}</td>
<td>${item.min || '-'}</td>
<td>${item.max || '-'}</td>
<td>${item.step || '-'}</td>
<td>${item.unit || '-'}</td>
<td>${item.default || '-'}</td>
`;
}
// param 增加完整参数列
if (type === 'param') {
html += `
<td>${getCtrlText(item.ctrl_type)}</td>
<td>${ctrlTypeMap[item.ctrl_type] || item.ctrl_type}</td>
<td>${item.min || '-'}</td>
<td>${item.max || '-'}</td>
<td>${item.step || '-'}</td>
@ -264,12 +259,23 @@
const saddr = document.getElementById('saddr').value.trim();
const type = document.getElementById('signal_type').value;
const curd = document.getElementById('curd').value;
const setting_zone = document.getElementById('setting_zone').value.trim();
const data = document.getElementById('signal_data').value.trim();
if (!saddr) return addLog('saddr required', 'error');
if (!ws || ws.readyState !== 1) return addLog('not connected', 'error');
const msg = { saddr, signal_type: type, curd, signal_data: data };
const msg = {
saddr,
signal_type: type,
curd,
setting_zone: setting_zone,
signal_data: data
};
ws.send(JSON.stringify(msg));
addLog(`sent: ${JSON.stringify(msg)}`, 'send');
parseData(JSON.parse(ws._lastData || '{}'));
}
function clearForm() {