diff --git a/examples/zephyr/CMakeLists.txt b/examples/zephyr/CMakeLists.txt new file mode 100644 index 00000000000..f18764812c7 --- /dev/null +++ b/examples/zephyr/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.20.0) + +project(server) + +# set(CMAKE_OBJCOPY /usr/bin/arm-linux-gnueabihf-objcopy) +set(Python3_EXECUTABLE "/usr/bin/python3" CACHE STRING "" FORCE) +set(EXTRA_ZEPHYR_MODULES ${CMAKE_CURRENT_SOURCE_DIR}/../..) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +target_sources(app PRIVATE main.c) +target_link_libraries(app PUBLIC open62541) diff --git a/examples/zephyr/README.md b/examples/zephyr/README.md new file mode 100644 index 00000000000..bad9d457ae1 --- /dev/null +++ b/examples/zephyr/README.md @@ -0,0 +1,24 @@ +# Zephyr server example +## HOWTO +``` +# Initialize the west workspace +cd examples/zephyr +west init -l server +west update +# Build the native sim executable +cd server +west build -p -b native_sim +# Setup host side ethernet interface (see +# https://github.com/zephyrproject-rtos/net-tools or +# https://docs.zephyrproject.org/latest/boards/native/native_sim/doc/index.html#peripherals) +sudo .//net-setup.sh & +# Execute the OPC UA server +./build/zephyr/zephyr.exe & +# Read the answer value via python-opcua CLI +uaread -u "opc.tcp://192.0.2.10:4840" -n "ns=1;s=the.answer" +``` +Expected output of uaread: +``` +WARNING: Requested secure channel timeout to be 3600000ms, got 600000ms instead +42 +``` diff --git a/examples/zephyr/main.c b/examples/zephyr/main.c new file mode 100644 index 00000000000..cdda413c7ac --- /dev/null +++ b/examples/zephyr/main.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(open62541_test, LOG_LEVEL_DBG); + +#include +#include + +int main(void) { + k_sleep(K_MSEC(1000)); + struct net_if *iface = net_if_get_default(); + struct in_addr addr; + struct in_addr mask; + int ret = zsock_inet_pton(AF_INET, "192.0.2.10", &addr); + if (ret < 0) { + LOG_ERR("Invalid IP address format"); + return 1; + } + ret = zsock_inet_pton(AF_INET, "255.255.255.0", &mask); + if (ret < 0) { + LOG_ERR("Invalid IP address format"); + return 1; + } + struct net_if_addr *in_addr = + net_if_ipv4_addr_add(iface, &addr, NET_ADDR_MANUAL, 0); + net_if_ipv4_set_netmask_by_addr(iface, &addr, &mask); + if (!in_addr) { + LOG_ERR("Failed to add IPv4 address"); + return 1; + } + k_sleep(K_MSEC(1000)); + + LOG_INF("Starting UA_Server"); + static UA_ServerConfig config; + memset(&config, 0, sizeof(UA_ServerConfig)); + UA_ServerConfig_setDefault(&config); + // Minimum is 8192 + config.tcpBufSize = 1 << 13; + config.tcpMaxMsgSize = 1 << 13; + config.maxSecureChannels = 1; + config.maxSessions = 1; + UA_Server *server = UA_Server_newWithConfig(&config); + if (server == NULL) { + LOG_ERR("UA_Server_new failed"); + return EXIT_FAILURE; + } + + // Add a variable node to the adresspace + UA_VariableAttributes attr; attr = UA_VariableAttributes_default; + UA_Int32 myInteger; myInteger = 42; + UA_Variant_setScalarCopy(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]); + attr.description = UA_LOCALIZEDTEXT_ALLOC("en-US", "the answer"); + attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en-US", "the answer"); + UA_NodeId myIntegerNodeId; myIntegerNodeId = UA_NODEID_STRING_ALLOC(1, "the.answer"); + UA_QualifiedName myIntegerName; myIntegerName = UA_QUALIFIEDNAME_ALLOC(1, "the answer"); + UA_NodeId parentNodeId; parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId; parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, + parentReferenceNodeId, myIntegerName, + UA_NODEID_NULL, attr, NULL, NULL); + + // /* Allocations on the heap need to be freed */ + UA_VariableAttributes_clear(&attr); + UA_NodeId_clear(&myIntegerNodeId); + UA_QualifiedName_clear(&myIntegerName); + + volatile UA_Boolean running = true; + UA_StatusCode retval = UA_Server_run(server, &running); + + UA_Server_delete(server); + return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/examples/zephyr/prj.conf b/examples/zephyr/prj.conf new file mode 100644 index 00000000000..51ef5571ccd --- /dev/null +++ b/examples/zephyr/prj.conf @@ -0,0 +1,59 @@ +# Networking +CONFIG_NETWORKING=y +CONFIG_NET_DRIVERS=y +CONFIG_NET_SOCKETS=y +CONFIG_NET_LOG=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=y +CONFIG_NET_TCP=y + +CONFIG_NET_PKT_RX_COUNT=8 +CONFIG_NET_PKT_TX_COUNT=8 +CONFIG_NET_MAX_CONTEXTS=16 +CONFIG_NET_MAX_CONN=16 +CONFIG_NET_CONTEXT_SYNC_RECV=y +CONFIG_NET_TX_STACK_SIZE=4096 +CONFIG_NET_RX_STACK_SIZE=4096 +CONFIG_NET_L2_ETHERNET=y +CONFIG_NET_SOCKETS_POLL_MAX=12 +CONFIG_NET_BUF_RX_COUNT=16 +CONFIG_NET_BUF_TX_COUNT=16 +CONFIG_NET_BUF_DATA_SIZE=128 +CONFIG_NET_TC_TX_COUNT=1 +CONFIG_NET_MAX_CONTEXTS=16 +CONFIG_NET_MAX_CONN=16 +CONFIG_NET_CONTEXT_SYNC_RECV=y +CONFIG_ENTROPY_GENERATOR=y + +# Memory +CONFIG_HEAP_MEM_POOL_SIZE=200000 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=100000 + +CONFIG_INIT_STACKS=y +CONFIG_MAIN_STACK_SIZE=8192 + +# Debugging +CONFIG_DEBUG=y +CONFIG_STACK_SENTINEL=y + +# Logging +CONFIG_LOG=y +CONFIG_PRINTK=y +CONFIG_COMMON_LIBC_MALLOC=y +CONFIG_NEWLIB_LIBC=y +CONFIG_POSIX_MAX_FDS=32 +CONFIG_EVENTFD=y +CONFIG_EVENTFD_MAX=8 +CONFIG_POSIX_API=y +CONFIG_SYS_HEAP_RUNTIME_STATS=y + +CONFIG_OPEN62541=y +CONFIG_OPEN62541_ENABLE_DISCOVERY_SEMAPHORE=n +CONFIG_OPEN62541_MULTITHREADING=0 +CONFIG_OPEN62541_NAMESPACE_ZERO="MINIMAL" +CONFIG_OPEN62541_ENABLE_PUBSUB=n +CONFIG_OPEN62541_ENABLE_PUBSUB_INFORMATIONMODEL=n +CONFIG_OPEN62541_ENABLE_SUBSCRIPTIONS_EVENTS=n +CONFIG_OPEN62541_ENABLE_SUBSCRIPTIONS=n +CONFIG_OPEN62541_ENABLE_HISTORIZING=n +CONFIG_OPEN62541_ENABLE_JSON_ENCODING=n diff --git a/examples/zephyr/west.yml b/examples/zephyr/west.yml new file mode 100644 index 00000000000..06ccd4b29ac --- /dev/null +++ b/examples/zephyr/west.yml @@ -0,0 +1,13 @@ +manifest: + version: 1.2 + remotes: + - name: ncs + url-base: https://github.com/nrfconnect + + projects: + - name: nrf + remote: ncs + repo-path: sdk-nrf + revision: v2.7.0 + import: true +