...
 
Commits (4)
......@@ -2,11 +2,11 @@
cmake_minimum_required(VERSION 3.13.1)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(s2opcPortageZephyr)
project(toolkit_test_server)
add_definitions (-DS2OPC_CLIENTSERVER_ONLY=1)
add_definitions (-DWITH_STATIC_SECURITY_DATA=1 -DPUBSUB_STATIC_CONFIG=1 -DWITH_NANO_EXTENDED=1)
add_definitions (-DMY_IP_MASK="255.255.255.0" -DMY_IP_ETH0="192.0.2.10" -DMY_IP_GW="192.0.2.1" -DMY_IP6_ETH0="2001:db8::2" -DMY_IP6_MASK="ffff:ffff:")
add_definitions (-DMY_IP_MASK="255.255.255.0" -DMY_IP_ETH0="192.0.2.10" -DMY_IP_GW="192.0.2.2" -DMY_IP6_ETH0="2001:db8::2" -DMY_IP6_MASK="ffff:ffff:")
# Add TEST include directory
......
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.13.1)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(pubsub_test_server)
add_definitions (-DWITH_STATIC_SECURITY_DATA=1 -DPUBSUB_STATIC_CONFIG=1 -DWITH_NANO_EXTENDED=1)
add_definitions (-DMY_IP_MASK="255.255.255.0" -DMY_IP_ETH0="192.0.2.10" -DMY_IP_GW="192.0.2.2" -DMY_IP6_ETH0="2001:db8::2" -DMY_IP6_MASK="ffff:ffff:")
add_definitions (-DPUBLISHER_ADDRESS="232.1.2.100:4840" -DSUBSCRIBER_ADDRESS="232.1.2.101:4840")
add_definitions (-DPUBLISH_PERIOD=1000 -DSUBSCRIBE_PERIOD=1000)
# add_definitions (-DDEBUG_PUBSUB_SCHEDULER_INFO=1)
# Add TEST include directory
SET(app_headers ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_include_directories(app PRIVATE ${app_headers})
# =====================
# MBEDTLS SPECIFIC DEFS
# =====================
# custom config file
SET(mbedtls_config ${CMAKE_CURRENT_SOURCE_DIR}/src/tls_config)
target_include_directories(app PRIVATE ${tls_config})
zephyr_include_directories(${mbedtls_config})
FILE(GLOB tls_files ${CMAKE_CURRENT_SOURCE_DIR}/src/tls_config/*.c)
target_sources(app PRIVATE ${tls_files})
# ============================
# END OF MBEDTLS SPECIFIC DEFS
# ============================
# Add PUBSUB APPS includes directories
FILE(GLOB app_headers_pubsub_src_apps_pubsub_server ${CMAKE_CURRENT_SOURCE_DIR}/src/pubsub_server)
target_include_directories(app PRIVATE ${app_headers_pubsub_src_apps_pubsub_server})
# Add PUBSUB APPS sources directories
FILE(GLOB app_sources_pubsub_src_apps_pubsub_server_helpers_c ${CMAKE_CURRENT_SOURCE_DIR}/src/pubsub_server/helpers.c)
target_sources(app PRIVATE ${app_sources_pubsub_src_apps_pubsub_server_helpers_c})
FILE(GLOB app_sources_pubsub_src_apps_pubsub_server_pubsub_c ${CMAKE_CURRENT_SOURCE_DIR}/src/pubsub_server/pubsub.c)
target_sources(app PRIVATE ${app_sources_pubsub_src_apps_pubsub_server_pubsub_c})
FILE(GLOB app_sources_pubsub_src_apps_pubsub_server_server_c ${CMAKE_CURRENT_SOURCE_DIR}/src/pubsub_server/server.c)
target_sources(app PRIVATE ${app_sources_pubsub_src_apps_pubsub_server_server_c})
# Add TEST source directory
FILE(GLOB app_sources ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c)
target_sources(app PRIVATE ${app_sources})
# Add other path.
set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/)
CONFIG_NET_L2_ETHERNET=y
CONFIG_NET_QEMU_ETHERNET=y
CONFIG_ETH_E1000=y
CONFIG_PCIE=y
#CONFIG_ETHERNET_LOG_LEVEL_DBG=y
# General config
CONFIG_NEWLIB_LIBC=y
CONFIG_MAIN_STACK_SIZE=8192
CONFIG_SOCKS=y
CONFIG_POSIX_MAX_FDS=16
CONFIG_INIT_STACKS=y
# Networking config
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
CONFIG_NET_TCP=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y
CONFIG_NET_SOCKETS_POLL_MAX=5
CONFIG_NET_L2_DUMMY=y
CONFIG_NET_L2_ETHERNET=y
CONFIG_NET_LOOPBACK=y
CONFIG_NET_ARP=y
CONFIG_NET_MGMT=y
CONFIG_DNS_RESOLVER=y
CONFIG_NET_DEFAULT_IF_ETHERNET=y
CONFIG_NET_MAX_CONN=16
CONFIG_NET_TX_STACK_SIZE=1500
CONFIG_NET_IF_MAX_IPV4_COUNT=2
CONFIG_NET_IF_MCAST_IPV4_ADDR_COUNT=16
CONFIG_NET_BUF_DATA_SIZE=512
# Network driver config
CONFIG_TEST_RANDOM_GENERATOR=y
# Network address config
CONFIG_NET_CONFIG_SETTINGS=y
CONFIG_NET_CONFIG_SETTINGS=y
CONFIG_NET_CONFIG_NEED_IPV4=y
CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.10"
CONFIG_NET_CONFIG_MY_IPV4_NETMASK="255.255.255.0"
CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2"
# MbedTLS
CONFIG_MBEDTLS=y
CONFIG_MBEDTLS_DTLS=y
CONFIG_MBEDTLS_GENPRIME_ENABLED=y
CONFIG_MBEDTLS_HEAP_SIZE=60000
CONFIG_MBEDTLS_HMAC_DRBG_ENABLED=y
CONFIG_MBEDTLS_ENTROPY_ENABLED=y
CONFIG_MBEDTLS_ENABLE_HEAP=y
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED=y
CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED=y
CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT=y
CONFIG_MBEDTLS_SSL_EXPORT_KEYS=y
CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=2048
CONFIG_MBEDTLS_TLS_VERSION_1_0=y
CONFIG_MBEDTLS_TLS_VERSION_1_1=y
CONFIG_MBEDTLS_USER_CONFIG_ENABLE=y
CONFIG_MBEDTLS_USER_CONFIG_FILE="config_custom_mbedtls.h"
# S2OPC
CONFIG_S2OPC=y
/*
* network_init.c
*
* Created on: 17 f�vr. 2020
* Author: nottin
*/
#include "network_init.h"
#include <errno.h>
#include <inttypes.h>
#include <kernel.h>
#include <limits.h>
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <kernel.h>
#include <net/net_ip.h>
#include <net/socket.h>
#include "net/ethernet.h"
#include "net/net_if.h"
#include "sopc_mutexes.h"
#ifndef MY_IP_LB
#define MY_IP_LB ((const char*) ("127.0.0.1"))
#endif
#ifndef MY_IP_ETH0
#define MY_IP_ETH0 ((const char*) ("192.168.1.102"))
#endif
#ifndef MY_IP_MASK
#define MY_IP_MASK ((const char*) ("255.255.255.0"))
#endif
#ifndef MY_IP_GW
#define MY_IP_GW ((const char*) ("192.168.1.111"))
#endif
typedef enum E_NETWORK_CONFIG_STATUS
{
NETWORK_CONFIG_STATUS_NOT_INITIALIZED,
NETWORK_CONFIG_STATUS_INITIALIZING,
NETWORK_CONFIG_STATUS_INITIALIZED,
NETWORK_CONFIG_STATUS_SIZE = INT32_MAX
} eNetworkConfigStatus;
/* Max socket based on max connections allowed by zephyr */
#ifdef CONFIG_NET_MAX_CONN
#define MAX_ZEPHYR_SOCKET (CONFIG_NET_MAX_CONN - 2)
#else
#define MAX_ZEPHYR_SOCKET 4
#endif
static volatile eNetworkConfigStatus priv_P_SOCKET_networkConfigStatus = NETWORK_CONFIG_STATUS_NOT_INITIALIZED;
static Mutex priv_lockL2; // tabMCast protection
// *** Weak p_sockets functions definitions ***
bool Network_Initialize(void)
{
uint32_t nwStatus = 0;
printk("\r\nNetwork initialize called\r\n");
do
{
nwStatus = __sync_val_compare_and_swap(&priv_P_SOCKET_networkConfigStatus, //
NETWORK_CONFIG_STATUS_NOT_INITIALIZED, // Not initialized
NETWORK_CONFIG_STATUS_INITIALIZING); // Initializing
if (0 == nwStatus)
{
assert(SOPC_STATUS_OK == Mutex_Initialization(&priv_lockL2));
struct net_if* ptrNetIf = NULL;
struct in_addr addressLoopBack;
struct in_addr addressLoopBackNetMask;
struct in_addr addressInterfaceEth;
struct in_addr addressInterfaceEthMask;
struct in_addr addressInterfaceEthGtw;
net_addr_pton(AF_INET, MY_IP_LB, (void*) &addressLoopBack);
net_addr_pton(AF_INET, MY_IP_MASK, (void*) &addressLoopBackNetMask);
net_addr_pton(AF_INET, MY_IP_ETH0, (void*) &addressInterfaceEth);
net_addr_pton(AF_INET, MY_IP_MASK, (void*) &addressInterfaceEthMask);
net_addr_pton(AF_INET, MY_IP_GW, (void*) &addressInterfaceEthGtw);
if (NULL == net_if_ipv4_addr_lookup(&addressLoopBack, &ptrNetIf))
{
#if defined(CONFIG_NET_L2_DUMMY)
ptrNetIf = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
#else
#error "CONFIG_NET_L2_DUMMY should be defined."
#endif
assert(NULL != ptrNetIf);
assert(NULL != net_if_ipv4_addr_add(ptrNetIf, &addressLoopBack, NET_ADDR_MANUAL, 0));
net_if_ipv4_set_netmask(ptrNetIf, &addressLoopBackNetMask);
}
if (NULL == net_if_ipv4_addr_lookup(&addressInterfaceEth, &ptrNetIf))
{
#if defined(CONFIG_NET_L2_ETHERNET)
ptrNetIf = net_if_get_first_by_type(&NET_L2_GET_NAME(ETHERNET));
#else
#error "CONFIG_NET_L2_ETHERNET should be defined"
#endif
assert(NULL != ptrNetIf);
assert(NULL != net_if_ipv4_addr_add(ptrNetIf, &addressInterfaceEth, NET_ADDR_MANUAL, 0));
net_if_ipv4_set_gw(ptrNetIf, &addressInterfaceEthGtw);
net_if_ipv4_set_netmask(ptrNetIf, &addressInterfaceEthMask);
}
priv_P_SOCKET_networkConfigStatus = NETWORK_CONFIG_STATUS_INITIALIZED;
nwStatus = NETWORK_CONFIG_STATUS_INITIALIZED;
}
else
{
// Initializing on going, yield and retry
if (NETWORK_CONFIG_STATUS_INITIALIZING == nwStatus)
{
k_yield();
}
}
} while (NETWORK_CONFIG_STATUS_INITIALIZING == nwStatus);
// Initialized or not initialized
if (NETWORK_CONFIG_STATUS_INITIALIZED == nwStatus)
{
return true;
}
else
{
return false;
}
}
#ifndef __NETWORK_INIT_H__
#define __NETWORK_INIT_H__
#include <stdbool.h>
bool Network_Initialize(void);
#endif /* __NETWORK_INIT_H__ */
\ No newline at end of file
/* Copyright (C) Systerel SAS 2019, all rights reserved. */
#include "pubsub_config_static.h"
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#ifndef PUBLISH_PERIOD
#define PUBLISH_PERIOD 1000
#endif
#ifndef SUBSCRIBE_PERIOD
#define SUBSCRIBE_PERIOD 1000
#endif
#ifndef PUBLISHER_ADDRESS
#define PUBLISHER_ADDRESS "232.1.2.100:4840"
#endif
#ifndef SUBSCRIBER_ADDRESS
#define SUBSCRIBER_ADDRESS "232.1.2.101:4840"
#endif
static SOPC_DataSetWriter* SOPC_PubSubConfig_SetPubMessageAt(SOPC_PubSubConnection* connection,
uint16_t index,
uint16_t messageId,
uint32_t version,
uint64_t interval)
{
SOPC_WriterGroup* group = SOPC_PubSubConnection_Get_WriterGroup_At(connection, index);
SOPC_WriterGroup_Set_Id(group, messageId);
SOPC_WriterGroup_Set_Version(group, version);
SOPC_WriterGroup_Set_PublishingInterval(group, interval);
// Create one DataSet Writer
SOPC_WriterGroup_Allocate_DataSetWriter_Array(group, 1);
SOPC_DataSetWriter* writer = SOPC_WriterGroup_Get_DataSetWriter_At(group, 0);
SOPC_DataSetWriter_Set_Id(writer, messageId);
return writer;
}
static SOPC_PublishedDataSet* SOPC_PubSubConfig_InitDataSet(SOPC_PubSubConfiguration* config,
uint16_t dataSetIndex,
SOPC_DataSetWriter* writer,
uint16_t nbVar)
{
SOPC_PublishedDataSet* dataset = SOPC_PubSubConfiguration_Get_PublishedDataSet_At(config, dataSetIndex);
SOPC_PublishedDataSet_Init(dataset, SOPC_PublishedDataItemsDataType, nbVar);
SOPC_DataSetWriter_Set_DataSet(writer, dataset);
return dataset;
}
static void SOPC_PubSubConfig_SetPubVariableAt(SOPC_PublishedDataSet* dataset,
uint16_t index,
char* strNodeId,
SOPC_BuiltinId builtinType)
{
SOPC_FieldMetaData* fieldmetadata = SOPC_PublishedDataSet_Get_FieldMetaData_At(dataset, index);
SOPC_FieldMetaData_Set_ValueRank(fieldmetadata, -1);
SOPC_FieldMetaData_Set_BuiltinType(fieldmetadata, builtinType);
SOPC_PublishedVariable* publishedVar = SOPC_FieldMetaData_Get_PublishedVariable(fieldmetadata);
assert(NULL != publishedVar);
SOPC_NodeId* nodeId = SOPC_NodeId_FromCString(strNodeId, (int32_t) strlen(strNodeId));
assert(NULL != nodeId);
SOPC_PublishedVariable_Set_NodeId(publishedVar, nodeId);
SOPC_PublishedVariable_Set_AttributeId(publishedVar,
13); // Value => AttributeId=13
}
static SOPC_DataSetReader* SOPC_PubSubConfig_SetSubMessageAt(SOPC_PubSubConnection* connection,
uint16_t index,
uint32_t publisherId,
uint16_t messageId,
uint32_t version,
uint64_t interval)
{
SOPC_ReaderGroup* readerGroup = SOPC_PubSubConnection_Get_ReaderGroup_At(connection, index);
assert(readerGroup != NULL);
bool allocSuccess = SOPC_ReaderGroup_Allocate_DataSetReader_Array(readerGroup, 1);
if (allocSuccess)
{
SOPC_DataSetReader* reader = SOPC_ReaderGroup_Get_DataSetReader_At(readerGroup, 0);
assert(reader != NULL);
SOPC_DataSetReader_Set_WriterGroupVersion(reader, version);
SOPC_DataSetReader_Set_WriterGroupId(reader, messageId);
SOPC_DataSetReader_Set_DataSetWriterId(reader,
messageId); // Same as WriterGroup
SOPC_DataSetReader_Set_ReceiveTimeout(reader, 2 * interval);
SOPC_DataSetReader_Set_PublisherId_UInteger(reader, publisherId);
return reader;
}
return NULL;
}
static bool SOPC_PubSubConfig_SetSubNbVariables(SOPC_DataSetReader* reader, uint16_t nbVar)
{
return SOPC_DataSetReader_Allocate_FieldMetaData_Array(reader, SOPC_TargetVariablesDataType, nbVar);
}
static void SOPC_PubSubConfig_SetSubVariableAt(SOPC_DataSetReader* reader,
uint16_t index,
char* strNodeId,
SOPC_BuiltinId builtinType)
{
SOPC_FieldMetaData* fieldmetadata = SOPC_DataSetReader_Get_FieldMetaData_At(reader, index);
assert(fieldmetadata != NULL);
/* fieldmetadata: type the field */
SOPC_FieldMetaData_Set_ValueRank(fieldmetadata, -1);
SOPC_FieldMetaData_Set_BuiltinType(fieldmetadata, builtinType);
/* FieldTarget: link to the source/target data */
SOPC_FieldTarget* fieldTarget = SOPC_FieldMetaData_Get_TargetVariable(fieldmetadata);
assert(fieldTarget != NULL);
SOPC_NodeId* nodeId = SOPC_NodeId_FromCString(strNodeId, (int32_t) strlen(strNodeId));
SOPC_FieldTarget_Set_NodeId(fieldTarget, nodeId);
SOPC_FieldTarget_Set_AttributeId(fieldTarget, 13); // Value => AttributeId=13
}
SOPC_PubSubConfiguration* SOPC_PubSubConfig_GetStatic()
{
bool alloc = true;
SOPC_PubSubConfiguration* config = SOPC_PubSubConfiguration_Create();
SOPC_PubSubConnection* connection;
/* 1 connection pub */
alloc = SOPC_PubSubConfiguration_Allocate_PubConnection_Array(config, 1);
/** connection pub 0 **/
if (alloc)
{
// Set publisher id and address
connection = SOPC_PubSubConfiguration_Get_PubConnection_At(config, 0);
SOPC_PubSubConnection_Set_PublisherId_UInteger(connection, 42);
alloc = SOPC_PubSubConnection_Set_Address(connection, "opc.udp://" PUBLISHER_ADDRESS);
}
if (alloc)
{
// 2 pub messages
alloc = SOPC_PubSubConnection_Allocate_WriterGroup_Array(connection, 2);
}
if (alloc)
{
// 2 published data sets
alloc = SOPC_PubSubConfiguration_Allocate_PublishedDataSet_Array(config, 2);
}
/*** Pub Message 14 ***/
SOPC_DataSetWriter* writer = NULL;
if (alloc)
{
writer = SOPC_PubSubConfig_SetPubMessageAt(connection, 0, 14, 1, PUBLISH_PERIOD);
alloc = NULL != writer;
}
SOPC_PublishedDataSet* dataset = NULL;
if (alloc)
{
dataset = SOPC_PubSubConfig_InitDataSet(config, 0, writer, 2);
alloc = NULL != dataset;
}
if (alloc)
{
SOPC_PubSubConfig_SetPubVariableAt(dataset, 0, "ns=1;s=PubBool", SOPC_Boolean_Id);
SOPC_PubSubConfig_SetPubVariableAt(dataset, 1, "ns=1;s=PubString", SOPC_String_Id);
}
/*** Pub Message 15 ***/
if (alloc)
{
writer = SOPC_PubSubConfig_SetPubMessageAt(connection, 1, 15, 1, PUBLISH_PERIOD);
alloc = NULL != writer;
}
if (alloc)
{
dataset = SOPC_PubSubConfig_InitDataSet(config, 1, writer, 2);
alloc = NULL != dataset;
}
if (alloc)
{
SOPC_PubSubConfig_SetPubVariableAt(dataset, 0, "ns=1;s=PubInt", SOPC_Int64_Id);
SOPC_PubSubConfig_SetPubVariableAt(dataset, 1, "ns=1;s=PubUInt", SOPC_UInt64_Id);
}
/* 1 connection Sub */
alloc = SOPC_PubSubConfiguration_Allocate_SubConnection_Array(config, 1);
/** connection sub 0 **/
if (alloc)
{
// Set subscriber id and address
connection = SOPC_PubSubConfiguration_Get_SubConnection_At(config, 0);
alloc = SOPC_PubSubConnection_Set_Address(connection, "opc.udp://" SUBSCRIBER_ADDRESS);
}
if (alloc)
{
// 2 sub messages
alloc = SOPC_PubSubConnection_Allocate_ReaderGroup_Array(connection, 2);
}
SOPC_DataSetReader* reader = NULL;
/*** Sub Message 14 ***/
if (alloc)
{
reader = SOPC_PubSubConfig_SetSubMessageAt(connection, 0, 42, 14, 1, SUBSCRIBE_PERIOD);
alloc = NULL != reader;
}
if (alloc)
{
alloc = SOPC_PubSubConfig_SetSubNbVariables(reader, 2);
}
if (alloc)
{
SOPC_PubSubConfig_SetSubVariableAt(reader, 0, "ns=1;s=SubBool", SOPC_Boolean_Id);
SOPC_PubSubConfig_SetSubVariableAt(reader, 1, "ns=1;s=SubString", SOPC_String_Id);
}
/*** Sub Message 15 ***/
if (alloc)
{
reader = SOPC_PubSubConfig_SetSubMessageAt(connection, 1, 42, 15, 1, SUBSCRIBE_PERIOD);
alloc = NULL != reader;
}
if (alloc)
{
alloc = SOPC_PubSubConfig_SetSubNbVariables(reader, 2);
}
if (alloc)
{
SOPC_PubSubConfig_SetSubVariableAt(reader, 0, "ns=1;s=SubInt", SOPC_Int64_Id);
SOPC_PubSubConfig_SetSubVariableAt(reader, 1, "ns=1;s=SubUInt", SOPC_UInt64_Id);
}
if (!alloc)
{
SOPC_PubSubConfiguration_Delete(config);
return NULL;
}
return config;
}
/*
* Licensed to Systerel under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Systerel licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/** Hard-coded configuration */
#ifndef CONFIG_H_
#define CONFIG_H_
#define xstr(s) str(s)
#define str(s) #s
/* Server Configuration */
#define SERVER_CERT_PATH "./server_public/server_2k_cert.der"
#define SERVER_KEY_PATH "./server_private/server_2k_key.pem"
#define CA_CERT_PATH "./trusted/cacert.der"
#define CA_CRL_PATH "./revoked/cacrl.der"
#define DEFAULT_ENDPOINT_URL "opc.tcp://localhost:4841"
#define APPLICATION_URI "urn:S2OPC:localhost"
#define PRODUCT_URI "urn:S2OPC:localhost"
#define SERVER_DESCRIPTION "S2OPC Server + PubSub"
#define LOG_PATH "./logs/"
#define ADDRESS_SPACE_PATH "./pubsub_server.xml"
#define SLEEP_TIMEOUT 100
#define NODEID_PUBSUB_STATUS "ns=1;s=PubSubStatus"
#define NODEID_PUBSUB_CONFIG "ns=1;s=PubSubConfiguration"
#define NODEID_PUBSUB_COMMAND "ns=1;s=PubSubStartStop"
#define SYNCHRONOUS_READ_TIMEOUT 10000
extern char* ENDPOINT_URL;
/* Sub Configuration */
#define PUBSUB_CONFIG_PATH "./config_pubsub_server.xml"
#endif /* CONFIG_H_ */
/*
* Licensed to Systerel under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Systerel licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <stdint.h>
#include "sopc_mem_alloc.h"
#include "sopc_toolkit_async_api.h"
#include "sopc_types.h"
#include "helpers.h"
SOPC_ReturnStatus Helpers_AsyncLocalWrite(uint32_t endpointConfigIdx,
SOPC_NodeId** lpNid,
uint32_t* lAttrId,
SOPC_DataValue** lpDv,
size_t nItems,
Helpers_WriteValue_Callback wvNotifier)
{
if (NULL == lpNid || NULL == lAttrId || NULL == lpDv || INT32_MAX < nItems)
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
for (size_t i = 0; i < nItems; ++i)
{
/* Does not protect against invalid attribute ids */
if (NULL == lpNid[i] || NULL == lpDv[i])
{
return SOPC_STATUS_INVALID_PARAMETERS;
}
}
OpcUa_WriteRequest* request = SOPC_Calloc(1, sizeof(OpcUa_WriteRequest));
OpcUa_WriteValue* lwv = SOPC_Calloc(nItems, sizeof(OpcUa_WriteValue));
if (NULL == request || NULL == lwv)
{
SOPC_Free(request);
SOPC_Free(lwv);
return SOPC_STATUS_OUT_OF_MEMORY;
}
OpcUa_WriteRequest_Initialize(request);
request->NoOfNodesToWrite = (int32_t) nItems;
/* Now fills the WriteValues */
SOPC_ReturnStatus status = SOPC_STATUS_OK;
for (size_t i = 0; i < nItems && SOPC_STATUS_OK == status; ++i)
{
OpcUa_WriteValue* wv = &lwv[i];
status = SOPC_NodeId_Copy(&wv->NodeId, lpNid[i]);
wv->AttributeId = lAttrId[i];
SOPC_String_Initialize(&wv->IndexRange);
if (SOPC_STATUS_OK == status)
{
status = SOPC_DataValue_Copy(&wv->Value, lpDv[i]);
}
}
/* Optionnal before-hand write notification system */
for (size_t i = 0; i < nItems && SOPC_STATUS_OK == status && NULL != wvNotifier; ++i)
{
wvNotifier(&lwv[i]);
}
/* Finish the WriteRequest and send it */
if (SOPC_STATUS_OK == status)
{
request->NodesToWrite = lwv;
SOPC_ToolkitServer_AsyncLocalServiceRequest(endpointConfigIdx, request, 0);
}
else
{
for (size_t i = 0; i < nItems; ++i)
{
OpcUa_WriteValue_Clear(&lwv[i]);
}
SOPC_Free(lwv);
lwv = NULL;
SOPC_Free(request);
request = NULL;
}
return status;
}
/*
* Licensed to Systerel under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Systerel licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef HELPERS_H_
#define HELPERS_H_
#include "sopc_builtintypes.h"
typedef void (*Helpers_WriteValue_Callback)(OpcUa_WriteValue* pwv);
/**
* Copy the NodeIds, the AttributeIds, and the DataValues in an array of WriteValues,
* which is then encapsulated in an OpcUa_WriteRequest,
* which is finally sent to the toolkit.
*
* wvNotifier is (sort-of) compatible with Address Space notification callback and can be NULL.
* It is called on each WriteValue of the WriteRequest.
* It is called *before* the WriteRequest is processed by the toolkit.
*/
SOPC_ReturnStatus Helpers_AsyncLocalWrite(uint32_t endpointConfigIdx,
SOPC_NodeId** lNid,
uint32_t* lAttrId,
SOPC_DataValue** lpDv,
size_t nItems,
Helpers_WriteValue_Callback wvNotifier);
#endif /* HELPERS_H_ */
/*
* Licensed to Systerel under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Systerel licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include "sopc_helper_uri.h"
#include "sopc_pubsub_helpers.h"
#include "sopc_time.h"
#include "config.h"
#include "pubsub.h"
#include "server.h"
volatile sig_atomic_t stopSignal = 0;
static void signal_stop_server(int sig)
{
(void) sig;
if (stopSignal != 0)
{
exit(1);
}
else
{
stopSignal = 1;
}
}
int main(int argc, char* const argv[])
{
/* Signal handling: close the server gracefully when interrupted */
signal(SIGINT, signal_stop_server);
signal(SIGTERM, signal_stop_server);
/* Parse command line arguments ? */
if (argc > 1)
{
assert(argc == 2);
size_t tmp, tmp2, tmp3;
bool res = SOPC_Helper_URI_ParseUri_WithPrefix("opc.tcp://", argv[1], &tmp, &tmp2, &tmp3);
if (!res)
{
printf("# Error: invalid OPC UA server address\n");
exit(1);
}
ENDPOINT_URL = argv[1];
}
else
{
ENDPOINT_URL = DEFAULT_ENDPOINT_URL;
}
/* Initialize S2OPC Server */
SOPC_ReturnStatus status = Server_Initialize();
if (SOPC_STATUS_OK != status)
{
printf("# Error: Could not initialize the server.\n");
}
/* Configure the Server */
SOPC_S2OPC_Config s2opcConfig;
SOPC_S2OPC_Config_Initialize(&s2opcConfig);
if (SOPC_STATUS_OK == status)
{
status = Server_CreateServerConfig(&s2opcConfig);
if (SOPC_STATUS_OK != status)
{
printf("# Error: Could not create the server configuration.\n");
}
}
if (SOPC_STATUS_OK == status)
{
status = Server_LoadAddressSpace();
}
/* Configuration of the PubSub module is done upon PubSub start through the local service */
/* Start the Server */
if (SOPC_STATUS_OK == status)
{
status = Server_ConfigureStartServer(&s2opcConfig.serverConfig.endpoints[0]);
}
/* Write in PubSub nodes, which starts the PubSub */
if (SOPC_STATUS_OK == status)
{
status = Server_WritePubSubNodes();
}
/* Wait for a signal */
while (SOPC_STATUS_OK == status && Server_IsRunning() && stopSignal == 0)
{
SOPC_Sleep(SLEEP_TIMEOUT);
if (Server_PubSubStop_Requested())
{
PubSub_Stop();
printf("# Info: PubSub stopped through Start/Stop Command.\n");
}
if (Server_PubSubStart_Requested())
{
status = PubSub_Configure();
if (SOPC_STATUS_OK == status)
{
printf("# Info: PubSub configured through Start/Stop Command.\n");
}
else
{
printf("# Warning: Start/Stop Command failed to configure the PubSub module.\n");
}
if (SOPC_STATUS_OK == status)
{
status = PubSub_Start() ? SOPC_STATUS_OK : SOPC_STATUS_NOK;
if (SOPC_STATUS_NOK == status)
{
PubSub_Stop(); // Ensure Pub & Sub are stopped in this case
}
}
if (SOPC_STATUS_OK == status)
{
printf("# Info: PubSub started through Start/Stop Command.\n");
}
else
{
printf("# Warning: Start/Stop Command failed to start the PubSub module.\n");
}
}
if (SOPC_STATUS_OK != status)
{
printf("# Warning: waiting for a new configure + start command !\n");
status = SOPC_STATUS_OK;
}
}
/* Clean and quit */
PubSub_StopAndClear();
Server_StopAndClear(&s2opcConfig);
printf("# Info: Server closed.\n");
}
/*
* Licensed to Systerel under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Systerel licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "sopc_array.h"
#include "sopc_atomic.h"
#include "sopc_filesystem.h"
#include "sopc_pub_scheduler.h"
#include "sopc_sub_scheduler.h"
#include "sopc_udp_sockets.h"
#include "sopc_xml_loader.h"
#include "config.h"
#include "pubsub.h"
#include "server.h"
#ifdef PUBSUB_STATIC_CONFIG
#include "pubsub_config_static.h"
#endif
static int32_t pubsubOnline = 0;
static SOPC_PubSubConfiguration* g_pPubSubConfig = NULL;
static SOPC_SubTargetVariableConfig* g_pTargetConfig = NULL;
static SOPC_PubSourceVariableConfig* g_pSourceConfig = NULL;
static void free_global_configurations(void);
#ifndef PUBSUB_STATIC_CONFIG
static void PubSub_SaveConfiguration(char* configBuffer);
static void PubSub_SaveConfiguration(char* configBuffer)
{
FILE* fd = fopen(PUBSUB_CONFIG_PATH, "w");
if (NULL != fd)
{
const int ret = fputs(configBuffer, fd);
if (EOF == ret)
{
printf("# Error: Cannot write %s\n", configBuffer);
}
fclose(fd);
}
else
{
printf("# Error: Cannot open \"%s\": %s\n", PUBSUB_CONFIG_PATH, strerror(errno));
}
}
#endif
SOPC_ReturnStatus PubSub_Configure(void)
{
SOPC_ReturnStatus status = SOPC_STATUS_OK;
#ifdef PUBSUB_STATIC_CONFIG
/* static configuration cannot be changed */
if (NULL != g_pPubSubConfig)
{
return SOPC_STATUS_OK;
}
SOPC_PubSubConfiguration* pPubSubConfig = SOPC_PubSubConfig_GetStatic();
if (NULL == pPubSubConfig)
{
return SOPC_STATUS_NOK;
}
printf("# Info: PubSub static configuration loaded.\n");
#else
/* PubSub Configuration */
SOPC_Array* configBuffers = Server_GetConfigurationPaths();
if (NULL == configBuffers || SOPC_Array_Size(configBuffers) != 1)
{
printf("# Error: Multiple configuration paths.\n");
SOPC_Array_Delete(configBuffers);
return SOPC_STATUS_NOK;
}
char* configBuffer = SOPC_Array_Get(configBuffers, char*, 0);
FILE* fd = SOPC_FileSystem_fmemopen((void*) configBuffer, strlen(configBuffer), "r");
SOPC_PubSubConfiguration* pPubSubConfig = NULL;
if (NULL == fd)
{
printf("# Error: Cannot open \"%s\": %s.\n", configBuffer, strerror(errno));
status = SOPC_STATUS_NOK;
}
if (SOPC_STATUS_OK == status)
{
pPubSubConfig = SOPC_PubSubConfig_ParseXML(fd);
if (NULL == pPubSubConfig)
{
printf("# Error: Cannot parse PubSub configuration file \"%s\".\n", configBuffer);
status = SOPC_STATUS_NOK;
}
else
{
printf("# Info: PubSub XML configuration loaded.\n");
}
}
if (NULL != fd)
{
fclose(fd);
fd = NULL;
}
#endif
/* Sub target configuration */
SOPC_SubTargetVariableConfig* pTargetConfig = NULL;
if (SOPC_STATUS_OK == status)
{
pTargetConfig = SOPC_SubTargetVariableConfig_Create(Server_SetTargetVariables);
if (NULL == pTargetConfig)
{
printf("# Error: Cannot create Sub configuration.\n");
status = SOPC_STATUS_NOK;
}
}
/* Pub target configuration */
SOPC_PubSourceVariableConfig* pSourceConfig = NULL;
if (SOPC_STATUS_OK == status)
{
pSourceConfig = SOPC_PubSourceVariableConfig_Create(Server_GetSourceVariables);
if (NULL == pSourceConfig)
{
printf("# Error: Cannot create Pub configuration.\n");
status = SOPC_STATUS_NOK;
}
}
if (SOPC_STATUS_OK == status)
{
free_global_configurations();
g_pPubSubConfig = pPubSubConfig;
g_pTargetConfig = pTargetConfig;
g_pSourceConfig = pSourceConfig;
}
#ifndef PUBSUB_STATIC_CONFIG
/* Save XML configuration */
if (SOPC_STATUS_OK == status)
{
PubSub_SaveConfiguration(configBuffer);
}
SOPC_Array_Delete(configBuffers);
#endif
return status;
}
bool PubSub_IsRunning(void)
{
return SOPC_Atomic_Int_Get(&pubsubOnline);
}
bool PubSub_Start(void)
{
bool subOK = false;
bool pubOK = false;
uint32_t sub_nb_connections = SOPC_PubSubConfiguration_Nb_SubConnection(g_pPubSubConfig);
uint32_t pub_nb_connections = SOPC_PubSubConfiguration_Nb_PubConnection(g_pPubSubConfig);
if (sub_nb_connections > 0)
{
subOK = SOPC_SubScheduler_Start(g_pPubSubConfig, g_pTargetConfig, Server_SetSubStatus);
}
if (pub_nb_connections > 0)
{
pubOK = SOPC_PubScheduler_Start(g_pPubSubConfig, g_pSourceConfig);
}
if (subOK || pubOK)
{
SOPC_Atomic_Int_Set(&pubsubOnline, 1);
if (!subOK)
{
// PubSubStatus NOT managed by Sub scheduler: set operational manually
Server_SetSubStatus(SOPC_PubSubState_Operational);
}
}
return subOK || pubOK;
}
void PubSub_Stop(void)
{
SOPC_Atomic_Int_Set(&pubsubOnline, 0);
SOPC_SubScheduler_Stop();
SOPC_PubScheduler_Stop();
// Force Disabled after stop in case Sub scheduler was not start (no management of the status)
Server_SetSubStatus(SOPC_PubSubState_Disabled);
}
void PubSub_StopAndClear(void)
{
PubSub_Stop();
free_global_configurations();
}
static void free_global_configurations(void)
{
SOPC_SubTargetVariableConfig_Delete(g_pTargetConfig);
g_pTargetConfig = NULL;
SOPC_PubSourceVariableConfig_Delete(g_pSourceConfig);
g_pSourceConfig = NULL;
SOPC_PubSubConfiguration_Delete(g_pPubSubConfig);
g_pPubSubConfig = NULL;
}
/*
* Licensed to Systerel under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Systerel licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/** \file
*
* Pub+Sub library API.
*/
#ifndef PUBSUB_H
#define PUBSUB_H
#include "sopc_enums.h"
/* Running the PubSub modules */
SOPC_ReturnStatus PubSub_Configure(void);
bool PubSub_Start(void);
bool PubSub_IsRunning(void);
void PubSub_Stop(void);
void PubSub_StopAndClear(void);
#endif /* PUBSUB_H */
/*
* Licensed to Systerel under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Systerel licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef PUBSUB_CONF_STATIC_H_
#define PUBSUB_CONF_STATIC_H_
#include "sopc_pubsub_conf.h"
SOPC_PubSubConfiguration* SOPC_PubSubConfig_GetStatic(void);
#endif /* PUBSUB_CONF_STATIC_H_ */
/*
* Licensed to Systerel under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Systerel licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/** \file
*
* Server's API, split server functionalities in smaller chunks.
*/
#ifndef SERVER_H_
#define SERVER_H_
#include <stdbool.h>
#include "sopc_array.h"
#include "sopc_builtintypes.h"
#include "sopc_sub_scheduler.h"
#include "sopc_user_app_itf.h"
/* Running the Server */
SOPC_ReturnStatus Server_Initialize(void);
/* SOPC_ReturnStatus Server_SetRuntimeVariables(void); */ /* Future */
SOPC_ReturnStatus Server_CreateServerConfig(SOPC_S2OPC_Config* output_s2opcConfig);
SOPC_ReturnStatus Server_LoadAddressSpace(void);
/** Calls Toolkit_Configured(), starts the server */
SOPC_ReturnStatus Server_ConfigureStartServer(SOPC_Endpoint_Config* pEpConfig);
bool Server_IsRunning(void);
SOPC_ReturnStatus Server_WritePubSubNodes(void);
void Server_StopAndClear(SOPC_S2OPC_Config* pConfig);
bool Server_PubSubStop_Requested(void);
bool Server_PubSubStart_Requested(void);
/* Interacting with the Sub module */
SOPC_Array* Server_GetConfigurationPaths(void); /* Returns an array of char* */
void Server_SetSubStatus(SOPC_PubSubState state);
bool Server_SetTargetVariables(OpcUa_WriteValue* nodesToWrite, int32_t nbValues);
SOPC_DataValue* Server_GetSourceVariables(OpcUa_ReadValueId* nodesToRead, int32_t nbValues);
#endif /* SERVER_H_ */
/*
* Licensed to Systerel under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Systerel licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <errno.h>
#include <inttypes.h>
#include <kernel.h>
#include <limits.h>
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef __INT32_MAX__
#include <toolchain/xcc_missing_defs.h>
#endif
#include <fcntl.h>
#include <kernel.h>
#include <net/net_ip.h>
#include <net/socket.h>
#ifndef NULL
#define NULL ((void*) 0)
#endif
#include "opcua_identifiers.h"
#include "opcua_statuscodes.h"
#include "sopc_atomic.h"
#include "sopc_crypto_profiles.h"
#include "sopc_crypto_provider.h"
#include "sopc_encodeable.h"
#include "sopc_mem_alloc.h"
#include "sopc_pki_stack.h"
#include "sopc_time.h"
#include "sopc_toolkit_async_api.h"
#include "sopc_toolkit_config.h"
#include "sopc_user_app_itf.h"
#include "sopc_user_manager.h"
#include "sopc_common.h"
#include "sopc_mutexes.h"
#include "sopc_raw_sockets.h"
#include "sopc_threads.h"
#include "sopc_time.h"
#include "sopc_udp_sockets.h"
#include "sopc_helper_uri.h"
#include "sopc_pub_scheduler.h"
#include "sopc_pubsub_helpers.h"
#include "sopc_time.h"
#include "embedded/sopc_addspace_loader.h"
#include "runtime_variables.h"
#include "network_init.h"
#include "threading_alt.h"
#include "static_security_data.h"
#include "config.h"
#include "pubsub.h"
#include "server.h"
#define LIBC_STDOUT_BUFFER_HOOK 0
/****************************************/
#if LIBC_STDOUT_BUFFER_HOOK == 1
extern void __stdout_buffer_hook_install(void (*fn)(const char*, int));
extern void __stdout_hook_install(int (*fn)(int));
K_MUTEX_DEFINE(my_mutex);
char gBuffer[256];
static void _zephyr_callback_log_buffer_hook(const char* buffer, int size)
{
//SOPC_LogServer_Print(0, buffer, size, false);
k_mutex_lock(&my_mutex,K_FOREVER);
size = size > 256 ? 256 : size;
memset(gBuffer,0,256);
memcpy(gBuffer,buffer,size);
gBuffer[size-1]=0;
(void)printk("%s\r\n",(char*)gBuffer);
k_mutex_unlock(&my_mutex);
return;
}
static int _zephyr_callback_log_hook(int character)
{
if (character == '\r')
{
return character;
}
return character;
}
static int _zephyr_add_log_hook(struct device* d)
{
ARG_UNUSED(d);
__stdout_hook_install(_zephyr_callback_log_hook);
__stdout_buffer_hook_install(_zephyr_callback_log_buffer_hook);
return 0;
}
#endif
#ifndef SOPC_PUBSCHEDULER_BEATHEART_FROM_IRQ
void Pub_BeatHeart(void)
{
SOPC_Sleep(50);
}
#endif
volatile uint32_t stopSignal = 0;
static void* callbackTest(void* pCtx)
{
/* Signal handling: close the server gracefully when interrupted */
#if SOPC_PUBSCHEDULER_BEATHEART_FROM_IRQ == 1
uint32_t tickValue = 0;
#endif
int argc = 1;
char** argv = (char**) SOPC_Calloc(1, sizeof(char*));
assert(argv != NULL);
argv[0] = (char*) SOPC_Calloc(1, 16);
assert(argv[0] != NULL);
snprintf(argv[0], 16, "%s", "toolkit_test");
/* Parse command line arguments ? */
if (argc > 1)
{
assert(argc == 2);
int32_t tmp, tmp2, tmp3;
bool res = SOPC_Helper_URI_ParseUri_WithPrefix("opc.tcp://", argv[1], &tmp, &tmp2, &tmp3);
if (!res)
{
printf("# Error: invalid OPC UA server address\n");
exit(1);
}
ENDPOINT_URL = argv[1];
}
else
{
ENDPOINT_URL = DEFAULT_ENDPOINT_URL;
}
/* Initialize S2OPC Server */
SOPC_ReturnStatus status = Server_Initialize();
if (SOPC_STATUS_OK != status)
{
printf("# Error: Could not initialize the server.\n");
}
/* Configure the Server */
SOPC_S2OPC_Config s2opcConfig;
SOPC_S2OPC_Config_Initialize(&s2opcConfig);
if (SOPC_STATUS_OK == status)
{
status = Server_CreateServerConfig(&s2opcConfig);
if (SOPC_STATUS_OK != status)
{
printf("# Error: Could not create the server configuration.\n");
}
}
if (SOPC_STATUS_OK == status)
{
status = Server_LoadAddressSpace();
}
/* Configuration of the PubSub module is done upon PubSub start through the local service */
/* Start the Server */
if (SOPC_STATUS_OK == status)
{
status = Server_ConfigureStartServer(&s2opcConfig.serverConfig.endpoints[0]);
}
/* Write in PubSub nodes, which starts the PubSub */
if (SOPC_STATUS_OK == status)
{
status = Server_WritePubSubNodes();
}
/* Wait for a signal */
while (SOPC_STATUS_OK == status && Server_IsRunning() && stopSignal == 0)
{
// Beat heart. Simple pause during SOPC_TIMER_RESOLUTION_MS if
// SOPC_PUBSCHEDULER_BEATHEART_FROM_IRQ #define is set to 0
// in the sopc_pub_scheduler header file.
// Else, SOPC_PubScheduler_BeatHeartFromIRQ is defined and called
// with a monotonic uint32_t counter, followed by a pause of
// SOPC_TIMER_RESOLTION_MS
Pub_BeatHeart();
if (Server_PubSubStop_Requested())
{
PubSub_Stop();
printf("# Info: PubSub stopped through Start/Stop Command.\n");
}
if (Server_PubSubStart_Requested())
{
status = PubSub_Configure();
if (SOPC_STATUS_OK == status)
{
printf("# Info: PubSub configured through Start/Stop Command.\n");
}
else
{
printf("# Warning: Start/Stop Command failed to configure the PubSub module.\n");
}
if (SOPC_STATUS_OK == status)
{
status = PubSub_Start() ? SOPC_STATUS_OK : SOPC_STATUS_NOK;
if (SOPC_STATUS_NOK == status)
{
PubSub_Stop(); // Ensure Pub & Sub are stopped in this case
}
}
if (SOPC_STATUS_OK == status)
{
printf("# Info: PubSub started through Start/Stop Command.\n");
}
else
{
printf("# Warning: Start/Stop Command failed to start the PubSub module.\n");
}
}
if (SOPC_STATUS_OK != status)
{
printf("# Warning: waiting for a new configure + start command !\n");
status = SOPC_STATUS_OK;
}
}
/* Clean and quit */
PubSub_StopAndClear();
Server_StopAndClear(&s2opcConfig);
printf("# Info: Server closed.\n");
return NULL;
}
static void TEST_LAUNCH(void)
{
SOPC_ReturnStatus result;
#if LIBC_STDOUT_BUFFER_HOOK == 1
_zephyr_add_log_hook(NULL);
#endif
bool netInit = Network_Initialize();
assert(netInit == true);
Thread sopcThreadHandle1 = NULL;
printk("\r\nReady to launch application :)\r\n");
result = SOPC_Thread_Create(&sopcThreadHandle1, callbackTest, NULL, NULL);
assert(SOPC_STATUS_OK == result);
SOPC_Thread_Join(sopcThreadHandle1);
while (true)
{
printf("\r\nThread quit, error and go to idle...\r\n");
SOPC_Sleep(1000);
}
return;
}
void main(void)
{
TEST_LAUNCH();
}
/*
* Licensed to Systerel under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Systerel licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef SOPC_RUNTIME_VARIABLES_H
#define SOPC_RUNTIME_VARIABLES_H
#include "sopc_common_build_info.h"
#include "sopc_types.h"
#include "sopc_user_app_itf.h"
typedef struct _RuntimeVariables
{
SOPC_Server_Config* serverConfig;
uint32_t secondsTillShutdown;
SOPC_LocalizedText shutdownReason;
OpcUa_ServerState server_state;
OpcUa_BuildInfo build_info;
SOPC_Byte service_level;
bool auditing;
uint32_t maximum_operation_per_request;
} RuntimeVariables;