open62541 (http://open62541.org) — это реализация OPC UA с открытым исходным кодом (OPC Unified Architecture/IEC 62541), написанная на языке C. Библиотека пригодна для использования со всеми основными компиляторами и предоставляет необходимые инструменты для реализации выделенных клиентов и серверов OPC UA или для интеграции связи на основе OPC UA в существующие приложения. Библиотека open62541 не зависит от платформы: все функции, специфичные для платформы, реализуются через сменные плагины для легкого портирования на различные (встроенные) цели.
open62541 распространяется по лицензии Mozilla Public License v2.0 (MPLv2). Это позволяет комбинировать и распространять библиотеку open62541 с любым проприетарным программным обеспечением. Только изменения в самой библиотеке open62541 должны лицензироваться по MPLv2 при копировании и распространении. Плагины, а также примеры серверов и клиентов находятся в свободном доступе (лицензия CC0). Их можно повторно использовать под любой лицензией, и изменения не требуют публикации.
Библиотека доступна в стандартном исходном и двоичном виде. Кроме того, дистрибутив исходного кода в виде одного файла объединяет всю библиотеку в один файл .c и .h, который можно легко добавить в существующие проекты. Примеры реализации сервера и клиента можно найти в каталоге /examples или ниже на этой странице.
open62541 реализует OPC UA SDK с поддержкой серверов, клиентов и связи PubSub (публикация-подписка). Подробную информацию смотрите в обзоре функций.
open62541 распространяется по лицензии MPLv2. То есть изменения файлов под MPLv2 подпадают под ту же лицензию с открытым исходным кодом. Но библиотеку можно комбинировать с частной разработкой из отдельных файлов, даже если создается статический двоичный файл, без влияния лицензии на частные файлы. Подробности смотрите в полном лицензионном документе.
Fraunhofer IOSB нанимает нескольких разработчиков open62541 и обеспечивает коммерческую поддержку . Дополнительные поставщики услуг в экосистеме open62541 перечислены на open62541.org.
Пример сервера (server_ctt), созданный с использованием open62541 v1.0, соответствует профилю «Сервер микровстроенных устройств» OPC Foundation, поддерживающему связь клиент/сервер OPC UA, подписки, вызовы методов и безопасность (шифрование) с политиками безопасности «Basic128Rsa15». ', 'Basic256' и 'Basic256Sha256', а также фасеты 'сервер методов' и 'узел'. управление'. Дополнительную информацию см. на https://open62541.org/certified-sdk.
PubSub (UADP) реализован в open62541. Но на данный момент (сентябрь 2019 г.) эта функция не может быть сертифицирована из-за отсутствия официальных тестовых примеров и инструментов тестирования.
При разработке регулярно применяются инструменты тестирования соответствия (CTT) OPC Foundation. Конфигурация и результаты CTT отслеживаются по адресу https://github.com/open62541/open62541-ctt. В настоящее время регулярно тестируются профили OPC UA в CTT:
См. страницу «Функции open62541», где подробно рассматривается поддержка модулей соответствия, составляющих профили OPC UA.
Общее введение в OPC UA и документацию open62541 можно найти по адресу http://open62541.org. Предыдущие выпуски библиотеки можно скачать по адресу https://github.com/open62541/open62541/releases.
Все сообщество open62541 обрабатывает запросы на публичную поддержку на Github и в списке рассылки. Для индивидуального обсуждения и поддержки используйте следующие каналы:
Мы хотим создать открытое и гостеприимное сообщество. Пожалуйста, примите во внимание наш кодекс поведения.
Среда сборки open62541 создается с помощью CMake. Подробности смотрите в документации по сборке. Чтобы упростить интеграцию с существующими программными проектами, исходники open62541 можно сжать (объединить) в единый дистрибутив, пару файлов open62541.c/.h
. Функциональность, включенная в однофайловое распространение, зависит от текущей конфигурации CMake.
Исходный код структурирован следующим образом:
/include
): общедоступный API доступен приложениям, использующим open62541. Заголовки реализаций плагинов находятся в /plugins/include
./src
): основная библиотека не имеет никаких зависимостей, кроме стандартных заголовков C99./arch
): поддержка архитектуры реализуется через плагин EventLoop
. Это позволяет исключить код, специфичный для архитектуры (например, для использования API-интерфейсов POSIX), из основной библиотеки. Предоставляются порты для различных (встроенных) архитектур./plugins
): интерфейсы плагинов позволяют интегрироваться с различными серверными системами и библиотеками. Например, относительно криптопримитивов, хранения информационной модели и так далее. Предоставляются реализации по умолчанию./deps
): некоторые дополнительные библиотеки используются через подмодули git или встроены в папку deps/
. Дополнительную информацию о сторонних библиотеках и соответствующих лицензиях можно найти в deps/README.md.В большинстве систем для простого open62541 требуется только стандартная библиотека C. В зависимости от конфигурации сборки open62541 зависит от дополнительных библиотек, таких как mbedTLS или OpenSSL для шифрования.
Поскольку open62541 является проектом с открытым исходным кодом, новым участникам предлагается помочь улучшить open62541. В файле CONTRIBUTING.md собраны лучшие практики, которые мы ожидаем при написании кода. Ниже приведены хорошие отправные точки для новых участников:
Для индивидуальной разработки, которая в конечном итоге станет частью библиотеки open62541, пожалуйста, держите в курсе одного из основных сопровождающих.
Мы делаем упор на качество кода. Следующие показатели качества постоянно проверяются и обеспечиваются до выпуска официального релиза:
В проекте налажен процесс устранения уязвимостей. Подробную информацию о том, как ответственно раскрывать результаты сопровождающим, можно найти на сайте SECURITY.md.
Примеры кода можно найти в каталоге /examples. Для сборки примеров мы рекомендуем установить open62541, как указано в предыдущем разделе. Используя компилятор GCC, просто запустите gcc -std=c99
(под Windows вам может потребоваться добавить дополнительную ссылку на библиотеку сокетов ws2_32
).
#include
int main ( int argc , char * * argv )
{
/* Create a server listening on port 4840 (default) */
UA_Server * server = UA_Server_new ();
/* Add a variable node to the server */
/* 1) Define the variable attributes */
UA_VariableAttributes attr = UA_VariableAttributes_default ;
attr . displayName = UA_LOCALIZEDTEXT ( "en-US" , "the answer" );
UA_Int32 myInteger = 42 ;
UA_Variant_setScalar ( & attr . value , & myInteger , & UA_TYPES [ UA_TYPES_INT32 ]);
/* 2) Define where the node shall be added with which browsename */
UA_NodeId newNodeId = UA_NODEID_STRING ( 1 , "the.answer" );
UA_NodeId parentNodeId = UA_NS0ID ( OBJECTSFOLDER );
UA_NodeId parentReferenceNodeId = UA_NS0ID ( ORGANIZES );
UA_NodeId variableType = UA_NODEID_NULL ; /* take the default variable type */
UA_QualifiedName browseName = UA_QUALIFIEDNAME ( 1 , "the answer" );
/* 3) Add the node */
UA_Server_addVariableNode ( server , newNodeId , parentNodeId ,
parentReferenceNodeId , browseName ,
variableType , attr , NULL , NULL );
/* Run the server (until ctrl-c interrupt) */
UA_StatusCode status = UA_Server_runUntilInterrupt ( server );
/* Clean up */
UA_Server_delete ( server );
return status == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE ;
}
#include
#include
#include
int main ( int argc , char * argv [])
{
/* Create a client and connect */
UA_Client * client = UA_Client_new ();
UA_ClientConfig_setDefault ( UA_Client_getConfig ( client ));
UA_StatusCode status = UA_Client_connect ( client , "opc.tcp://localhost:4840" );
if ( status != UA_STATUSCODE_GOOD ) {
UA_Client_delete ( client );
return status ;
}
/* Read the value attribute of the node. UA_Client_readValueAttribute is a
* 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 );
status = UA_Client_readValueAttribute ( client , UA_NODEID_STRING ( 1 , "the.answer" ), & value );
if ( status == UA_STATUSCODE_GOOD &&
UA_Variant_hasScalarType ( & value , & UA_TYPES [ UA_TYPES_INT32 ])) {
printf ( "the value is: %in" , * ( UA_Int32 * ) value . data );
}
/* Clean up */
UA_Variant_clear ( & value );
UA_Client_delete ( client ); /* Disconnects the client internally */
return status == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE ;
}