forked from xuos/xiuos
optimize OPCUA demo and PLC demo and added PLC channel instead of bus
This commit is contained in:
parent
eb4538e331
commit
06b2ed5235
|
@ -42,7 +42,7 @@
|
||||||
* Variables
|
* Variables
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
char test_ua_ip[] = {192, 168, 250, 5};
|
char test_ua_ip[] = {192, 168, 250, 2};
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Code
|
* Code
|
||||||
|
@ -53,9 +53,7 @@ static void UaConnectTestTask(void *arg)
|
||||||
struct netif net;
|
struct netif net;
|
||||||
UA_StatusCode retval;
|
UA_StatusCode retval;
|
||||||
char ua_uri[UA_URL_SIZE];
|
char ua_uri[UA_URL_SIZE];
|
||||||
|
|
||||||
memset(ua_uri, 0, sizeof(ua_uri));
|
memset(ua_uri, 0, sizeof(ua_uri));
|
||||||
|
|
||||||
UA_Client* client = UA_Client_new();
|
UA_Client* client = UA_Client_new();
|
||||||
|
|
||||||
if(client == NULL)
|
if(client == NULL)
|
||||||
|
@ -66,13 +64,11 @@ static void UaConnectTestTask(void *arg)
|
||||||
|
|
||||||
UA_ClientConfig* config = UA_Client_getConfig(client);
|
UA_ClientConfig* config = UA_Client_getConfig(client);
|
||||||
UA_ClientConfig_setDefault(config);
|
UA_ClientConfig_setDefault(config);
|
||||||
|
|
||||||
snprintf(ua_uri, sizeof(ua_uri), "opc.tcp://%d.%d.%d.%d:4840",
|
snprintf(ua_uri, sizeof(ua_uri), "opc.tcp://%d.%d.%d.%d:4840",
|
||||||
test_ua_ip[0], test_ua_ip[1], test_ua_ip[2], test_ua_ip[3]);
|
test_ua_ip[0], test_ua_ip[1], test_ua_ip[2], test_ua_ip[3]);
|
||||||
|
|
||||||
ua_pr_info("ua uri: %d %s\n", strlen(ua_uri), ua_uri);
|
ua_pr_info("ua uri: %d %s\n", strlen(ua_uri), ua_uri);
|
||||||
|
|
||||||
retval = UA_Client_connect(client,ua_uri);
|
retval = UA_Client_connect(client,ua_uri);
|
||||||
|
|
||||||
if(retval != UA_STATUSCODE_GOOD)
|
if(retval != UA_STATUSCODE_GOOD)
|
||||||
{
|
{
|
||||||
ua_pr_info("ua: [%s] connected failed %x\n", __func__, retval);
|
ua_pr_info("ua: [%s] connected failed %x\n", __func__, retval);
|
||||||
|
@ -97,7 +93,6 @@ SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) |
|
||||||
void UaBrowserObjectsTestTask(void* param)
|
void UaBrowserObjectsTestTask(void* param)
|
||||||
{
|
{
|
||||||
UA_Client* client = UA_Client_new();
|
UA_Client* client = UA_Client_new();
|
||||||
|
|
||||||
ua_pr_info("ua: [%s] start ...\n", __func__);
|
ua_pr_info("ua: [%s] start ...\n", __func__);
|
||||||
|
|
||||||
if(client == NULL)
|
if(client == NULL)
|
||||||
|
@ -108,9 +103,10 @@ void UaBrowserObjectsTestTask(void *param)
|
||||||
|
|
||||||
UA_ClientConfig* config = UA_Client_getConfig(client);
|
UA_ClientConfig* config = UA_Client_getConfig(client);
|
||||||
UA_ClientConfig_setDefault(config);
|
UA_ClientConfig_setDefault(config);
|
||||||
|
|
||||||
UA_StatusCode retval = UA_Client_connect(client, OPC_SERVER);
|
UA_StatusCode retval = UA_Client_connect(client, OPC_SERVER);
|
||||||
if(retval != UA_STATUSCODE_GOOD) {
|
|
||||||
|
if(retval != UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
ua_print("ua: [%s] connect failed %#x\n", __func__, retval);
|
ua_print("ua: [%s] connect failed %#x\n", __func__, retval);
|
||||||
UA_Client_delete(client);
|
UA_Client_delete(client);
|
||||||
return;
|
return;
|
||||||
|
@ -118,12 +114,9 @@ void UaBrowserObjectsTestTask(void *param)
|
||||||
|
|
||||||
ua_print("ua: [%s] connect ok!\n", __func__);
|
ua_print("ua: [%s] connect ok!\n", __func__);
|
||||||
ua_pr_info("--- start read time ---\n", __func__);
|
ua_pr_info("--- start read time ---\n", __func__);
|
||||||
|
|
||||||
ua_read_time(client);
|
ua_read_time(client);
|
||||||
|
|
||||||
ua_pr_info("--- get server info ---\n", __func__);
|
ua_pr_info("--- get server info ---\n", __func__);
|
||||||
ua_browser_objects(client);
|
ua_test_browser_objects(client);
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
UA_Client_disconnect(client);
|
UA_Client_disconnect(client);
|
||||||
UA_Client_delete(client); /* Disconnects the client internally */
|
UA_Client_delete(client); /* Disconnects the client internally */
|
||||||
|
@ -154,7 +147,6 @@ SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) |
|
||||||
void UaGetInfoTestTask(void* param)
|
void UaGetInfoTestTask(void* param)
|
||||||
{
|
{
|
||||||
UA_Client* client = UA_Client_new();
|
UA_Client* client = UA_Client_new();
|
||||||
|
|
||||||
ua_pr_info("ua: [%s] start ...\n", __func__);
|
ua_pr_info("ua: [%s] start ...\n", __func__);
|
||||||
|
|
||||||
if(client == NULL)
|
if(client == NULL)
|
||||||
|
@ -165,18 +157,18 @@ void UaGetInfoTestTask(void *param)
|
||||||
|
|
||||||
UA_ClientConfig* config = UA_Client_getConfig(client);
|
UA_ClientConfig* config = UA_Client_getConfig(client);
|
||||||
UA_ClientConfig_setDefault(config);
|
UA_ClientConfig_setDefault(config);
|
||||||
|
|
||||||
UA_StatusCode retval = UA_Client_connect(client, OPC_SERVER);
|
UA_StatusCode retval = UA_Client_connect(client, OPC_SERVER);
|
||||||
if(retval != UA_STATUSCODE_GOOD) {
|
|
||||||
|
if(retval != UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
ua_print("ua: [%s] connect failed %#x\n", __func__, retval);
|
ua_print("ua: [%s] connect failed %#x\n", __func__, retval);
|
||||||
UA_Client_delete(client);
|
UA_Client_delete(client);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ua_print("ua: [%s] connect ok!\n", __func__);
|
ua_print("ua: [%s] connect ok!\n", __func__);
|
||||||
ua_pr_info("--- get server info ---\n", __func__);
|
ua_pr_info("--- interactive server ---\n", __func__);
|
||||||
ua_get_server_info(client);
|
ua_test_interact_server(client);
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
UA_Client_disconnect(client);
|
UA_Client_disconnect(client);
|
||||||
UA_Client_delete(client); /* Disconnects the client internally */
|
UA_Client_delete(client); /* Disconnects the client internally */
|
||||||
|
@ -204,3 +196,55 @@ void *UaGetInfoTest(int argc, char *argv[])
|
||||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
UaInfo, UaGetInfoTest, UaInfo [IP]);
|
UaInfo, UaGetInfoTest, UaInfo [IP]);
|
||||||
|
|
||||||
|
void UaAddNodesTask(void* param)
|
||||||
|
{
|
||||||
|
UA_Client* client = UA_Client_new();
|
||||||
|
ua_pr_info("ua: [%s] start ...\n", __func__);
|
||||||
|
|
||||||
|
if(client == NULL)
|
||||||
|
{
|
||||||
|
ua_print("ua: [%s] tcp client null\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UA_ClientConfig* config = UA_Client_getConfig(client);
|
||||||
|
UA_ClientConfig_setDefault(config);
|
||||||
|
UA_StatusCode retval = UA_Client_connect(client, OPC_SERVER);
|
||||||
|
|
||||||
|
if(retval != UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
|
ua_print("ua: [%s] connect failed %#x\n", __func__, retval);
|
||||||
|
UA_Client_delete(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ua_print("ua: [%s] connect ok!\n", __func__);
|
||||||
|
ua_pr_info("--- add nodes ---\n", __func__);
|
||||||
|
ua_add_nodes(client);
|
||||||
|
/* Clean up */
|
||||||
|
UA_Client_disconnect(client);
|
||||||
|
UA_Client_delete(client); /* Disconnects the client internally */
|
||||||
|
}
|
||||||
|
|
||||||
|
void* UaAddNodesTest(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if(argc == 2)
|
||||||
|
{
|
||||||
|
if(isdigit(argv[1][0]))
|
||||||
|
{
|
||||||
|
if(sscanf(argv[1], "%d.%d.%d.%d", &test_ua_ip[0], &test_ua_ip[1], &test_ua_ip[2], &test_ua_ip[3]) == EOF)
|
||||||
|
{
|
||||||
|
lw_pr_info("input wrong ip\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip);
|
||||||
|
sys_thread_new("ua add nodes", UaAddNodesTask, NULL, UA_STACK_SIZE, UA_TASK_PRIO);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
|
UaAdd, UaAddNodesTest, UA Add Nodes);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
SRC_FILES := plc_demo.c
|
SRC_FILES := plc_show_demo.c plc_control_demo.c
|
||||||
|
|
||||||
include $(KERNEL_ROOT)/compiler.mk
|
include $(KERNEL_ROOT)/compiler.mk
|
||||||
|
|
|
@ -0,0 +1,232 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file plc_control_demo.c
|
||||||
|
* @brief Demo for PLC control
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2022.2.22
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "transform.h"
|
||||||
|
#include "open62541.h"
|
||||||
|
#include "ua_api.h"
|
||||||
|
#include "sys_arch.h"
|
||||||
|
#include "plc_ch.h"
|
||||||
|
#include "plc_dev.h"
|
||||||
|
#include "plc_demo.h"
|
||||||
|
|
||||||
|
struct PlcChannel plc_demo_ch;
|
||||||
|
struct PlcDriver plc_demo_drv;
|
||||||
|
struct PlcDevice plc_demo_dev;
|
||||||
|
|
||||||
|
PlcCtrlParamType plc_ctrl_param;
|
||||||
|
|
||||||
|
char plc_demo_ip[] = {192, 168, 250, 2};
|
||||||
|
|
||||||
|
#define TEST_STR_NID "ServiceInterfaces"
|
||||||
|
#define PLC_NS_FORMAT "n%d,%s"
|
||||||
|
|
||||||
|
UA_NodeId test_nodeid =
|
||||||
|
{
|
||||||
|
4,
|
||||||
|
UA_NODEIDTYPE_NUMERIC,
|
||||||
|
5
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
void PlcDemoChannelDrvInit(void)
|
||||||
|
{
|
||||||
|
static uint8_t init_flag = 0;
|
||||||
|
if(init_flag)
|
||||||
|
return;
|
||||||
|
init_flag = 1;
|
||||||
|
|
||||||
|
lwip_config_tcp(lwip_ipaddr, lwip_netmask, plc_demo_ip);
|
||||||
|
PlcChannelInit(&plc_demo_ch, PLC_CH_NAME);
|
||||||
|
if(PlcDriverInit(&plc_demo_drv, PLC_DRV_NAME) == EOK)
|
||||||
|
{
|
||||||
|
PlcDriverAttachToChannel(PLC_DRV_NAME, PLC_CH_NAME);
|
||||||
|
}
|
||||||
|
memset(&plc_demo_dev, 0, sizeof(plc_demo_dev));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PlcCtrlDemoInit(void)
|
||||||
|
{
|
||||||
|
static uint8_t init_flag = 0;
|
||||||
|
|
||||||
|
PlcDemoChannelDrvInit();
|
||||||
|
// register plc device
|
||||||
|
plc_demo_dev.state = CHDEV_INIT;
|
||||||
|
strcpy(plc_demo_dev.name, "UA Demo");
|
||||||
|
plc_demo_dev.info.product = "CPU 1215C";
|
||||||
|
plc_demo_dev.info.vendor = "SIEMENS";
|
||||||
|
plc_demo_dev.info.model = "S7-1200";
|
||||||
|
plc_demo_dev.info.id = 123;
|
||||||
|
plc_demo_dev.net = PLC_IND_ENET_OPCUA;
|
||||||
|
|
||||||
|
// register UA parameter
|
||||||
|
if(!plc_demo_dev.priv_data)
|
||||||
|
{
|
||||||
|
plc_demo_dev.priv_data = (UaParamType*)malloc(sizeof(UaParamType));
|
||||||
|
}
|
||||||
|
UaParamType* ua_ptr = plc_demo_dev.priv_data;
|
||||||
|
memset(ua_ptr, 0, sizeof(UaParamType));
|
||||||
|
strcpy(ua_ptr->ua_remote_ip, OPC_SERVER);
|
||||||
|
ua_ptr->act = UA_ACT_ATTR;
|
||||||
|
memcpy(&ua_ptr->ua_id, &test_nodeid, sizeof(test_nodeid));
|
||||||
|
|
||||||
|
if(init_flag)
|
||||||
|
return;
|
||||||
|
init_flag = 1;
|
||||||
|
|
||||||
|
if(PlcDevRegister(&plc_demo_dev, NULL, plc_demo_dev.name) != EOK)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PlcDeviceAttachToChannel(plc_demo_dev.name, PLC_CH_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlcReadUATask(void* arg)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct PlcOps* ops = NULL;
|
||||||
|
char buf[PLC_BUF_SIZE];
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
PlcCtrlDemoInit();
|
||||||
|
ops = plc_demo_dev.ops;
|
||||||
|
ret = ops->open(&plc_demo_dev);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
plc_print("plc: [%s] open failed %#x\n", __func__, ret);
|
||||||
|
// free(plc_demo_dev.priv_data);
|
||||||
|
// plc_demo_dev.priv_data = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ops->read(&plc_demo_dev, buf, PLC_BUF_SIZE);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
plc_print("plc: [%s] read failed %x\n", __func__, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
ops->close(&plc_demo_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlcReadTest(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
static char node_str[UA_NODE_LEN];
|
||||||
|
memset(node_str, 0, sizeof(node_str));
|
||||||
|
|
||||||
|
if(argc > 1)
|
||||||
|
{
|
||||||
|
plc_print("plc: arg %s\n", argv[1]);
|
||||||
|
|
||||||
|
if(sscanf(argv[1], PLC_NS_FORMAT, &test_nodeid.namespaceIndex, node_str) != EOF)
|
||||||
|
{
|
||||||
|
if(isdigit(node_str[0]))
|
||||||
|
{
|
||||||
|
test_nodeid.identifierType = UA_NODEIDTYPE_NUMERIC;
|
||||||
|
test_nodeid.identifier.numeric = atoi(node_str);
|
||||||
|
plc_print("ns %d num %d\n", test_nodeid.namespaceIndex, test_nodeid.identifier.numeric);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
test_nodeid.identifierType = UA_NODEIDTYPE_STRING;
|
||||||
|
test_nodeid.identifier.string.length = strlen(node_str);
|
||||||
|
test_nodeid.identifier.string.data = node_str;
|
||||||
|
plc_print("ns %d str %s\n", test_nodeid.namespaceIndex, test_nodeid.identifier.string.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_thread_new("plc read", PlcReadUATask, NULL, PLC_STACK_SIZE, PLC_TASK_PRIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
|
PlcRead, PlcReadTest, Read PLC);
|
||||||
|
|
||||||
|
void PlcWriteUATask(void* arg)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct PlcOps* ops = NULL;
|
||||||
|
char buf[PLC_BUF_SIZE];
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
PlcCtrlDemoInit();
|
||||||
|
|
||||||
|
ops = plc_demo_dev.ops;
|
||||||
|
ret = ops->open(&plc_demo_dev);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
plc_print("plc: [%s] open failed %#x\n", __func__, ret);
|
||||||
|
// free(plc_demo_dev.priv_data);
|
||||||
|
// plc_demo_dev.priv_data = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ops->write(&plc_demo_dev, arg, PLC_BUF_SIZE);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
plc_print("plc: [%s] read failed\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
ops->close(&plc_demo_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlcWriteTest(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
static char node_str[UA_NODE_LEN];
|
||||||
|
static char val_param[UA_NODE_LEN];
|
||||||
|
memset(node_str, 0, sizeof(node_str));
|
||||||
|
memset(val_param, 0, sizeof(val_param));
|
||||||
|
|
||||||
|
if(argc > 1)
|
||||||
|
{
|
||||||
|
plc_print("plc: arg %s\n", argv[1]);
|
||||||
|
|
||||||
|
if(sscanf(argv[1], PLC_NS_FORMAT, &test_nodeid.namespaceIndex, node_str) != EOF)
|
||||||
|
{
|
||||||
|
if(isdigit(node_str[0]))
|
||||||
|
{
|
||||||
|
test_nodeid.identifierType = UA_NODEIDTYPE_NUMERIC;
|
||||||
|
test_nodeid.identifier.numeric = atoi(node_str);
|
||||||
|
plc_print("ns %d num %d\n", test_nodeid.namespaceIndex, test_nodeid.identifier.numeric);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
test_nodeid.identifierType = UA_NODEIDTYPE_STRING;
|
||||||
|
test_nodeid.identifier.string.length = strlen(node_str);
|
||||||
|
test_nodeid.identifier.string.data = node_str;
|
||||||
|
plc_print("ns %d str %s\n", test_nodeid.namespaceIndex, test_nodeid.identifier.string.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argc > 2)
|
||||||
|
{
|
||||||
|
strcpy(val_param, argv[2]);
|
||||||
|
plc_print("write value %s\n", val_param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_thread_new("plc write", PlcWriteUATask, val_param, PLC_STACK_SIZE, PLC_TASK_PRIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
|
PlcWrite, PlcWriteTest, Read PLC);
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021 AIIT XUOS Lab
|
|
||||||
* XiUOS is licensed under Mulan PSL v2.
|
|
||||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
||||||
* You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
||||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file ua_demo.c
|
|
||||||
* @brief Demo for OpcUa function
|
|
||||||
* @version 1.0
|
|
||||||
* @author AIIT XUOS Lab
|
|
||||||
* @date 2021.11.11
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "open62541.h"
|
|
||||||
#include "ua_api.h"
|
|
||||||
#include "sys_arch.h"
|
|
||||||
#include "plc_bus.h"
|
|
||||||
#include "plc_dev.h"
|
|
||||||
|
|
||||||
#define PLC_BUS_NAME "PLC"
|
|
||||||
#define PLC_DRV_NAME "OPCUA"
|
|
||||||
#define PLC_DEV_NAME "PLC_1"
|
|
||||||
|
|
||||||
#define PLC_BUF_LEN 1000
|
|
||||||
|
|
||||||
#define PLC_STACK_SIZE 4096
|
|
||||||
#define PLC_TASK_PRIO 15
|
|
||||||
|
|
||||||
struct PlcBus plc_demo_bus;
|
|
||||||
struct PlcDriver plc_demo_drv;
|
|
||||||
struct PlcDevice plc_demo_dev;
|
|
||||||
|
|
||||||
char plc_demo_ip[] = {192, 168, 250, 5};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
void PlcTestInit(void)
|
|
||||||
{
|
|
||||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, plc_demo_ip);
|
|
||||||
|
|
||||||
PlcBusInit(&plc_demo_bus, PLC_BUS_NAME);
|
|
||||||
PlcDriverInit(&plc_demo_drv, PLC_DRV_NAME);
|
|
||||||
PlcDriverAttachToBus(PLC_DRV_NAME, PLC_BUS_NAME);
|
|
||||||
|
|
||||||
// register plc device
|
|
||||||
plc_demo_dev.state = DEV_INIT;
|
|
||||||
PlcDevRegister(&plc_demo_dev, NULL, PLC_DEV_NAME);
|
|
||||||
|
|
||||||
PlcDeviceAttachToBus(PLC_DEV_NAME, PLC_BUS_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlcReadUATask(void *arg)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
struct PlcOps *ops = NULL;
|
|
||||||
char buf[PLC_BUF_LEN];
|
|
||||||
|
|
||||||
plc_demo_dev.priv_data = (ua_dev_t *)malloc(sizeof(ua_dev_t));
|
|
||||||
ua_dev_t *ua_ptr = plc_demo_dev.priv_data;
|
|
||||||
memset(ua_ptr, 0, sizeof(ua_dev_t));
|
|
||||||
strcpy(ua_ptr->ua_remote_ip, OPC_SERVER);
|
|
||||||
|
|
||||||
PlcTestInit();
|
|
||||||
plc_demo_dev.net = PLC_IND_ENET_OPCUA;
|
|
||||||
ops = plc_demo_dev.ops;
|
|
||||||
ret = ops->open(&plc_demo_dev);
|
|
||||||
if(EOK != ret)
|
|
||||||
{
|
|
||||||
plc_print("plc: [%s] open failed %#x\n", __func__, ret);
|
|
||||||
free(plc_demo_dev.priv_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ret = ops->read(&plc_demo_dev, buf, PLC_BUF_LEN);
|
|
||||||
if(EOK != ret)
|
|
||||||
{
|
|
||||||
plc_print("plc: [%s] read failed\n", __func__);
|
|
||||||
}
|
|
||||||
free(plc_demo_dev.priv_data);
|
|
||||||
ops->close(&plc_demo_dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlcReadTest(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
sys_thread_new("plc read", PlcReadUATask, NULL, PLC_STACK_SIZE, PLC_TASK_PRIO);
|
|
||||||
}
|
|
||||||
|
|
||||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
|
||||||
plc, PlcReadTest, Read PLC);
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file plc_show_demo.c
|
||||||
|
* @brief Demo for PLC information show
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2022.02.24
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PLC_DEMO_H_
|
||||||
|
#define __PLC_DEMO_H_
|
||||||
|
|
||||||
|
#define PLC_CH_NAME "PLC"
|
||||||
|
#define PLC_DRV_NAME "OPCUA"
|
||||||
|
|
||||||
|
#define PLC_BUF_SIZE 128
|
||||||
|
|
||||||
|
#define PLC_STACK_SIZE 4096
|
||||||
|
#define PLC_TASK_PRIO 15
|
||||||
|
|
||||||
|
extern struct PlcChannel plc_demo_ch;
|
||||||
|
extern struct PlcDriver plc_demo_drv;
|
||||||
|
extern struct PlcDevice plc_demo_dev;
|
||||||
|
|
||||||
|
void PlcDemoChannelDrvInit(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,256 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file plc_show_demo.c
|
||||||
|
* @brief Demo for PLC information show
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2022.02.24
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "transform.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
#include "open62541.h"
|
||||||
|
#include "ua_api.h"
|
||||||
|
#include "sys_arch.h"
|
||||||
|
#include "plc_ch.h"
|
||||||
|
#include "plc_dev.h"
|
||||||
|
#include "plc_demo.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define PLC_DEMO_NUM 5
|
||||||
|
|
||||||
|
struct PlcDevice plc_demo_array[PLC_DEMO_NUM];
|
||||||
|
|
||||||
|
typedef struct PlcShowParam
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
char* vector;
|
||||||
|
char* model;
|
||||||
|
char* product;
|
||||||
|
} PlcShowParamType;
|
||||||
|
|
||||||
|
PlcShowParamType plc_demo_param[PLC_NAME_SIZE] =
|
||||||
|
{
|
||||||
|
{1, "SIEMENS", "S7-1500", "CPU 1512SP-1PN"},
|
||||||
|
{2, "SIEMENS", "S7-1200", "CPU 1215C"},
|
||||||
|
{3, "SIEMSNS", "S7-200", "CPU SR60"},
|
||||||
|
{4, "B&R", "X20", "X20 CP1586"},
|
||||||
|
{5, "B&R", "X20", "X20 CP1381"}
|
||||||
|
};
|
||||||
|
|
||||||
|
static char* const channel_type_str[] =
|
||||||
|
{
|
||||||
|
"PLC_Channel",
|
||||||
|
"Unknown"
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DoublelistType plcdev_list;
|
||||||
|
extern DoublelistType ch_linklist;
|
||||||
|
|
||||||
|
void PlcShowTitle(const char* item_array[])
|
||||||
|
{
|
||||||
|
int i = 0, max_len = 65;
|
||||||
|
KPrintf(" %-15s%-15s%-15s%-15s%-20s\n", item_array[0], item_array[1], item_array[2], item_array[3], item_array[4]);
|
||||||
|
|
||||||
|
while(i < max_len)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if(max_len == i)
|
||||||
|
{
|
||||||
|
KPrintf("-\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ChDrvType ShowChannelFindDriver(struct Channel* ch)
|
||||||
|
{
|
||||||
|
struct ChDrv* driver = NONE;
|
||||||
|
DoublelistType* node = NONE;
|
||||||
|
DoublelistType* head = &ch->ch_drvlink;
|
||||||
|
|
||||||
|
for(node = head->node_next; node != head; node = node->node_next)
|
||||||
|
{
|
||||||
|
driver = DOUBLE_LIST_ENTRY(node, struct ChDrv, driver_link);
|
||||||
|
return driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlcShowChannel(void)
|
||||||
|
{
|
||||||
|
ChannelType ch;
|
||||||
|
ChDrvType driver;
|
||||||
|
ChDevType device;
|
||||||
|
int dev_cnt;
|
||||||
|
DoublelistType* ch_node = NONE;
|
||||||
|
DoublelistType* ch_head = &ch_linklist;
|
||||||
|
const char* item_array[] = {"ch_type", "ch_name", "drv_name", "dev_name", "cnt"};
|
||||||
|
PlcShowTitle(item_array);
|
||||||
|
ch_node = ch_head->node_next;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ch = DOUBLE_LIST_ENTRY(ch_node, struct Channel, ch_link);
|
||||||
|
|
||||||
|
if((ch) && (ch->ch_type == CH_PLC_TYPE))
|
||||||
|
{
|
||||||
|
KPrintf("%s", " ");
|
||||||
|
KPrintf("%-15s%-15s",
|
||||||
|
channel_type_str[ch->ch_type],
|
||||||
|
ch->ch_name);
|
||||||
|
|
||||||
|
driver = ShowChannelFindDriver(ch);
|
||||||
|
|
||||||
|
if(driver)
|
||||||
|
{
|
||||||
|
KPrintf("%-15s", driver->drv_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("%-15s", "nil");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ch->haldev_cnt)
|
||||||
|
{
|
||||||
|
DoublelistType* dev_node = NONE;
|
||||||
|
DoublelistType* dev_head = &ch->ch_devlink;
|
||||||
|
dev_node = dev_head->node_next;
|
||||||
|
dev_cnt = 1;
|
||||||
|
|
||||||
|
while(dev_node != dev_head)
|
||||||
|
{
|
||||||
|
device = DOUBLE_LIST_ENTRY(dev_node, struct ChDev, dev_link);
|
||||||
|
|
||||||
|
if(1 == dev_cnt)
|
||||||
|
{
|
||||||
|
if(device)
|
||||||
|
{
|
||||||
|
KPrintf("%-16s%-4d\n", device->dev_name, dev_cnt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("%-16s%-4d\n", "nil", dev_cnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("%46s", " ");
|
||||||
|
|
||||||
|
if(device)
|
||||||
|
{
|
||||||
|
KPrintf("%-16s%-4d\n", device->dev_name, dev_cnt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("%-16s%-4d\n", "nil", dev_cnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_cnt++;
|
||||||
|
dev_node = dev_node->node_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ch_node = ch_node->node_next;
|
||||||
|
}
|
||||||
|
while(ch_node != ch_head);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
|
ShowChannel, PlcShowChannel, Show PLC information);
|
||||||
|
|
||||||
|
static void PlcShowDemoInit(void)
|
||||||
|
{
|
||||||
|
static uint8_t init_flag = 0;
|
||||||
|
int i;
|
||||||
|
PlcDemoChannelDrvInit();
|
||||||
|
|
||||||
|
for(i = 0; i < PLC_DEMO_NUM; i++)
|
||||||
|
{
|
||||||
|
// register plc device
|
||||||
|
plc_demo_array[i].state = CHDEV_INIT;
|
||||||
|
snprintf(plc_demo_array[i].name, PLC_NAME_SIZE, "PLC Demo %d", i);
|
||||||
|
plc_demo_array[i].info.vendor = plc_demo_param[i].vector;
|
||||||
|
plc_demo_array[i].info.model = plc_demo_param[i].model;
|
||||||
|
plc_demo_array[i].info.id = plc_demo_param[i].id;
|
||||||
|
plc_demo_array[i].info.product = plc_demo_param[i].product;
|
||||||
|
plc_demo_array[i].net = PLC_IND_ENET_OPCUA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(init_flag)
|
||||||
|
return;
|
||||||
|
init_flag = 1;
|
||||||
|
|
||||||
|
for(i = 0; i < PLC_DEMO_NUM; i++)
|
||||||
|
{
|
||||||
|
if(PlcDevRegister(&plc_demo_array[i], NULL, plc_demo_array[i].name) == EOK)
|
||||||
|
{
|
||||||
|
PlcDeviceAttachToChannel(plc_demo_array[i].name, PLC_CH_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlcShowDev(void)
|
||||||
|
{
|
||||||
|
PlcDeviceType* plc_dev;
|
||||||
|
ChDrvType driver;
|
||||||
|
ChDevType device;
|
||||||
|
DoublelistType* plc_node = NONE;
|
||||||
|
DoublelistType* plc_head = &plcdev_list;
|
||||||
|
const char* item_array[] = {"device", "vendor", "model", "product", "id"};
|
||||||
|
PlcShowDemoInit();
|
||||||
|
PlcShowTitle(item_array);
|
||||||
|
plc_node = plc_head->node_next;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
plc_dev = DOUBLE_LIST_ENTRY(plc_node, struct PlcDevice, link);
|
||||||
|
|
||||||
|
if(plc_dev)
|
||||||
|
{
|
||||||
|
KPrintf("%s", " ");
|
||||||
|
KPrintf("%-15s%-15s%-15s%-15s%-20d",
|
||||||
|
plc_dev->name,
|
||||||
|
plc_dev->info.vendor,
|
||||||
|
plc_dev->info.model,
|
||||||
|
plc_dev->info.product,
|
||||||
|
plc_dev->info.id);
|
||||||
|
KPrintf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
plc_node = plc_node->node_next;
|
||||||
|
}
|
||||||
|
while(plc_node != plc_head);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
|
ShowPlc, PlcShowDev, Show PLC information);
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
SRC_FILES := ua_data.c open62541.c ua_client.c ua_server.c ua_api.c
|
SRC_FILES := ua_data.c open62541.c ua_client.c ua_server.c ua_api.c ua_test.c
|
||||||
|
|
||||||
include $(KERNEL_ROOT)/compiler.mk
|
include $(KERNEL_ROOT)/compiler.mk
|
||||||
|
|
|
@ -44256,7 +44256,7 @@ UA_Client_run_iterate(UA_Client *client, UA_UInt32 timeout) {
|
||||||
client->sessionState < UA_SESSIONSTATE_ACTIVATED) {
|
client->sessionState < UA_SESSIONSTATE_ACTIVATED) {
|
||||||
retval = connectIterate(client, timeout);
|
retval = connectIterate(client, timeout);
|
||||||
notifyClientState(client);
|
notifyClientState(client);
|
||||||
lw_print("lw: [%s] ret %d timeout %d state %d ch %d\n", __func__, retval, timeout,
|
ua_print("lw: [%s] ret %d timeout %d state %d ch %d\n", __func__, retval, timeout,
|
||||||
client->sessionState, client->channel.state);
|
client->sessionState, client->channel.state);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -45299,7 +45299,7 @@ connectIterate(UA_Client *client, UA_UInt32 timeout) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
lw_print("lw: [%s] sess %d conn %d\n", __func__, client->sessionState, client->connectStatus);
|
ua_print("ua: [%s] sess %d conn %d\n", __func__, client->sessionState, client->connectStatus);
|
||||||
return client->connectStatus;
|
return client->connectStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,33 +10,39 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ua_api.c
|
||||||
|
* @brief Demo for OpcUa function
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.11.11
|
||||||
|
*/
|
||||||
|
|
||||||
#include "open62541.h"
|
#include "open62541.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "ua_api.h"
|
#include "ua_api.h"
|
||||||
|
|
||||||
|
|
||||||
int ua_open(void *dev)
|
int ua_open(void *dev)
|
||||||
{
|
{
|
||||||
ua_dev_t *pdev = (ua_dev_t *)dev;
|
UaParamType *param = (UaParamType *)dev;
|
||||||
|
|
||||||
pdev->client = UA_Client_new();
|
param->client = UA_Client_new();
|
||||||
|
|
||||||
ua_pr_info("ua: [%s] start ...\n", __func__);
|
ua_pr_info("ua: [%s] start ...\n", __func__);
|
||||||
|
|
||||||
if (pdev->client == NULL)
|
if (param->client == NULL)
|
||||||
{
|
{
|
||||||
ua_print("ua: [%s] tcp client null\n", __func__);
|
ua_print("ua: [%s] tcp client null\n", __func__);
|
||||||
return EEMPTY;
|
return EEMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
UA_ClientConfig *config = UA_Client_getConfig(pdev->client);
|
UA_ClientConfig *config = UA_Client_getConfig(param->client);
|
||||||
UA_ClientConfig_setDefault(config);
|
UA_ClientConfig_setDefault(config);
|
||||||
|
|
||||||
ua_pr_info("ua: [%s] %d %s\n", __func__, strlen(pdev->ua_remote_ip), pdev->ua_remote_ip);
|
ua_pr_info("ua: [%s] %d %s\n", __func__, strlen(param->ua_remote_ip), param->ua_remote_ip);
|
||||||
|
|
||||||
UA_StatusCode retval = UA_Client_connect(pdev->client, pdev->ua_remote_ip);
|
UA_StatusCode retval = UA_Client_connect(param->client, param->ua_remote_ip);
|
||||||
if(retval != UA_STATUSCODE_GOOD) {
|
if(retval != UA_STATUSCODE_GOOD) {
|
||||||
// UA_Client_delete(pdev->client);
|
|
||||||
ua_pr_info("ua: [%s] deleted ret %x!\n", __func__, retval);
|
ua_pr_info("ua: [%s] deleted ret %x!\n", __func__, retval);
|
||||||
return (int)retval;
|
return (int)retval;
|
||||||
}
|
}
|
||||||
|
@ -45,22 +51,43 @@ int ua_open(void *dev)
|
||||||
|
|
||||||
void ua_close(void *dev)
|
void ua_close(void *dev)
|
||||||
{
|
{
|
||||||
ua_dev_t *pdev = (ua_dev_t *)dev;
|
UaParamType *param = (UaParamType *)dev;
|
||||||
UA_Client_disconnect(pdev->client);
|
UA_Client_disconnect(param->client);
|
||||||
UA_Client_delete(pdev->client); /* Disconnects the client internally */
|
UA_Client_delete(param->client); /* Disconnects the client internally */
|
||||||
}
|
}
|
||||||
|
|
||||||
int ua_read(void *dev, void *buf, size_t len)
|
int ua_read(void *dev, void *buf, size_t len)
|
||||||
{
|
{
|
||||||
ua_dev_t *pdev = (ua_dev_t *)dev;
|
UaParamType *param = (UaParamType *)dev;
|
||||||
ua_get_server_info(pdev->client);
|
switch(param->act)
|
||||||
|
{
|
||||||
|
case UA_ACT_ATTR:
|
||||||
|
ua_read_nodeid_value(param->client, param->ua_id, buf);
|
||||||
|
break;
|
||||||
|
case UA_ACT_OBJ:
|
||||||
|
ua_test_browser_objects(param->client);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
return EOK;
|
return EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ua_write(void *dev, const void *buf, size_t len)
|
int ua_write(void *dev, const void *buf, size_t len)
|
||||||
{
|
{
|
||||||
ua_dev_t *pdev = (ua_dev_t *)dev;
|
UaParamType *param = (UaParamType *)dev;
|
||||||
|
|
||||||
|
switch(param->act)
|
||||||
|
{
|
||||||
|
case UA_ACT_ATTR:
|
||||||
|
ua_write_nodeid_value(param->client, param->ua_id, (char *)buf);
|
||||||
|
break;
|
||||||
|
case UA_ACT_OBJ:
|
||||||
|
ua_test_browser_objects(param->client);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
return EOK;
|
return EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,4 +96,3 @@ int ua_ioctl(void* dev, int cmd, void *arg)
|
||||||
return EOK;
|
return EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,35 +9,50 @@
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ua_api.h
|
||||||
|
* @brief API for OpcUa function
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.11.11
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef __UA_API_H__
|
#ifndef __UA_API_H__
|
||||||
#define __UA_API_H__
|
#define __UA_API_H__
|
||||||
|
|
||||||
#include "open62541.h"
|
#include "open62541.h"
|
||||||
|
|
||||||
#define UA_DEV_IP_LEN 128
|
#define UA_DEV_IP_LEN 48
|
||||||
#define UA_NODE_LEN 50
|
#define UA_NODE_LEN 32
|
||||||
|
|
||||||
typedef struct _ua_dev_t
|
enum UaAction_e
|
||||||
{
|
{
|
||||||
|
UA_ACT_ATTR,
|
||||||
|
UA_ACT_OBJ,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct UaParam
|
||||||
|
{
|
||||||
|
enum UaAction_e act;
|
||||||
|
UA_NodeId ua_id;
|
||||||
char ua_remote_ip[UA_DEV_IP_LEN];
|
char ua_remote_ip[UA_DEV_IP_LEN];
|
||||||
char ua_node[UA_NODE_LEN];
|
char ua_node[UA_NODE_LEN];
|
||||||
UA_Client *client;
|
UA_Client *client;
|
||||||
}ua_dev_t;
|
}UaParamType;
|
||||||
|
|
||||||
#define OPC_SERVER "opc.tcp://192.168.250.5:4840"
|
#define OPC_SERVER "opc.tcp://192.168.250.2:4840"
|
||||||
|
|
||||||
#define ua_print //KPrintf
|
#define ua_print //KPrintf
|
||||||
#define ua_trace() //KPrintf("ua: [%s] line %d checked!\n", __func__, __LINE__)
|
#define ua_trace() //KPrintf("ua: [%s] line %d checked!\n", __func__, __LINE__)
|
||||||
#define ua_pr_info KPrintf
|
#define ua_pr_info KPrintf
|
||||||
#define ua_debug
|
#define ua_debug //KPrintf
|
||||||
|
|
||||||
int ua_server_connect(void);
|
int ua_server_connect(void);
|
||||||
int ua_get_server_info(UA_Client *client);
|
|
||||||
void ua_browser_objects(UA_Client *client);
|
|
||||||
void ua_browser_nodes(UA_Client *client);
|
void ua_browser_nodes(UA_Client *client);
|
||||||
|
void ua_browser_id(UA_Client *client, UA_NodeId id);
|
||||||
void ua_read_time(UA_Client *client);
|
void ua_read_time(UA_Client *client);
|
||||||
int16 ua_test(void);
|
void ua_add_nodes(UA_Client *client);
|
||||||
|
|
||||||
|
|
||||||
int ua_open(void *dev); // open and connect PLC device
|
int ua_open(void *dev); // open and connect PLC device
|
||||||
void ua_close(void* dev); // close and disconnect PLC device
|
void ua_close(void* dev); // close and disconnect PLC device
|
||||||
|
@ -45,4 +60,12 @@ int ua_read(void* dev, void *buf, size_t len); // read data from PLC
|
||||||
int ua_write(void* dev, const void *buf, size_t len); // write data from PLC
|
int ua_write(void* dev, const void *buf, size_t len); // write data from PLC
|
||||||
int ua_ioctl(void* dev, int cmd, void *arg); // send control command to PLC
|
int ua_ioctl(void* dev, int cmd, void *arg); // send control command to PLC
|
||||||
|
|
||||||
|
char *ua_get_nodeid_str(UA_NodeId *node_id);
|
||||||
|
void ua_read_nodeid_value(UA_Client *client, UA_NodeId id, UA_Int32 *value);
|
||||||
|
void ua_write_nodeid_value(UA_Client *client, UA_NodeId id, char* value);
|
||||||
|
void ua_test_attr(UA_Client *client);
|
||||||
|
UA_StatusCode ua_read_array_value(UA_Client *client, int array_size, UA_ReadValueId *array);
|
||||||
|
void ua_test_browser_objects(UA_Client *client);
|
||||||
|
int ua_test_interact_server(UA_Client *client);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,10 +10,20 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "open62541.h"
|
/**
|
||||||
|
* @file ua_client.c
|
||||||
|
* @brief Client for OpcUa function
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.11.11
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "open62541.h"
|
||||||
#include "ua_api.h"
|
#include "ua_api.h"
|
||||||
|
|
||||||
|
#define UA_RESPONSE_TIMEOUT 10000
|
||||||
|
|
||||||
#ifdef UA_ENABLE_SUBSCRIPTIONS
|
#ifdef UA_ENABLE_SUBSCRIPTIONS
|
||||||
static void handler_TheAnswerChanged(UA_Client* client, UA_UInt32 subId, void* subContext,
|
static void handler_TheAnswerChanged(UA_Client* client, UA_UInt32 subId, void* subContext,
|
||||||
UA_UInt32 monId, void* monContext, UA_DataValue* value)
|
UA_UInt32 monId, void* monContext, UA_DataValue* value)
|
||||||
|
@ -34,7 +44,6 @@ static UA_StatusCode nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId
|
||||||
parent->namespaceIndex, parent->identifier.numeric,
|
parent->namespaceIndex, parent->identifier.numeric,
|
||||||
referenceTypeId.identifier.numeric, childId.namespaceIndex,
|
referenceTypeId.identifier.numeric, childId.namespaceIndex,
|
||||||
childId.identifier.numeric);
|
childId.identifier.numeric);
|
||||||
|
|
||||||
return UA_STATUSCODE_GOOD;
|
return UA_STATUSCODE_GOOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,48 +52,120 @@ int ua_get_points(UA_Client *client)
|
||||||
/* Listing endpoints */
|
/* Listing endpoints */
|
||||||
UA_EndpointDescription* endpointArray = NULL;
|
UA_EndpointDescription* endpointArray = NULL;
|
||||||
size_t endpointArraySize = 0;
|
size_t endpointArraySize = 0;
|
||||||
UA_StatusCode retval = UA_Client_getEndpoints(client, OPC_SERVER,
|
UA_StatusCode ret = UA_Client_getEndpoints(client, OPC_SERVER,
|
||||||
&endpointArraySize, &endpointArray);
|
&endpointArraySize, &endpointArray);
|
||||||
if(retval != UA_STATUSCODE_GOOD)
|
|
||||||
|
if(ret != UA_STATUSCODE_GOOD)
|
||||||
{
|
{
|
||||||
UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
|
UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ua_print("%i endpoints found\n", (int)endpointArraySize);
|
ua_print("%i endpoints found\n", (int)endpointArraySize);
|
||||||
|
|
||||||
for(size_t i=0; i<endpointArraySize; i++)
|
for(size_t i=0; i<endpointArraySize; i++)
|
||||||
{
|
{
|
||||||
ua_print("URL of endpoint %i is %.*s\n", (int)i,
|
ua_print("URL of endpoint %i is %.*s\n", (int)i,
|
||||||
(int)endpointArray[i].endpointUrl.length,
|
(int)endpointArray[i].endpointUrl.length,
|
||||||
endpointArray[i].endpointUrl.data);
|
endpointArray[i].endpointUrl.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
|
UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ua_browser_objects(UA_Client *client)
|
void ua_print_value(UA_Variant* val)
|
||||||
{
|
{
|
||||||
/* Browse some objects */
|
if(val->type == &UA_TYPES[UA_TYPES_LOCALIZEDTEXT])
|
||||||
ua_pr_info("Browsing nodes in objects folder:\n");
|
{
|
||||||
|
UA_LocalizedText* ptr = (UA_LocalizedText*)val->data;
|
||||||
|
ua_pr_info("%.*s (Text)\n", ptr->text.length, ptr->text.data);
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_UINT32])
|
||||||
|
{
|
||||||
|
UA_UInt32* ptr = (UA_UInt32*)val->data;
|
||||||
|
ua_pr_info("%d (UInt32)\n", *ptr);
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_BOOLEAN])
|
||||||
|
{
|
||||||
|
UA_Boolean* ptr = (UA_Boolean*)val->data;
|
||||||
|
ua_pr_info("%i (BOOL)\n", *ptr);
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_INT32])
|
||||||
|
{
|
||||||
|
UA_Int32* ptr = (UA_Int32*)val->data;
|
||||||
|
ua_pr_info("%d (Int32)\n", *ptr);
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_INT16])
|
||||||
|
{
|
||||||
|
UA_Int16* ptr = (UA_Int16*)val->data;
|
||||||
|
ua_pr_info("%d (Int16)\n", *ptr);
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_STRING])
|
||||||
|
{
|
||||||
|
UA_String* ptr = (UA_String*)val->data;
|
||||||
|
ua_pr_info("%*.s (String)\n", ptr->length, ptr->data);
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_DATETIME])
|
||||||
|
{
|
||||||
|
UA_DateTime* ptr = (UA_DateTime*)val->data;
|
||||||
|
UA_DateTimeStruct dts = UA_DateTime_toStruct(*ptr);
|
||||||
|
ua_pr_info("%d-%d-%d %d:%d:%d.%03d (Time)\n",
|
||||||
|
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UA_BrowseRequest bReq;
|
char *ua_get_nodeid_str(UA_NodeId *node_id)
|
||||||
UA_BrowseRequest_init(&bReq);
|
{
|
||||||
|
static char nodeid_str[UA_NODE_LEN] = {0};
|
||||||
|
|
||||||
bReq.requestedMaxReferencesPerNode = 0;
|
switch(node_id->identifierType)
|
||||||
bReq.nodesToBrowse = UA_BrowseDescription_new();
|
{
|
||||||
bReq.nodesToBrowseSize = 1;
|
case UA_NODEIDTYPE_NUMERIC:
|
||||||
bReq.nodesToBrowse[0].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); /* browse objects folder */
|
snprintf(nodeid_str, UA_NODE_LEN, "n%d,%d", node_id->namespaceIndex, node_id->identifier.numeric);
|
||||||
bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; /* return everything */
|
break;
|
||||||
|
case UA_NODEIDTYPE_STRING:
|
||||||
|
snprintf(nodeid_str, UA_NODE_LEN, "n%d,%.*s", node_id->namespaceIndex, node_id->identifier.string.length,
|
||||||
|
node_id->identifier.string.data);
|
||||||
|
break;
|
||||||
|
case UA_NODEIDTYPE_BYTESTRING:
|
||||||
|
snprintf(nodeid_str, UA_NODE_LEN, "n%d,%s", node_id->namespaceIndex, node_id->identifier.byteString.data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nodeid_str;
|
||||||
|
}
|
||||||
|
|
||||||
UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
|
void ua_print_nodeid(UA_NodeId *node_id)
|
||||||
|
{
|
||||||
|
switch(node_id->identifierType)
|
||||||
|
{
|
||||||
|
case UA_NODEIDTYPE_NUMERIC:
|
||||||
|
ua_pr_info(" NodeID n%d,%d ", node_id->namespaceIndex, node_id->identifier.numeric);
|
||||||
|
break;
|
||||||
|
case UA_NODEIDTYPE_STRING:
|
||||||
|
ua_pr_info(" NodeID n%d,%.*s ", node_id->namespaceIndex, node_id->identifier.string.length,
|
||||||
|
node_id->identifier.string.data);
|
||||||
|
break;
|
||||||
|
case UA_NODEIDTYPE_BYTESTRING:
|
||||||
|
ua_pr_info(" NodeID n%d,%s ", node_id->namespaceIndex, node_id->identifier.byteString.data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ua_print_object(UA_BrowseResponse* res)
|
||||||
|
{
|
||||||
ua_pr_info("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");
|
ua_pr_info("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");
|
||||||
|
|
||||||
for(size_t i = 0; i < bResp.resultsSize; ++i)
|
for(size_t i = 0; i < res->resultsSize; ++i)
|
||||||
{
|
{
|
||||||
for(size_t j = 0; j < bResp.results[i].referencesSize; ++j)
|
for(size_t j = 0; j < res->results[i].referencesSize; ++j)
|
||||||
{
|
{
|
||||||
UA_ReferenceDescription *ref = &(bResp.results[i].references[j]);
|
UA_ReferenceDescription* ref = &(res->results[i].references[j]);
|
||||||
|
|
||||||
if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC)
|
if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC)
|
||||||
{
|
{
|
||||||
ua_pr_info("%-9d %-16d %-16.*s %-16.*s\n", ref->nodeId.nodeId.namespaceIndex,
|
ua_pr_info("%-9d %-16d %-16.*s %-16.*s\n", ref->nodeId.nodeId.namespaceIndex,
|
||||||
|
@ -100,92 +181,191 @@ void ua_browser_objects(UA_Client *client)
|
||||||
(int)ref->browseName.name.length, ref->browseName.name.data,
|
(int)ref->browseName.name.length, ref->browseName.name.data,
|
||||||
(int)ref->displayName.text.length, ref->displayName.text.data);
|
(int)ref->displayName.text.length, ref->displayName.text.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: distinguish further types */
|
/* TODO: distinguish further types */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ua_pr_info("\n");
|
ua_pr_info("\n");
|
||||||
UA_BrowseRequest_clear(&bReq);
|
}
|
||||||
UA_BrowseResponse_clear(&bResp);
|
|
||||||
|
UA_StatusCode ua_read_array_value(UA_Client* client, int array_size, UA_ReadValueId* array)
|
||||||
|
{
|
||||||
|
UA_ReadRequest request;
|
||||||
|
UA_ReadRequest_init(&request);
|
||||||
|
request.nodesToRead = array;
|
||||||
|
request.nodesToReadSize = array_size;
|
||||||
|
UA_ReadResponse response = UA_Client_Service_read(client, request);
|
||||||
|
|
||||||
|
if((response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
|
||||||
|
|| (response.resultsSize != array_size))
|
||||||
|
{
|
||||||
|
UA_ReadResponse_clear(&response);
|
||||||
|
ua_pr_info("ua: [%s] read failed 0x%x\n", __func__,
|
||||||
|
response.responseHeader.serviceResult);
|
||||||
|
return UA_STATUSCODE_BADUNEXPECTEDERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
UA_StatusCode* arr_ret = malloc(array_size * sizeof(UA_StatusCode));
|
||||||
|
|
||||||
|
for(int i = 0; i < array_size; ++i)
|
||||||
|
{
|
||||||
|
if((response.results[i].status == UA_STATUSCODE_GOOD)
|
||||||
|
&& (response.results[i].hasValue))
|
||||||
|
{
|
||||||
|
ua_pr_info("node %s: ", ua_get_nodeid_str(&array[i].nodeId));
|
||||||
|
ua_print_value(&response.results[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ua_pr_info("\n");
|
||||||
|
|
||||||
|
free(arr_ret);
|
||||||
|
UA_ReadResponse_clear(&response);
|
||||||
|
return UA_STATUSCODE_GOOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ua_browser_id(UA_Client* client, UA_NodeId id)
|
||||||
|
{
|
||||||
|
/* Browse some objects */
|
||||||
|
ua_pr_info("Browsing nodes in objects folder:\n");
|
||||||
|
UA_BrowseRequest bReq;
|
||||||
|
UA_BrowseRequest_init(&bReq);
|
||||||
|
bReq.requestedMaxReferencesPerNode = 0;
|
||||||
|
bReq.nodesToBrowse = UA_BrowseDescription_new();
|
||||||
|
bReq.nodesToBrowseSize = 1;
|
||||||
|
bReq.nodesToBrowse[0].nodeId = id; /* browse objects folder */
|
||||||
|
bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; /* return everything */
|
||||||
|
UA_BrowseResponse res = UA_Client_Service_browse(client, bReq);
|
||||||
|
ua_print_object(&res);
|
||||||
|
UA_BrowseResponse_clear(&res);
|
||||||
|
// UA_BrowseRequest_clear(&bReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ua_browser_nodes(UA_Client* client)
|
void ua_browser_nodes(UA_Client* client)
|
||||||
{
|
{
|
||||||
/* Same thing, this time using the node iterator... */
|
|
||||||
UA_NodeId* parent = UA_NodeId_new();
|
UA_NodeId* parent = UA_NodeId_new();
|
||||||
*parent = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
|
*parent = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
|
||||||
UA_Client_forEachChildNodeCall(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
UA_Client_forEachChildNodeCall(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), nodeIter, (void*) parent);
|
||||||
nodeIter, (void *) parent);
|
|
||||||
UA_NodeId_delete(parent);
|
UA_NodeId_delete(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
UA_UInt32 ua_start_sub(UA_Client *client)
|
UA_UInt32 ua_start_sub(UA_Client* client, UA_NodeId node_id)
|
||||||
{
|
{
|
||||||
/* Create a subscription */
|
/* Create a subscription */
|
||||||
UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
|
UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
|
||||||
UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,
|
UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
|
|
||||||
UA_UInt32 subId = response.subscriptionId;
|
UA_UInt32 subId = response.subscriptionId;
|
||||||
|
|
||||||
if(response.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
|
if(response.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
ua_print("Create subscription succeeded, id %u\n", subId);
|
ua_print("Create subscription succeeded, id %u\n", subId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ua_print("Create subscription failed, id %u\n", response.responseHeader.serviceResult);
|
||||||
|
return response.responseHeader.serviceResult;
|
||||||
|
}
|
||||||
|
|
||||||
UA_MonitoredItemCreateRequest monRequest =
|
UA_MonitoredItemCreateRequest monRequest =
|
||||||
UA_MonitoredItemCreateRequest_default(UA_NODEID_STRING(1, "the.answer"));
|
UA_MonitoredItemCreateRequest_default(node_id);
|
||||||
|
|
||||||
UA_MonitoredItemCreateResult monResponse =
|
UA_MonitoredItemCreateResult monResponse =
|
||||||
UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,
|
UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,
|
||||||
UA_TIMESTAMPSTORETURN_BOTH,
|
UA_TIMESTAMPSTORETURN_BOTH,
|
||||||
monRequest, NULL, handler_TheAnswerChanged, NULL);
|
monRequest, NULL, handler_TheAnswerChanged, NULL);
|
||||||
if(monResponse.statusCode == UA_STATUSCODE_GOOD)
|
|
||||||
ua_print("Monitoring 'the.answer', id %u\n", monResponse.monitoredItemId);
|
|
||||||
|
|
||||||
|
if(monResponse.statusCode == UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
|
ua_print("Monitoring 'the.answer', id %u\n", monResponse.monitoredItemId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ua_print("%s return 0x%x\n", __func__, monResponse.statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
/* The first publish request should return the initial value of the variable */
|
/* The first publish request should return the initial value of the variable */
|
||||||
UA_Client_run_iterate(client, 1000);
|
UA_Client_run_iterate(client, UA_RESPONSE_TIMEOUT);
|
||||||
return subId;
|
return subId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ua_read_attr(UA_Client *client)
|
void ua_write_nodeid_value(UA_Client* client, UA_NodeId id, char* value)
|
||||||
{
|
{
|
||||||
/* Read attribute */
|
UA_Boolean bool_val;
|
||||||
UA_Int32 value = 0;
|
uint32_t integer_val;
|
||||||
ua_pr_info("\nReading the value of node (1, \"the.answer\"):\n");
|
|
||||||
UA_Variant *val = UA_Variant_new();
|
|
||||||
UA_StatusCode retval = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "the.answer"), val);
|
|
||||||
if(retval == UA_STATUSCODE_GOOD && UA_Variant_isScalar(val) &&
|
|
||||||
val->type == &UA_TYPES[UA_TYPES_INT32]) {
|
|
||||||
value = *(UA_Int32*)val->data;
|
|
||||||
ua_pr_info("the value is: %i\n", value);
|
|
||||||
}
|
|
||||||
UA_Variant_delete(val);
|
|
||||||
|
|
||||||
/* Write node attribute */
|
|
||||||
value++;
|
|
||||||
ua_pr_info("\nWriting a value of node (1, \"the.answer\"):\n");
|
|
||||||
UA_WriteRequest wReq;
|
UA_WriteRequest wReq;
|
||||||
UA_WriteRequest_init(&wReq);
|
UA_WriteRequest_init(&wReq);
|
||||||
|
|
||||||
wReq.nodesToWrite = UA_WriteValue_new();
|
wReq.nodesToWrite = UA_WriteValue_new();
|
||||||
wReq.nodesToWriteSize = 1;
|
wReq.nodesToWriteSize = 1;
|
||||||
wReq.nodesToWrite[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
|
|
||||||
|
if(strncmp(value, "1b", 2) == 0)
|
||||||
|
{
|
||||||
|
wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
|
||||||
|
bool_val = 1;
|
||||||
|
wReq.nodesToWrite[0].value.value.data = &bool_val;
|
||||||
|
}
|
||||||
|
else if(strncmp(value, "0b", 2) == 0)
|
||||||
|
{
|
||||||
|
wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
|
||||||
|
bool_val = 0;
|
||||||
|
wReq.nodesToWrite[0].value.value.data = &bool_val;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_INT16];
|
||||||
|
sscanf(value, "%d", &integer_val);
|
||||||
|
wReq.nodesToWrite[0].value.value.data = &integer_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
wReq.nodesToWrite[0].nodeId = id;
|
||||||
wReq.nodesToWrite[0].attributeId = UA_ATTRIBUTEID_VALUE;
|
wReq.nodesToWrite[0].attributeId = UA_ATTRIBUTEID_VALUE;
|
||||||
wReq.nodesToWrite[0].value.hasValue = true;
|
wReq.nodesToWrite[0].value.hasValue = true;
|
||||||
wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_INT32];
|
|
||||||
wReq.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA_NODELETE; /* do not free the integer on deletion */
|
wReq.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA_NODELETE; /* do not free the integer on deletion */
|
||||||
wReq.nodesToWrite[0].value.value.data = &value;
|
|
||||||
UA_WriteResponse wResp = UA_Client_Service_write(client, wReq);
|
UA_WriteResponse wResp = UA_Client_Service_write(client, wReq);
|
||||||
|
|
||||||
if(wResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
|
if(wResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
|
||||||
ua_pr_info("the new value is: %i\n", value);
|
{
|
||||||
|
ua_pr_info("write new value is: %s\n", value);
|
||||||
|
}
|
||||||
|
|
||||||
UA_WriteRequest_clear(&wReq);
|
UA_WriteRequest_clear(&wReq);
|
||||||
UA_WriteResponse_clear(&wResp);
|
UA_WriteResponse_clear(&wResp);
|
||||||
|
|
||||||
/* Write node attribute (using the highlevel API) */
|
// /* Write node attribute (using the highlevel API) */
|
||||||
value++;
|
// value++;
|
||||||
UA_Variant *myVariant = UA_Variant_new();
|
// UA_Variant *myVariant = UA_Variant_new();
|
||||||
UA_Variant_setScalarCopy(myVariant, &value, &UA_TYPES[UA_TYPES_INT32]);
|
// UA_Variant_setScalarCopy(myVariant, &value, &UA_TYPES[UA_TYPES_INT32]);
|
||||||
UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "the.answer"), myVariant);
|
// UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, UA_NODE_STR), myVariant);
|
||||||
UA_Variant_delete(myVariant);
|
// UA_Variant_delete(myVariant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read attribute */
|
||||||
|
void ua_read_nodeid_value(UA_Client* client, UA_NodeId id, UA_Int32 *value)
|
||||||
|
{
|
||||||
|
UA_Variant* val = UA_Variant_new();
|
||||||
|
UA_StatusCode ret = UA_Client_readValueAttribute(client, id, val);
|
||||||
|
|
||||||
|
if(ret == UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
|
ua_print_value(val);
|
||||||
|
if(UA_Variant_isScalar(val))
|
||||||
|
{
|
||||||
|
if(val->type == &UA_TYPES[UA_TYPES_BOOLEAN])
|
||||||
|
{
|
||||||
|
*value = *(UA_Boolean *)val->data;
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_INT32])
|
||||||
|
{
|
||||||
|
*value = *(UA_Int32 *)val->data;
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_INT16])
|
||||||
|
{
|
||||||
|
*value = *(UA_Int16 *)val->data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UA_Variant_delete(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ua_call_remote(UA_Client* client)
|
void ua_call_remote(UA_Client* client)
|
||||||
|
@ -197,9 +377,10 @@ void ua_call_remote(UA_Client *client)
|
||||||
UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
|
UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
|
||||||
size_t outputSize;
|
size_t outputSize;
|
||||||
UA_Variant* output;
|
UA_Variant* output;
|
||||||
UA_StatusCode retval = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
UA_StatusCode ret = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
||||||
UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
|
UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
|
||||||
if(retval == UA_STATUSCODE_GOOD)
|
|
||||||
|
if(ret == UA_STATUSCODE_GOOD)
|
||||||
{
|
{
|
||||||
ua_print("Method call was successful, and %lu returned values available.\n",
|
ua_print("Method call was successful, and %lu returned values available.\n",
|
||||||
(unsigned long)outputSize);
|
(unsigned long)outputSize);
|
||||||
|
@ -207,8 +388,9 @@ void ua_call_remote(UA_Client *client)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ua_print("Method call was unsuccessful, and %x returned values available.\n", retval);
|
ua_print("Method call was unsuccessful, and %x returned values available.\n", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
UA_Variant_clear(&input);
|
UA_Variant_clear(&input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,43 +404,52 @@ void ua_add_nodes(UA_Client *client)
|
||||||
ref_attr.displayName = UA_LOCALIZEDTEXT("en-US", "NewReference");
|
ref_attr.displayName = UA_LOCALIZEDTEXT("en-US", "NewReference");
|
||||||
ref_attr.description = UA_LOCALIZEDTEXT("en-US", "References something that might or might not exist");
|
ref_attr.description = UA_LOCALIZEDTEXT("en-US", "References something that might or might not exist");
|
||||||
ref_attr.inverseName = UA_LOCALIZEDTEXT("en-US", "IsNewlyReferencedBy");
|
ref_attr.inverseName = UA_LOCALIZEDTEXT("en-US", "IsNewlyReferencedBy");
|
||||||
UA_StatusCode retval = UA_Client_addReferenceTypeNode(client,
|
UA_StatusCode ret = UA_Client_addReferenceTypeNode(client,
|
||||||
UA_NODEID_NUMERIC(1, 12133),
|
UA_NODEID_NUMERIC(1, 12133),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
||||||
UA_QUALIFIEDNAME(1, "NewReference"),
|
UA_QUALIFIEDNAME(1, "NewReference"),
|
||||||
ref_attr, &ref_id);
|
ref_attr, &ref_id);
|
||||||
if(retval == UA_STATUSCODE_GOOD )
|
|
||||||
|
if(ret == UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
ua_print("Created 'NewReference' with numeric NodeID %u\n", ref_id.identifier.numeric);
|
ua_print("Created 'NewReference' with numeric NodeID %u\n", ref_id.identifier.numeric);
|
||||||
|
}
|
||||||
|
|
||||||
/* New ObjectType */
|
/* New ObjectType */
|
||||||
UA_NodeId objt_id;
|
UA_NodeId objt_id;
|
||||||
UA_ObjectTypeAttributes objt_attr = UA_ObjectTypeAttributes_default;
|
UA_ObjectTypeAttributes objt_attr = UA_ObjectTypeAttributes_default;
|
||||||
objt_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewObjectType");
|
objt_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewObjectType");
|
||||||
objt_attr.description = UA_LOCALIZEDTEXT("en-US", "Put innovative description here");
|
objt_attr.description = UA_LOCALIZEDTEXT("en-US", "Put innovative description here");
|
||||||
retval = UA_Client_addObjectTypeNode(client,
|
ret = UA_Client_addObjectTypeNode(client,
|
||||||
UA_NODEID_NUMERIC(1, 12134),
|
UA_NODEID_NUMERIC(1, 12134),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
||||||
UA_QUALIFIEDNAME(1, "NewObjectType"),
|
UA_QUALIFIEDNAME(1, "NewObjectType"),
|
||||||
objt_attr, &objt_id);
|
objt_attr, &objt_id);
|
||||||
if(retval == UA_STATUSCODE_GOOD)
|
|
||||||
|
if(ret == UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
ua_print("Created 'NewObjectType' with numeric NodeID %u\n", objt_id.identifier.numeric);
|
ua_print("Created 'NewObjectType' with numeric NodeID %u\n", objt_id.identifier.numeric);
|
||||||
|
}
|
||||||
|
|
||||||
/* New Object */
|
/* New Object */
|
||||||
UA_NodeId obj_id;
|
UA_NodeId obj_id;
|
||||||
UA_ObjectAttributes obj_attr = UA_ObjectAttributes_default;
|
UA_ObjectAttributes obj_attr = UA_ObjectAttributes_default;
|
||||||
obj_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewGreatNode");
|
obj_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewGreatNode");
|
||||||
obj_attr.description = UA_LOCALIZEDTEXT("de-DE", "Hier koennte Ihre Webung stehen!");
|
obj_attr.description = UA_LOCALIZEDTEXT("de-DE", "Hier koennte Ihre Webung stehen!");
|
||||||
retval = UA_Client_addObjectNode(client,
|
ret = UA_Client_addObjectNode(client,
|
||||||
UA_NODEID_NUMERIC(1, 0),
|
UA_NODEID_NUMERIC(1, 0),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
||||||
UA_QUALIFIEDNAME(1, "TheGreatNode"),
|
UA_QUALIFIEDNAME(1, "TheGreatNode"),
|
||||||
UA_NODEID_NUMERIC(1, 12134),
|
UA_NODEID_NUMERIC(1, 12134),
|
||||||
obj_attr, &obj_id);
|
obj_attr, &obj_id);
|
||||||
if(retval == UA_STATUSCODE_GOOD )
|
|
||||||
|
if(ret == UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
ua_print("Created 'NewObject' with numeric NodeID %u\n", obj_id.identifier.numeric);
|
ua_print("Created 'NewObject' with numeric NodeID %u\n", obj_id.identifier.numeric);
|
||||||
|
}
|
||||||
|
|
||||||
/* New Integer Variable */
|
/* New Integer Variable */
|
||||||
UA_NodeId var_id;
|
UA_NodeId var_id;
|
||||||
|
@ -270,68 +461,36 @@ void ua_add_nodes(UA_Client *client)
|
||||||
/* This does not copy the value */
|
/* This does not copy the value */
|
||||||
UA_Variant_setScalar(&var_attr.value, &int_value, &UA_TYPES[UA_TYPES_INT32]);
|
UA_Variant_setScalar(&var_attr.value, &int_value, &UA_TYPES[UA_TYPES_INT32]);
|
||||||
var_attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
|
var_attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
|
||||||
retval = UA_Client_addVariableNode(client,
|
ret = UA_Client_addVariableNode(client,
|
||||||
UA_NODEID_NUMERIC(1, 0), // Assign new/random NodeID
|
UA_NODEID_NUMERIC(1, 0), // Assign new/random NodeID
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
||||||
UA_QUALIFIEDNAME(0, "VariableNode"),
|
UA_QUALIFIEDNAME(0, "VariableNode"),
|
||||||
UA_NODEID_NULL, // no variable type
|
UA_NODEID_NULL, // no variable type
|
||||||
var_attr, &var_id);
|
var_attr, &var_id);
|
||||||
if(retval == UA_STATUSCODE_GOOD )
|
|
||||||
ua_print("Created 'NewVariable' with numeric NodeID %u\n", var_id.identifier.numeric);
|
|
||||||
|
|
||||||
}
|
if(ret == UA_STATUSCODE_GOOD)
|
||||||
|
|
||||||
int ua_get_server_info(UA_Client *client)
|
|
||||||
{
|
{
|
||||||
ua_browser_objects(client);
|
ua_print("Created 'NewVariable' with numeric NodeID %u\n", var_id.identifier.numeric);
|
||||||
|
}
|
||||||
/* Same thing, this time using the node iterator... */
|
|
||||||
ua_browser_nodes(client);
|
|
||||||
|
|
||||||
#ifdef UA_ENABLE_SUBSCRIPTIONS
|
|
||||||
UA_Int32 subId = ua_start_sub(client);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ua_read_attr(client);
|
|
||||||
|
|
||||||
#ifdef UA_ENABLE_SUBSCRIPTIONS
|
|
||||||
/* Take another look at the.answer */
|
|
||||||
UA_Client_run_iterate(client, 10000);
|
|
||||||
/* Delete the subscription */
|
|
||||||
if(UA_Client_Subscriptions_deleteSingle(client, subId) == UA_STATUSCODE_GOOD)
|
|
||||||
ua_print("Subscription removed\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UA_ENABLE_METHODCALLS
|
|
||||||
ua_call_remote(client);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UA_ENABLE_NODEMANAGEMENT
|
|
||||||
ua_add_nodes(client);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ua_read_time(UA_Client* client)
|
void ua_read_time(UA_Client* client)
|
||||||
{
|
{
|
||||||
/* Read the value attribute of the node. UA_Client_readValueAttribute is a
|
UA_Variant value;
|
||||||
* wrapper for the raw read service available as UA_Client_Service_read. */
|
|
||||||
UA_Variant value; /* Variants can hold scalar values and arrays of any type */
|
|
||||||
UA_Variant_init(&value);
|
UA_Variant_init(&value);
|
||||||
|
|
||||||
/* NodeId of the variable holding the current time */
|
|
||||||
const UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
|
const UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
|
||||||
UA_StatusCode retval = UA_Client_readValueAttribute(client, nodeId, &value);
|
UA_StatusCode ret = UA_Client_readValueAttribute(client, nodeId, &value);
|
||||||
|
|
||||||
if(retval == UA_STATUSCODE_GOOD && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME]))
|
if(ret == UA_STATUSCODE_GOOD && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME]))
|
||||||
{
|
{
|
||||||
UA_DateTime raw_date = *(UA_DateTime*) value.data;
|
UA_DateTime raw_date = *(UA_DateTime*) value.data;
|
||||||
UA_DateTimeStruct dts = UA_DateTime_toStruct(raw_date);
|
UA_DateTimeStruct dts = UA_DateTime_toStruct(raw_date);
|
||||||
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "date is: %u-%u-%u %u:%u:%u.%03u\n",
|
ua_pr_info("date is: %d-%d-%d %d:%d:%d.%03d\n",
|
||||||
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
|
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
UA_Variant_clear(&value);
|
UA_Variant_clear(&value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,75 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ua_test.c
|
||||||
|
* @brief Test for OpcUa function
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.11.11
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "open62541.h"
|
||||||
|
#include "ua_api.h"
|
||||||
|
|
||||||
|
//for target NODEID
|
||||||
|
#define UA_TEST_BROWSER_NODEID UA_NODEID_STRING(3, "ServerInterfaces")
|
||||||
|
#define UA_TEST_BROWSER_NODEID1 UA_NODEID_NUMERIC(4, 1)
|
||||||
|
#define UA_TEST_WRITE_NODEID UA_NODEID_NUMERIC(4, 5)
|
||||||
|
|
||||||
|
|
||||||
|
static UA_StatusCode ua_test_read_array(UA_Client *client)
|
||||||
|
{
|
||||||
|
const int item_size = 4;
|
||||||
|
UA_ReadValueId test_item[item_size];
|
||||||
|
|
||||||
|
for (int i = 0; i < item_size; i++)
|
||||||
|
{
|
||||||
|
UA_ReadValueId_init(&test_item[i]);
|
||||||
|
test_item[i].attributeId = UA_ATTRIBUTEID_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_item[0].nodeId = UA_NODEID_NUMERIC(4, 2);
|
||||||
|
test_item[1].nodeId = UA_NODEID_NUMERIC(4, 3);
|
||||||
|
test_item[2].nodeId = UA_NODEID_NUMERIC(4, 4);
|
||||||
|
test_item[3].nodeId = UA_NODEID_NUMERIC(4, 5);
|
||||||
|
|
||||||
|
return ua_read_array_value(client, item_size, test_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ua_test_browser_objects(UA_Client *client)
|
||||||
|
{
|
||||||
|
UA_NodeId test_id;
|
||||||
|
ua_browser_id(client, UA_TEST_BROWSER_NODEID);
|
||||||
|
ua_browser_id(client, UA_TEST_BROWSER_NODEID1);
|
||||||
|
test_id = UA_TEST_BROWSER_NODEID1;
|
||||||
|
ua_pr_info("Show values in %s:\n", ua_get_nodeid_str(&test_id));
|
||||||
|
ua_test_read_array(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ua_test_write_attr(UA_Client *client)
|
||||||
|
{
|
||||||
|
UA_Int32 value;
|
||||||
|
char val_str[UA_NODE_LEN];
|
||||||
|
UA_NodeId id = UA_TEST_WRITE_NODEID;
|
||||||
|
|
||||||
|
ua_pr_info("--- Test write %s ---\n", ua_get_nodeid_str(&id));
|
||||||
|
ua_read_nodeid_value(client, id, &value);
|
||||||
|
ua_write_nodeid_value(client, id, itoa(value + 1, val_str, 10));
|
||||||
|
ua_read_nodeid_value(client, id, &value);
|
||||||
|
ua_pr_info("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int ua_test_interact_server(UA_Client *client)
|
||||||
|
{
|
||||||
|
ua_read_time(client);
|
||||||
|
ua_test_browser_objects(client);
|
||||||
|
ua_test_write_attr(client);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int16 ua_test(void)
|
int16 ua_test(void)
|
||||||
{
|
{
|
||||||
UA_Client *client = UA_Client_new();
|
UA_Client *client = UA_Client_new();
|
||||||
|
@ -20,7 +89,6 @@ int16 ua_test(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
ua_read_time(client);
|
ua_read_time(client);
|
||||||
ua_run_test(client);
|
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
UA_Client_disconnect(client);
|
UA_Client_disconnect(client);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
SRC_FILES := plc_dev.c plc_bus.c plc_drv.c
|
SRC_FILES := plc_dev.c plc_ch.c plc_drv.c channel.c
|
||||||
|
|
||||||
include $(KERNEL_ROOT)/compiler.mk
|
include $(KERNEL_ROOT)/compiler.mk
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,433 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file plc_ch.c
|
||||||
|
* @brief Support channel driver framework provide ch API version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021-04-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
#include "channel.h"
|
||||||
|
#include "transform.h"
|
||||||
|
|
||||||
|
DoublelistType ch_linklist;
|
||||||
|
|
||||||
|
/*Create the ch linklist*/
|
||||||
|
static void ChannelLinkInit(struct Channel *ch)
|
||||||
|
{
|
||||||
|
static uint8 ch_link_flag = RET_FALSE;
|
||||||
|
|
||||||
|
if(!ch_link_flag) {
|
||||||
|
AppInitDoubleList(&ch_linklist);
|
||||||
|
ch_link_flag = RET_TRUE;
|
||||||
|
ch->ch_link_flag = RET_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Create the driver of the ch linklist*/
|
||||||
|
if(!ch->ch_drvlink_flag) {
|
||||||
|
AppInitDoubleList(&ch->ch_drvlink);
|
||||||
|
ch->ch_drvlink_flag = RET_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Create the hardware device of the ch linklist*/
|
||||||
|
if(!ch->ch_devlink_flag) {
|
||||||
|
AppInitDoubleList(&ch->ch_devlink);
|
||||||
|
ch->ch_devlink_flag = RET_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ChannelMatchDrvDev(struct ChDrv *driver, struct ChDev *device)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(driver);
|
||||||
|
CHECK_CH_PARAM(device);
|
||||||
|
|
||||||
|
if(!strncmp(driver->owner_ch->ch_name, device->owner_ch->ch_name, NAME_NUM_MAX)) {
|
||||||
|
KPrintf("ChannelMatchDrvDev match successfully, ch name %s\n", driver->owner_ch->ch_name);
|
||||||
|
|
||||||
|
driver->private_data = device->private_data;//driver get the device param
|
||||||
|
device->owner_ch->owner_driver = driver;
|
||||||
|
driver->owner_ch->owner_haldev = device;
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to obtain ch for a certain dev if necessary, then configure and init its drv
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param dev - dev pointer
|
||||||
|
* @param drv_name - drv name
|
||||||
|
* @param config - ChConfigInfo pointer
|
||||||
|
* @return successful:EOK,failed:ERROR
|
||||||
|
*/
|
||||||
|
int DeviceObtainChannel(struct Channel *ch, struct ChDev *dev, const char *drv_name, struct ChConfigInfo *cfg)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
|
int32 ret = EOK;
|
||||||
|
|
||||||
|
ret = PrivMutexObtain(&ch->ch_lock);
|
||||||
|
if(EOK != ret) {
|
||||||
|
KPrintf("DevObtainChannel ch_lock error %d!\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ch->owner_haldev != dev) {
|
||||||
|
struct ChDrv *drv = ChannelFindDriver(ch, drv_name);
|
||||||
|
|
||||||
|
cfg->configure_cmd = OPE_CFG;
|
||||||
|
drv->configure(drv, cfg);
|
||||||
|
|
||||||
|
cfg->configure_cmd = OPE_INT;
|
||||||
|
drv->configure(drv, cfg);
|
||||||
|
|
||||||
|
ch->owner_haldev = dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to register ch pointer with linklist
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int ChannelRegister(struct Channel *ch)
|
||||||
|
{
|
||||||
|
int ret = EOK;
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
|
||||||
|
ch->match = ChannelMatchDrvDev;
|
||||||
|
|
||||||
|
ChannelLinkInit(ch);
|
||||||
|
|
||||||
|
PrivMutexCreate(&ch->ch_lock, NULL);
|
||||||
|
|
||||||
|
AppDoubleListInsertNodeAfter(&ch_linklist, &(ch->ch_link));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to release ch pointer in linklist
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int ChannelRelease(struct Channel *ch)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
|
||||||
|
PrivMutexAbandon(&ch->ch_lock);
|
||||||
|
|
||||||
|
ch->ch_cnt = 0;
|
||||||
|
ch->driver_cnt = 0;
|
||||||
|
ch->haldev_cnt = 0;
|
||||||
|
|
||||||
|
ch->ch_link_flag = RET_FALSE;
|
||||||
|
ch->ch_drvlink_flag = RET_FALSE;
|
||||||
|
ch->ch_devlink_flag = RET_FALSE;
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to unregister ch pointer and delete its linklist node
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int ChannelUnregister(struct Channel *ch)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
|
||||||
|
ch->ch_cnt--;
|
||||||
|
|
||||||
|
AppDoubleListRmNode(&(ch->ch_link));
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to register driver pointer to ch pointer
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param driver - driver pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int DriverRegisterToChannel(struct Channel *ch, struct ChDrv *driver)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
CHECK_CH_PARAM(driver);
|
||||||
|
|
||||||
|
driver->owner_ch = ch;
|
||||||
|
ch->driver_cnt++;
|
||||||
|
|
||||||
|
AppDoubleListInsertNodeAfter(&ch->ch_drvlink, &(driver->driver_link));
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to register dev pointer to ch pointer
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param device - device pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int DeviceRegisterToChannel(struct Channel *ch, struct ChDev *device)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
CHECK_CH_PARAM(device);
|
||||||
|
|
||||||
|
device->owner_ch = ch;
|
||||||
|
ch->haldev_cnt++;
|
||||||
|
|
||||||
|
AppDoubleListInsertNodeAfter(&ch->ch_devlink, &(device->dev_link));
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to delete driver pointer from ch pointer
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param driver - driver pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int DriverDeleteFromChannel(struct Channel *ch, struct ChDrv *driver)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
CHECK_CH_PARAM(driver);
|
||||||
|
|
||||||
|
ch->driver_cnt--;
|
||||||
|
|
||||||
|
AppDoubleListRmNode(&(driver->driver_link));
|
||||||
|
|
||||||
|
free(driver);
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to delete dev pointer from ch pointer
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param device - device pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int DeviceDeleteFromChannel(struct Channel *ch, struct ChDev *device)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
CHECK_CH_PARAM(device);
|
||||||
|
|
||||||
|
ch->haldev_cnt--;
|
||||||
|
|
||||||
|
AppDoubleListRmNode(&(device->dev_link));
|
||||||
|
|
||||||
|
free(device);
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to find ch pointer by ch name
|
||||||
|
* @param ch_name - ch name
|
||||||
|
* @return successful:ch pointer,failed:NONE
|
||||||
|
*/
|
||||||
|
ChannelType ChannelFind(const char *ch_name)
|
||||||
|
{
|
||||||
|
struct Channel *ch = NONE;
|
||||||
|
|
||||||
|
DoublelistType *node = NONE;
|
||||||
|
DoublelistType *head = &ch_linklist;
|
||||||
|
|
||||||
|
for (node = head->node_next; node != head; node = node->node_next)
|
||||||
|
{
|
||||||
|
ch = DOUBLE_LIST_ENTRY(node, struct Channel, ch_link);
|
||||||
|
if(!strcmp(ch->ch_name, ch_name)) {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KPrintf("ChannelFind cannot find the %s ch.return NULL\n", ch_name);
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to find driver pointer of certain ch by driver name
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param driver_name - driver name
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
ChDrvType ChannelFindDriver(struct Channel *ch, const char *driver_name)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
struct ChDrv *driver = NONE;
|
||||||
|
|
||||||
|
DoublelistType *node = NONE;
|
||||||
|
DoublelistType *head = &ch->ch_drvlink;
|
||||||
|
|
||||||
|
for (node = head->node_next; node != head; node = node->node_next)
|
||||||
|
{
|
||||||
|
driver = DOUBLE_LIST_ENTRY(node, struct ChDrv, driver_link);
|
||||||
|
if(!strcmp(driver->drv_name, driver_name)) {
|
||||||
|
return driver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KPrintf("ChannelFindDriver cannot find the %s driver.return NULL\n", driver_name);
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to find device pointer of certain ch by device name
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param device_name - device name
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
ChDevType ChannelFindDevice(struct Channel *ch, const char *device_name)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
struct ChDev *device = NONE;
|
||||||
|
|
||||||
|
DoublelistType *node = NONE;
|
||||||
|
DoublelistType *head = &ch->ch_devlink;
|
||||||
|
|
||||||
|
for (node = head->node_next; node != head; node = node->node_next)
|
||||||
|
{
|
||||||
|
device = DOUBLE_LIST_ENTRY(node, struct ChDev, dev_link);
|
||||||
|
|
||||||
|
if(!strcmp(device->dev_name, device_name)) {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KPrintf("ChannelFindDevice cannot find the %s device.return NULL\n", device_name);
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to set dev receive function callback
|
||||||
|
* @param dev - dev pointer
|
||||||
|
* @param dev_recv_callback - callback function
|
||||||
|
* @return successful:EOK,failed:ERROR
|
||||||
|
*/
|
||||||
|
uint32 ChannelDevRecvCallback(struct ChDev *dev, int (*dev_recv_callback) (void *dev, x_size_t length))
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev );
|
||||||
|
|
||||||
|
dev->dev_recv_callback = dev_recv_callback;
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to open dev
|
||||||
|
* @param dev - dev pointer
|
||||||
|
* @return successful:EOK,failed:ERROR
|
||||||
|
*/
|
||||||
|
uint32 ChannelDevOpen(struct ChDev *dev)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
|
int ret = EOK;
|
||||||
|
|
||||||
|
if (dev->dev_done->open) {
|
||||||
|
ret = dev->dev_done->open(dev);
|
||||||
|
if(ret) {
|
||||||
|
KPrintf("ChannelDevOpen error ret %u\n", ret);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to close dev
|
||||||
|
* @param dev - dev pointer
|
||||||
|
* @return successful:EOK,failed:ERROR
|
||||||
|
*/
|
||||||
|
uint32 ChannelDevClose(struct ChDev *dev)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
|
int ret = EOK;
|
||||||
|
|
||||||
|
if (dev->dev_done->close) {
|
||||||
|
ret = dev->dev_done->close(dev);
|
||||||
|
if(ret) {
|
||||||
|
KPrintf("ChannelDevClose error ret %u\n", ret);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to write data to dev
|
||||||
|
* @param dev - dev pointer
|
||||||
|
* @param write_param - ChWriteParam
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
uint32 ChannelDevWriteData(struct ChDev *dev, struct ChWriteParam *write_param)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
|
if (dev->dev_done->write) {
|
||||||
|
return dev->dev_done->write(dev, write_param);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to read data from dev
|
||||||
|
* @param dev - dev pointer
|
||||||
|
* @param read_param - ChReadParam
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
uint32 ChannelDevReadData(struct ChDev *dev, struct ChReadParam *read_param)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
|
if (dev->dev_done->read) {
|
||||||
|
return dev->dev_done->read(dev, read_param);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to configure drv, include OPE_CFG and OPE_INT
|
||||||
|
* @param drv - drv pointer
|
||||||
|
* @param config - ChConfigInfo
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
uint32 ChannelDrvConfigure(struct ChDrv *drv, struct ChConfigInfo *config)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(drv);
|
||||||
|
CHECK_CH_PARAM(config);
|
||||||
|
|
||||||
|
int ret = EOK;
|
||||||
|
|
||||||
|
if (drv->configure) {
|
||||||
|
ret = drv->configure(drv, config);
|
||||||
|
if(ret) {
|
||||||
|
KPrintf("ChannelDrvCfg error, ret %u\n", ret);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,247 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file channel.h
|
||||||
|
* @brief define ch driver framework function and common API
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2022-03-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CHANNEL_H_
|
||||||
|
#define __CHANNEL_H_
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
#define x_OffPos uint32
|
||||||
|
#define x_size_t size_t
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define OPE_INT 0x0000
|
||||||
|
#define OPE_CFG 0x0001
|
||||||
|
|
||||||
|
#define OPER_WDT_SET_TIMEOUT 0x0002
|
||||||
|
#define OPER_WDT_KEEPALIVE 0x0003
|
||||||
|
|
||||||
|
#define CHECK_CH_PARAM(param) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if(param == NONE) { \
|
||||||
|
KPrintf("PARAM CHECK FAILED ...%s %d %s is NULL.\n",__FUNCTION__,__LINE__,#param); \
|
||||||
|
while(RET_TRUE); \
|
||||||
|
} \
|
||||||
|
}while (0)
|
||||||
|
|
||||||
|
typedef struct Channel *ChannelType;
|
||||||
|
typedef struct ChDev *ChDevType;
|
||||||
|
typedef struct ChDrv *ChDrvType;
|
||||||
|
|
||||||
|
/* need to add new ch type in ../tool/shell/letter-shell/cmd.c, ensure ShowBus cmd supported*/
|
||||||
|
enum ChType_e
|
||||||
|
{
|
||||||
|
CH_PLC_TYPE,
|
||||||
|
CH_END_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ChState_e
|
||||||
|
{
|
||||||
|
CHANNEL_INIT = 0,
|
||||||
|
CHANNEL_INSTALL,
|
||||||
|
CHANNEL_UNINSTALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ChDevType_e
|
||||||
|
{
|
||||||
|
CHDEV_PLC_TYPE,
|
||||||
|
CHDEV_END_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ChDevState_e
|
||||||
|
{
|
||||||
|
CHDEV_INIT = 0,
|
||||||
|
CHDEV_INSTALL,
|
||||||
|
CHDEV_UNINSTALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ChDrvType_e
|
||||||
|
{
|
||||||
|
CHDRV_PLC_TYPE,
|
||||||
|
CHDRV_END_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ChDrvState_e
|
||||||
|
{
|
||||||
|
CHDRV_INIT = 0,
|
||||||
|
CHDRV_INSTALL,
|
||||||
|
CHDRV_UNINSTALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChConfigInfo
|
||||||
|
{
|
||||||
|
int configure_cmd;
|
||||||
|
void *private_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChReadParam
|
||||||
|
{
|
||||||
|
x_OffPos pos;
|
||||||
|
void* buffer;
|
||||||
|
x_size_t size;
|
||||||
|
x_size_t read_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChWriteParam
|
||||||
|
{
|
||||||
|
x_OffPos pos;
|
||||||
|
const void* buffer;
|
||||||
|
x_size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
//struct ChHalDevBlockParam
|
||||||
|
//{
|
||||||
|
// uint32 cmd;
|
||||||
|
////tst by wly
|
||||||
|
//// struct DeviceBlockArrange dev_block;
|
||||||
|
//// struct DeviceBlockAddr *dev_addr;
|
||||||
|
//};
|
||||||
|
|
||||||
|
struct ChHalDevDone
|
||||||
|
{
|
||||||
|
uint32 (*open) (void *dev);
|
||||||
|
uint32 (*close) (void *dev);
|
||||||
|
uint32 (*write) (void *dev, struct ChWriteParam *write_param);
|
||||||
|
uint32 (*read) (void *dev, struct ChReadParam *read_param);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChDev
|
||||||
|
{
|
||||||
|
int8 dev_name[NAME_NUM_MAX];
|
||||||
|
enum ChDevType_e dev_type;
|
||||||
|
enum ChDevState_e dev_state;
|
||||||
|
|
||||||
|
const struct ChHalDevDone *dev_done;
|
||||||
|
|
||||||
|
int (*dev_recv_callback) (void *dev, x_size_t length);
|
||||||
|
// int (*dev_block_control) (struct ChDev *dev, struct ChHalDevBlockParam *block_param);
|
||||||
|
|
||||||
|
struct Channel *owner_ch;
|
||||||
|
void *private_data;
|
||||||
|
|
||||||
|
int32 dev_sem;
|
||||||
|
|
||||||
|
DoublelistType dev_link;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChDrv
|
||||||
|
{
|
||||||
|
int8 drv_name[NAME_NUM_MAX];
|
||||||
|
enum ChDrvType_e driver_type;
|
||||||
|
enum ChDrvState_e driver_state;
|
||||||
|
|
||||||
|
uint32 (*configure)(void *drv, struct ChConfigInfo *config);
|
||||||
|
|
||||||
|
struct Channel *owner_ch;
|
||||||
|
void *private_data;
|
||||||
|
|
||||||
|
DoublelistType driver_link;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Channel
|
||||||
|
{
|
||||||
|
int8 ch_name[NAME_NUM_MAX];
|
||||||
|
enum ChType_e ch_type;
|
||||||
|
enum ChState_e ch_state;
|
||||||
|
|
||||||
|
int32 (*match)(struct ChDrv *driver, struct ChDev *device);
|
||||||
|
|
||||||
|
int ch_lock;
|
||||||
|
|
||||||
|
struct ChDev *owner_haldev;
|
||||||
|
struct ChDrv *owner_driver;
|
||||||
|
|
||||||
|
void *private_data;
|
||||||
|
|
||||||
|
/*manage the drv of the channel*/
|
||||||
|
uint8 driver_cnt;
|
||||||
|
uint8 ch_drvlink_flag;
|
||||||
|
DoublelistType ch_drvlink;
|
||||||
|
|
||||||
|
/*manage the dev of the channel*/
|
||||||
|
uint8 haldev_cnt;
|
||||||
|
uint8 ch_devlink_flag;
|
||||||
|
DoublelistType ch_devlink;
|
||||||
|
|
||||||
|
uint8 ch_cnt;
|
||||||
|
uint8 ch_link_flag;
|
||||||
|
DoublelistType ch_link;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*Register the BUS,manage with the double linklist*/
|
||||||
|
int ChannelRegister(struct Channel *ch);
|
||||||
|
|
||||||
|
/*Release the BUS framework*/
|
||||||
|
int ChannelRelease(struct Channel *ch);
|
||||||
|
|
||||||
|
/*Unregister a certain kind of BUS*/
|
||||||
|
int ChannelUnregister(struct Channel *ch);
|
||||||
|
|
||||||
|
/*Register the driver to the channel*/
|
||||||
|
int DriverRegisterToChannel(struct Channel *ch, struct ChDrv *driver);
|
||||||
|
|
||||||
|
/*Register the device to the channel*/
|
||||||
|
int DeviceRegisterToChannel(struct Channel *ch, struct ChDev *device);
|
||||||
|
|
||||||
|
/*Delete the driver from the channel*/
|
||||||
|
int DriverDeleteFromChannel(struct Channel *ch, struct ChDrv *driver);
|
||||||
|
|
||||||
|
/*Delete the device from the channel*/
|
||||||
|
int DeviceDeleteFromChannel(struct Channel *ch, struct ChDev *device);
|
||||||
|
|
||||||
|
/*Find the ch with ch name*/
|
||||||
|
ChannelType ChannelFind(const char *ch_name);
|
||||||
|
|
||||||
|
/*Find the driver of cetain channel*/
|
||||||
|
ChDrvType ChannelFindDriver(struct Channel *ch, const char *driver_name);
|
||||||
|
|
||||||
|
/*Find the device of certain channel*/
|
||||||
|
ChDevType ChannelFindDevice(struct Channel *ch, const char *device_name);
|
||||||
|
|
||||||
|
/*Dev receive data callback function*/
|
||||||
|
uint32 ChannelDevRecvCallback(struct ChDev *dev, int (*dev_recv_callback) (void *dev, x_size_t length));
|
||||||
|
|
||||||
|
/*Open the device of the channel*/
|
||||||
|
uint32 ChannelDevOpen(struct ChDev *dev);
|
||||||
|
|
||||||
|
/*Close the device of the channel*/
|
||||||
|
uint32 ChannelDevClose(struct ChDev *dev);
|
||||||
|
|
||||||
|
/*Write data to the device*/
|
||||||
|
uint32 ChannelDevWriteData(struct ChDev *dev, struct ChWriteParam *write_param);
|
||||||
|
|
||||||
|
/*Read data from the device*/
|
||||||
|
uint32 ChannelDevReadData(struct ChDev *dev, struct ChReadParam *read_param);
|
||||||
|
|
||||||
|
/*Configure the driver of the channel*/
|
||||||
|
uint32 ChannelDrvConfigure(struct ChDrv *drv, struct ChConfigInfo *config);
|
||||||
|
|
||||||
|
/*Obtain the ch using a certain dev*/
|
||||||
|
int DeviceObtainChannel(struct Channel *ch, struct ChDev *dev, const char *drv_name, struct ChConfigInfo *config);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,119 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 AIIT XUOS Lab
|
|
||||||
* XiUOS is licensed under Mulan PSL v2.
|
|
||||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
||||||
* You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
||||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file bus_plc.c
|
|
||||||
* @brief register plc bus function using bus driver framework
|
|
||||||
* @version 1.0
|
|
||||||
* @author AIIT XUOS Lab
|
|
||||||
* @date 2022-01-24
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "plc_bus.h"
|
|
||||||
#include "plc_dev.h"
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
int PlcBusInit(struct PlcBus *plc_bus, const char *bus_name)
|
|
||||||
{
|
|
||||||
NULL_PARAM_CHECK(plc_bus);
|
|
||||||
NULL_PARAM_CHECK(bus_name);
|
|
||||||
|
|
||||||
x_err_t ret = EOK;
|
|
||||||
|
|
||||||
if (BUS_INSTALL != plc_bus->bus.bus_state) {
|
|
||||||
strncpy(plc_bus->bus.bus_name, bus_name, NAME_NUM_MAX);
|
|
||||||
plc_bus->bus.bus_type = TYPE_PLC_BUS;
|
|
||||||
plc_bus->bus.bus_state = BUS_INSTALL;
|
|
||||||
plc_bus->bus.private_data = plc_bus->private_data;
|
|
||||||
|
|
||||||
ret = BusRegister(&plc_bus->bus);
|
|
||||||
if (EOK != ret) {
|
|
||||||
KPrintf("PlcBusInit BusRegister error %u\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
KPrintf("PlcBusInit BusRegister bus has been register state%u\n", plc_bus->bus.bus_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PlcDriverInit(struct PlcDriver *plc_driver, const char *driver_name)
|
|
||||||
{
|
|
||||||
NULL_PARAM_CHECK(plc_driver);
|
|
||||||
NULL_PARAM_CHECK(driver_name);
|
|
||||||
|
|
||||||
x_err_t ret = EOK;
|
|
||||||
|
|
||||||
if (DRV_INSTALL != plc_driver->driver.driver_state) {
|
|
||||||
plc_driver->driver.driver_type = TYPE_PLC_DRV;
|
|
||||||
plc_driver->driver.driver_state = DRV_INSTALL;
|
|
||||||
|
|
||||||
strncpy(plc_driver->driver.drv_name, driver_name, NAME_NUM_MAX);
|
|
||||||
|
|
||||||
plc_driver->driver.configure = plc_driver->configure;
|
|
||||||
|
|
||||||
ret = PlcDriverRegister(&plc_driver->driver);
|
|
||||||
if (EOK != ret) {
|
|
||||||
KPrintf("PlcDriverInit DriverRegister error %u\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
KPrintf("PlcDriverInit DriverRegister driver has been register state%u\n", plc_driver->driver.driver_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PlcReleaseBus(struct PlcBus *plc_bus)
|
|
||||||
{
|
|
||||||
NULL_PARAM_CHECK(plc_bus);
|
|
||||||
|
|
||||||
return BusRelease(&plc_bus->bus);
|
|
||||||
}
|
|
||||||
|
|
||||||
int PlcDriverAttachToBus(const char *drv_name, const char *bus_name)
|
|
||||||
{
|
|
||||||
NULL_PARAM_CHECK(drv_name);
|
|
||||||
NULL_PARAM_CHECK(bus_name);
|
|
||||||
|
|
||||||
x_err_t ret = EOK;
|
|
||||||
|
|
||||||
struct Bus *bus;
|
|
||||||
struct Driver *driver;
|
|
||||||
|
|
||||||
bus = BusFind(bus_name);
|
|
||||||
if (NONE == bus) {
|
|
||||||
KPrintf("PlcDriverAttachToBus find plc bus error!name %s\n", bus_name);
|
|
||||||
return ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TYPE_PLC_BUS == bus->bus_type) {
|
|
||||||
driver = PlcDriverFind(drv_name, TYPE_PLC_DRV);
|
|
||||||
if (NONE == driver) {
|
|
||||||
KPrintf("PlcDriverAttachToBus find plc driver error!name %s\n", drv_name);
|
|
||||||
return ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (TYPE_PLC_DRV == driver->driver_type) {
|
|
||||||
ret = DriverRegisterToBus(bus, driver);
|
|
||||||
if (EOK != ret) {
|
|
||||||
KPrintf("PlcDriverAttachToBus DriverRegisterToBus error %u\n", ret);
|
|
||||||
return ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file plc_ch.c
|
||||||
|
* @brief register plc channel function using channel driver framework
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2022-01-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
#include "plc_ch.h"
|
||||||
|
#include "plc_dev.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
int PlcChannelInit(struct PlcChannel* plc_ch, const char* ch_name)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(plc_ch);
|
||||||
|
CHECK_CH_PARAM(ch_name);
|
||||||
|
int ret = EOK;
|
||||||
|
|
||||||
|
if(CHANNEL_INSTALL != plc_ch->ch.ch_state)
|
||||||
|
{
|
||||||
|
strncpy(plc_ch->ch.ch_name, ch_name, NAME_NUM_MAX);
|
||||||
|
plc_ch->ch.ch_type = CH_PLC_TYPE;
|
||||||
|
plc_ch->ch.ch_state = CHANNEL_INSTALL;
|
||||||
|
plc_ch->ch.private_data = plc_ch->private_data;
|
||||||
|
ret = ChannelRegister(&plc_ch->ch);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
KPrintf("PlcChannelInit ChannelRegister error %u\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("PlcChannelInit ChannelRegister channel has been register state %u\n",
|
||||||
|
plc_ch->ch.ch_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlcDriverInit(struct PlcDriver* plc_driver, const char* driver_name)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(plc_driver);
|
||||||
|
CHECK_CH_PARAM(driver_name);
|
||||||
|
int ret = EOK;
|
||||||
|
|
||||||
|
if(CHDRV_INSTALL != plc_driver->driver.driver_state)
|
||||||
|
{
|
||||||
|
plc_driver->driver.driver_type = CHDRV_PLC_TYPE;
|
||||||
|
plc_driver->driver.driver_state = CHDRV_INSTALL;
|
||||||
|
strncpy(plc_driver->driver.drv_name, driver_name, NAME_NUM_MAX);
|
||||||
|
plc_driver->driver.configure = plc_driver->configure;
|
||||||
|
ret = PlcDriverRegister(&plc_driver->driver);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
KPrintf("PlcDriverInit DriverRegister error %u\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("PlcDriverInit Driver %s has been register state %u\n",
|
||||||
|
driver_name, plc_driver->driver.driver_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlcReleaseChannel(struct PlcChannel* plc_ch)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(plc_ch);
|
||||||
|
return ChannelRelease(&plc_ch->ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlcDriverAttachToChannel(const char* drv_name, const char* ch_name)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(drv_name);
|
||||||
|
CHECK_CH_PARAM(ch_name);
|
||||||
|
int ret = EOK;
|
||||||
|
struct Channel* ch;
|
||||||
|
struct ChDrv* driver;
|
||||||
|
ch = ChannelFind(ch_name);
|
||||||
|
|
||||||
|
if(NONE == ch)
|
||||||
|
{
|
||||||
|
KPrintf("PlcDriverAttachToChannel find plc channel error!name %s\n", ch_name);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CH_PLC_TYPE == ch->ch_type)
|
||||||
|
{
|
||||||
|
driver = PlcDriverFind(drv_name, CHDRV_PLC_TYPE);
|
||||||
|
|
||||||
|
if(NONE == driver)
|
||||||
|
{
|
||||||
|
KPrintf("PlcDriverAttachToChannel find plc driver error!name %s\n", drv_name);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CHDRV_PLC_TYPE == driver->driver_type)
|
||||||
|
{
|
||||||
|
ret = DriverRegisterToChannel(ch, driver);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
KPrintf("PlcDriverAttachToChannel DriverRegisterToBus error %u\n", ret);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -11,17 +11,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file plc_bus.h
|
* @file plc_ch.h
|
||||||
* @brief define plc bus and drv function using bus driver framework
|
* @brief define plc bus and drv function using bus driver framework
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @author AIIT XUOS Lab
|
* @author AIIT XUOS Lab
|
||||||
* @date 2022-01-24
|
* @date 2022-01-24
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PLC_BUS_H_
|
#ifndef __PLC_CH_H_
|
||||||
#define __PLC_BUS_H_
|
#define __PLC_CH_H_
|
||||||
|
|
||||||
#include "bus.h"
|
#include "channel.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -29,33 +29,33 @@ extern "C" {
|
||||||
|
|
||||||
struct PlcDriver
|
struct PlcDriver
|
||||||
{
|
{
|
||||||
struct Driver driver;
|
struct ChDrv driver;
|
||||||
uint32 (*configure) (void *drv, struct BusConfigureInfo *configure_info);
|
uint32 (*configure) (void *drv, struct ChConfigInfo *cfg);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlcBus
|
struct PlcChannel
|
||||||
{
|
{
|
||||||
struct Bus bus;
|
struct Channel ch;
|
||||||
void *private_data;
|
void *private_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Register the plc bus*/
|
/*Register the plc bus*/
|
||||||
int PlcBusInit(struct PlcBus *plc_bus, const char *bus_name);
|
int PlcChannelInit(struct PlcChannel *plc_ch, const char *ch_name);
|
||||||
|
|
||||||
/*Register the plc driver*/
|
/*Register the plc driver*/
|
||||||
int PlcDriverInit(struct PlcDriver *plc_driver, const char *driver_name);
|
int PlcDriverInit(struct PlcDriver *plc_driver, const char *driver_name);
|
||||||
|
|
||||||
/*Release the plc device*/
|
/*Release the plc device*/
|
||||||
int PlcReleaseBus(struct PlcBus *plc_bus);
|
int PlcReleaseChannel(struct PlcChannel *plc_ch);
|
||||||
|
|
||||||
/*Register the plc driver to the plc bus*/
|
/*Register the plc driver to the plc bus*/
|
||||||
int PlcDriverAttachToBus(const char *drv_name, const char *bus_name);
|
int PlcDriverAttachToChannel(const char *drv_name, const char *ch_name);
|
||||||
|
|
||||||
/*Register the driver, manage with the double linklist*/
|
/*Register the driver, manage with the double linklist*/
|
||||||
int PlcDriverRegister(struct Driver *driver);
|
int PlcDriverRegister(struct ChDrv *driver);
|
||||||
|
|
||||||
/*Find the register driver*/
|
/*Find the register driver*/
|
||||||
DriverType PlcDriverFind(const char *drv_name, enum DriverType_e drv_type);
|
ChDrvType PlcDriverFind(const char *drv_name, enum ChDrvType_e drv_type);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
|
@ -19,22 +19,22 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ua_api.h"
|
#include "ua_api.h"
|
||||||
#include "plc_bus.h"
|
#include "plc_ch.h"
|
||||||
#include "plc_dev.h"
|
#include "plc_dev.h"
|
||||||
|
|
||||||
static DoubleLinklistType plcdev_list;
|
DoublelistType plcdev_list;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
/*Create the plc device linklist*/
|
/*Create the plc device linklist*/
|
||||||
static void PlcDeviceLinkInit()
|
static void PlcDeviceLinkInit()
|
||||||
{
|
{
|
||||||
InitDoubleLinkList(&plcdev_list);
|
AppInitDoubleList(&plcdev_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PlcDeviceOpen(void *dev)
|
static int PlcDeviceOpen(void *dev)
|
||||||
{
|
{
|
||||||
NULL_PARAM_CHECK(dev);
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
struct PlcDevice *plc_dev = (struct PlcDevice *)dev;
|
struct PlcDevice *plc_dev = (struct PlcDevice *)dev;
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ static int PlcDeviceOpen(void *dev)
|
||||||
|
|
||||||
static void PlcDeviceClose(void *dev)
|
static void PlcDeviceClose(void *dev)
|
||||||
{
|
{
|
||||||
NULL_PARAM_CHECK(dev);
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
struct PlcDevice *plc_dev = (struct PlcDevice *)dev;
|
struct PlcDevice *plc_dev = (struct PlcDevice *)dev;
|
||||||
|
|
||||||
|
@ -60,8 +60,7 @@ static void PlcDeviceClose(void *dev)
|
||||||
|
|
||||||
static int PlcDeviceWrite(void *dev, const void *buf, size_t len)
|
static int PlcDeviceWrite(void *dev, const void *buf, size_t len)
|
||||||
{
|
{
|
||||||
NULL_PARAM_CHECK(dev);
|
CHECK_CH_PARAM(dev);
|
||||||
NULL_PARAM_CHECK(buf);
|
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
struct PlcDevice *plc_dev = (struct PlcDevice *)dev;
|
struct PlcDevice *plc_dev = (struct PlcDevice *)dev;
|
||||||
|
@ -76,8 +75,8 @@ static int PlcDeviceWrite(void *dev, const void *buf, size_t len)
|
||||||
|
|
||||||
static int PlcDeviceRead(void *dev, void *buf, size_t len)
|
static int PlcDeviceRead(void *dev, void *buf, size_t len)
|
||||||
{
|
{
|
||||||
NULL_PARAM_CHECK(dev);
|
CHECK_CH_PARAM(dev);
|
||||||
NULL_PARAM_CHECK(buf);
|
CHECK_CH_PARAM(buf);
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
struct PlcDevice *plc_dev = (struct PlcDevice *)dev;
|
struct PlcDevice *plc_dev = (struct PlcDevice *)dev;
|
||||||
|
@ -99,18 +98,18 @@ static struct PlcOps plc_done =
|
||||||
};
|
};
|
||||||
|
|
||||||
/* find PLC device with device name */
|
/* find PLC device with device name */
|
||||||
struct HardwareDev *PlcDevFind(const char *dev_name)
|
struct ChDev *PlcDevFind(const char *dev_name)
|
||||||
{
|
{
|
||||||
NULL_PARAM_CHECK(dev_name);
|
CHECK_CH_PARAM(dev_name);
|
||||||
|
|
||||||
struct PlcDevice *device = NONE;
|
struct PlcDevice *device = NONE;
|
||||||
struct HardwareDev *haldev = NONE;
|
struct ChDev *haldev = NONE;
|
||||||
|
|
||||||
DoubleLinklistType *node = NONE;
|
DoublelistType *node = NONE;
|
||||||
DoubleLinklistType *head = &plcdev_list;
|
DoublelistType *head = &plcdev_list;
|
||||||
|
|
||||||
for (node = head->node_next; node != head; node = node->node_next) {
|
for (node = head->node_next; node != head; node = node->node_next) {
|
||||||
device = SYS_DOUBLE_LINKLIST_ENTRY(node, struct PlcDevice, link);
|
device = DOUBLE_LIST_ENTRY(node, struct PlcDevice, link);
|
||||||
if (!strcmp(device->name, dev_name)) {
|
if (!strcmp(device->name, dev_name)) {
|
||||||
haldev = &device->haldev;
|
haldev = &device->haldev;
|
||||||
return haldev;
|
return haldev;
|
||||||
|
@ -123,61 +122,63 @@ struct HardwareDev *PlcDevFind(const char *dev_name)
|
||||||
|
|
||||||
int PlcDevRegister(struct PlcDevice *plc_device, void *plc_param, const char *device_name)
|
int PlcDevRegister(struct PlcDevice *plc_device, void *plc_param, const char *device_name)
|
||||||
{
|
{
|
||||||
NULL_PARAM_CHECK(plc_device);
|
CHECK_CH_PARAM(plc_device);
|
||||||
NULL_PARAM_CHECK(device_name);
|
CHECK_CH_PARAM(device_name);
|
||||||
|
|
||||||
x_err_t ret = EOK;
|
int ret = EOK;
|
||||||
static x_bool dev_link_flag = RET_FALSE;
|
static uint8_t dev_link_flag = 0;
|
||||||
|
|
||||||
if (!dev_link_flag) {
|
if (!dev_link_flag) {
|
||||||
PlcDeviceLinkInit();
|
PlcDeviceLinkInit();
|
||||||
dev_link_flag = RET_TRUE;
|
dev_link_flag = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEV_INSTALL != plc_device->state) {
|
if (CHDEV_INSTALL != plc_device->state) {
|
||||||
strncpy(plc_device->haldev.dev_name, device_name, NAME_NUM_MAX);
|
strncpy(plc_device->haldev.dev_name, device_name, NAME_NUM_MAX);
|
||||||
plc_device->haldev.dev_type = TYPE_PLC_DEV;
|
plc_device->haldev.dev_type = CHDEV_PLC_TYPE;
|
||||||
plc_device->haldev.dev_state = DEV_INSTALL;
|
plc_device->haldev.dev_state = CHDEV_INSTALL;
|
||||||
|
|
||||||
strncpy(plc_device->name, device_name, strlen(device_name));
|
strncpy(plc_device->name, device_name, strlen(device_name));
|
||||||
plc_device->ops = &plc_done;
|
plc_device->ops = &plc_done;
|
||||||
|
|
||||||
DoubleLinkListInsertNodeAfter(&plcdev_list, &(plc_device->link));
|
AppDoubleListInsertNodeAfter(&plcdev_list, &(plc_device->link));
|
||||||
plc_device->state = DEV_INSTALL;
|
plc_device->state = CHDEV_INSTALL;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
KPrintf("PlcDevRegister device has been register state%u\n", plc_device->type);
|
KPrintf("PlcDevRegister device %s has been register state%u\n", device_name, plc_device->state);
|
||||||
|
ret = ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PlcDeviceAttachToBus(const char *dev_name, const char *bus_name)
|
int PlcDeviceAttachToChannel(const char *dev_name, const char *ch_name)
|
||||||
{
|
{
|
||||||
NULL_PARAM_CHECK(dev_name);
|
CHECK_CH_PARAM(dev_name);
|
||||||
NULL_PARAM_CHECK(bus_name);
|
CHECK_CH_PARAM(ch_name);
|
||||||
|
|
||||||
x_err_t ret = EOK;
|
int ret = EOK;
|
||||||
|
|
||||||
struct Bus *bus;
|
struct Channel *ch;
|
||||||
struct HardwareDev *device;
|
struct ChDev *device;
|
||||||
|
|
||||||
bus = BusFind(bus_name);
|
ch = ChannelFind(ch_name);
|
||||||
if (NONE == bus) {
|
if (NONE == ch) {
|
||||||
KPrintf("PlcDeviceAttachToBus find plc bus error!name %s\n", bus_name);
|
KPrintf("PlcDeviceAttachToChannel find plc ch error!name %s\n", ch_name);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TYPE_PLC_BUS == bus->bus_type) {
|
if (CH_PLC_TYPE == ch->ch_type) {
|
||||||
device = PlcDevFind(dev_name);
|
device = PlcDevFind(dev_name);
|
||||||
if (NONE == device) {
|
if (NONE == device) {
|
||||||
KPrintf("PlcDeviceAttachToBus find plc device error!name %s\n", dev_name);
|
KPrintf("PlcDeviceAttachToChannel find plc device %s error!\n", dev_name);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TYPE_PLC_DEV == device->dev_type) {
|
if (CHDEV_PLC_TYPE == device->dev_type) {
|
||||||
ret = DeviceRegisterToBus(bus, device);
|
ret = DeviceRegisterToChannel(ch, device);
|
||||||
if (EOK != ret) {
|
if (EOK != ret) {
|
||||||
KPrintf("PlcDeviceAttachToBus DeviceRegisterToBus error %u\n", ret);
|
KPrintf("PlcDeviceAttachToChannel DeviceRegisterToChannel error %u\n", ret);
|
||||||
return ERROR;
|
return ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
#ifndef __PLC_DEV_H_
|
#ifndef __PLC_DEV_H_
|
||||||
#define __PLC_DEV_H_
|
#define __PLC_DEV_H_
|
||||||
|
|
||||||
#include "bus.h"
|
#include "list.h"
|
||||||
#include "xs_klist.h"
|
#include "plc_ch.h"
|
||||||
|
|
||||||
#undef open
|
#undef open
|
||||||
#undef close
|
#undef close
|
||||||
|
@ -33,15 +33,16 @@
|
||||||
#define PLC_NAME_SIZE 32
|
#define PLC_NAME_SIZE 32
|
||||||
|
|
||||||
// PLC device information
|
// PLC device information
|
||||||
struct PlcInfo {
|
typedef struct PlcInfo {
|
||||||
uint32_t ability; // PLC ability
|
uint32_t ability; // PLC ability
|
||||||
uint32_t id; // PLC Device ID
|
uint32_t id; // PLC Device ID
|
||||||
uint32_t soft_version; // software version
|
uint32_t soft_version; // software version
|
||||||
uint32_t hard_version; // hardware version
|
uint32_t hard_version; // hardware version
|
||||||
uint32_t date; // manufact date
|
uint32_t date; // manufact date
|
||||||
const char *vendor; // vendor
|
const char *vendor; // vendor
|
||||||
const char *model; // product model
|
const char *model; // model
|
||||||
};
|
const char *product; // product
|
||||||
|
}PlcInfoType;
|
||||||
|
|
||||||
enum PlcSerialType {
|
enum PlcSerialType {
|
||||||
PLC_SERIAL_232,
|
PLC_SERIAL_232,
|
||||||
|
@ -64,13 +65,13 @@ union PlcCfg {
|
||||||
struct PlcDevice;
|
struct PlcDevice;
|
||||||
|
|
||||||
// operation API
|
// operation API
|
||||||
struct PlcOps {
|
typedef struct PlcOps {
|
||||||
int (*open)(void *dev); // open and connect PLC device
|
int (*open)(void *dev); // open and connect PLC device
|
||||||
void (*close)(void* dev); // close and disconnect PLC device
|
void (*close)(void* dev); // close and disconnect PLC device
|
||||||
int (*read)(void* dev, void *buf, size_t len); // read data from PLC
|
int (*read)(void* dev, void *buf, size_t len); // read data from PLC
|
||||||
int (*write)(void* dev, const void *buf, size_t len); // write data from PLC
|
int (*write)(void* dev, const void *buf, size_t len); // write data from PLC
|
||||||
int (*ioctl)(void* dev, int cmd, void *arg); // send control command to PLC
|
int (*ioctl)(void* dev, int cmd, void *arg); // send control command to PLC
|
||||||
};
|
}PlcOpsType;
|
||||||
|
|
||||||
enum PlcCtlType {
|
enum PlcCtlType {
|
||||||
PLC_CTRL_TYPE_HSC,
|
PLC_CTRL_TYPE_HSC,
|
||||||
|
@ -78,12 +79,10 @@ enum PlcCtlType {
|
||||||
PLC_CTRL_TYPE_PHASING
|
PLC_CTRL_TYPE_PHASING
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define PLC_ABILITY_HSC ((uint32_t)(1 << PLC_CTRL_TYPE_HSC))
|
#define PLC_ABILITY_HSC ((uint32_t)(1 << PLC_CTRL_TYPE_HSC))
|
||||||
#define PLC_ABILITY_PID ((uint32_t)(1 << PLC_CTRL_TYPE_PID))
|
#define PLC_ABILITY_PID ((uint32_t)(1 << PLC_CTRL_TYPE_PID))
|
||||||
#define PLC_ABILITY_PHASING ((uint32_t)(1 << PLC_CTRL_TYPE_PHASING))
|
#define PLC_ABILITY_PHASING ((uint32_t)(1 << PLC_CTRL_TYPE_PHASING))
|
||||||
|
|
||||||
|
|
||||||
enum PlcIndHybridNet
|
enum PlcIndHybridNet
|
||||||
{
|
{
|
||||||
// PLC Field Bus
|
// PLC Field Bus
|
||||||
|
@ -112,18 +111,19 @@ enum PlcTransType
|
||||||
};
|
};
|
||||||
|
|
||||||
//communication interface
|
//communication interface
|
||||||
struct PlcInterface
|
typedef struct PlcInterface
|
||||||
{
|
{
|
||||||
char ip_addr[IP_ADDR_SIZE];
|
char ip_addr[IP_ADDR_SIZE];
|
||||||
char attrib;
|
char attrib;
|
||||||
};
|
}PlcInterfaceType;
|
||||||
|
|
||||||
// identify PLC device
|
// identify PLC device
|
||||||
struct PlcDevice {
|
typedef struct PlcDevice {
|
||||||
struct HardwareDev haldev; /* hardware device driver for bus */
|
struct ChDev haldev; /* hardware device driver for channel */
|
||||||
|
enum ChDevState_e state;
|
||||||
|
|
||||||
char name[PLC_NAME_SIZE]; /* name of the device */
|
char name[PLC_NAME_SIZE]; /* name of the device */
|
||||||
enum PlcCtlType type; /* PLC Control Type */
|
enum PlcCtlType type; /* PLC Control Type */
|
||||||
enum DevState state;
|
|
||||||
enum PlcIndHybridNet net;
|
enum PlcIndHybridNet net;
|
||||||
enum PlcTransType trans;
|
enum PlcTransType trans;
|
||||||
|
|
||||||
|
@ -133,16 +133,20 @@ struct PlcDevice {
|
||||||
struct PlcInterface interface; /* protocols used for transferring data from program to plc */
|
struct PlcInterface interface; /* protocols used for transferring data from program to plc */
|
||||||
|
|
||||||
void *priv_data; /* private data for different PLC*/
|
void *priv_data; /* private data for different PLC*/
|
||||||
DoubleLinklistType link;/* link list node */
|
DoublelistType link;/* link list node */
|
||||||
};
|
}PlcDeviceType;
|
||||||
|
|
||||||
|
typedef struct PlcCtrlParam {
|
||||||
|
void *node_id; // for node ID
|
||||||
|
int value;
|
||||||
|
}PlcCtrlParamType;
|
||||||
|
|
||||||
#define plc_print KPrintf
|
#define plc_print KPrintf
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
int PlcDevRegister(struct PlcDevice *plc_device, void *plc_param, const char *device_name);
|
int PlcDevRegister(struct PlcDevice *plc_device, void *plc_param, const char *device_name);
|
||||||
int PlcDeviceAttachToBus(const char *dev_name, const char *bus_name);
|
int PlcDeviceAttachToChannel(const char *dev_name, const char *ch_name);
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
|
|
@ -19,30 +19,30 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "transform.h"
|
#include "transform.h"
|
||||||
#include "plc_bus.h"
|
#include "plc_ch.h"
|
||||||
#include "plc_dev.h"
|
#include "plc_dev.h"
|
||||||
|
|
||||||
static DoubleLinklistType plcdrv_linklist;
|
static DoublelistType plcdrv_linklist;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
/*Create the driver linklist*/
|
/*Create the driver linklist*/
|
||||||
static void PlcDrvLinkInit()
|
static void PlcDrvLinkInit()
|
||||||
{
|
{
|
||||||
InitDoubleLinkList(&plcdrv_linklist);
|
AppInitDoubleList(&plcdrv_linklist);
|
||||||
}
|
}
|
||||||
|
|
||||||
DriverType PlcDriverFind(const char *drv_name, enum DriverType_e drv_type)
|
ChDrvType PlcDriverFind(const char *drv_name, enum ChDrvType_e drv_type)
|
||||||
{
|
{
|
||||||
NULL_PARAM_CHECK(drv_name);
|
CHECK_CH_PARAM(drv_name);
|
||||||
|
|
||||||
struct Driver *driver = NONE;
|
struct ChDrv *driver = NONE;
|
||||||
|
|
||||||
DoubleLinklistType *node = NONE;
|
DoublelistType *node = NONE;
|
||||||
DoubleLinklistType *head = &plcdrv_linklist;
|
DoublelistType *head = &plcdrv_linklist;
|
||||||
|
|
||||||
for (node = head->node_next; node != head; node = node->node_next) {
|
for (node = head->node_next; node != head; node = node->node_next) {
|
||||||
driver = SYS_DOUBLE_LINKLIST_ENTRY(node, struct Driver, driver_link);
|
driver = DOUBLE_LIST_ENTRY(node, struct ChDrv, driver_link);
|
||||||
if ((!strcmp(driver->drv_name, drv_name)) && (drv_type == driver->driver_type)) {
|
if ((!strcmp(driver->drv_name, drv_name)) && (drv_type == driver->driver_type)) {
|
||||||
return driver;
|
return driver;
|
||||||
}
|
}
|
||||||
|
@ -52,19 +52,19 @@ DriverType PlcDriverFind(const char *drv_name, enum DriverType_e drv_type)
|
||||||
return NONE;
|
return NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PlcDriverRegister(struct Driver *driver)
|
int PlcDriverRegister(struct ChDrv *driver)
|
||||||
{
|
{
|
||||||
NULL_PARAM_CHECK(driver);
|
CHECK_CH_PARAM(driver);
|
||||||
|
|
||||||
x_err_t ret = EOK;
|
int ret = EOK;
|
||||||
static x_bool driver_link_flag = RET_FALSE;
|
static uint8_t driver_link_flag = 0;
|
||||||
|
|
||||||
if (!driver_link_flag) {
|
if (!driver_link_flag) {
|
||||||
PlcDrvLinkInit();
|
PlcDrvLinkInit();
|
||||||
driver_link_flag = RET_TRUE;
|
driver_link_flag = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
DoubleLinkListInsertNodeAfter(&plcdrv_linklist, &(driver->driver_link));
|
AppDoubleListInsertNodeAfter(&plcdrv_linklist, &(driver->driver_link));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022 AIIT XUOS Lab
|
* Copyright (c) 2020 RT-Thread Development Team
|
||||||
* XiUOS is licensed under Mulan PSL v2.
|
*
|
||||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
* You may obtain a copy of Mulan PSL v2 at:
|
*
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
* Change Logs:
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
* Date Author Notes
|
||||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
* 2012-04-25 weety first version
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue