├── .gitatributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question.md └── workflows │ └── build-all.yml ├── .gitignore ├── .gitkeep ├── .gitlab-ci.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CONTRIBUTORS.md ├── Examples ├── .gitignore ├── .gitkeep ├── BufferedExchange │ ├── .gitignore │ ├── README.md │ └── src │ │ ├── BufferedExchangeComponent.cpp │ │ ├── BufferedExchangeComponent.hpp │ │ ├── BufferedExchangeProgram.cpp │ │ ├── BufferedExchangeProgram.hpp │ │ └── MyWorker.hpp ├── ComponentPorts │ ├── CMakeLists.txt │ ├── README.md │ ├── external │ │ └── ADD_DEPENDENT_LIBRARIES_HERE.txt │ └── src │ │ ├── ComponentWithPorts.cpp │ │ ├── ComponentWithPorts.hpp │ │ ├── MyProgram.cpp │ │ └── MyProgram.hpp ├── CppDataTypeTest │ ├── README.md │ └── src │ │ ├── CppDataTypeTestComponent.cpp │ │ ├── CppDataTypeTestComponent.hpp │ │ ├── CppDataTypeTestProgram.cpp │ │ └── CppDataTypeTestProgram.hpp ├── DataAccess │ ├── DataAccess.pcwlx │ ├── EngineerProject.zip │ ├── README.MD │ ├── src │ │ ├── DataAccessComponent.cpp │ │ ├── DataAccessComponent.hpp │ │ └── DataAccessLibrary.acf.config │ └── test.bats ├── DynamicPorts │ ├── README.md │ ├── dynaports.gds.config │ ├── dynaports.json │ └── src │ │ └── DynamicPortsProgram.hpp ├── E_Learning_InternalFunctionExtensions │ ├── Picture │ │ └── Architecture.png │ ├── README.MD │ ├── data │ │ ├── AxioReadConfig.json │ │ ├── AxioReadConfig.schema.json │ │ └── LIB_AxioReadLibrary.acf.config │ └── src │ │ ├── COMP_AxioRead.cpp │ │ └── COMP_AxioRead.hpp ├── FileStreamExample │ ├── .gitignore │ ├── README.md │ └── src │ │ ├── FileStreamExampleComponent.cpp │ │ ├── FileStreamExampleComponent.hpp │ │ ├── FileStreamExampleProgram.cpp │ │ └── FileStreamExampleProgram.hpp ├── Force │ ├── Force.pcwex │ ├── README.MD │ └── src │ │ ├── ForceComponent.cpp │ │ └── ForceComponent.hpp ├── IncludeOpenSourceLibrary │ ├── .gitkeep │ └── README.md ├── NoEngineer │ ├── README.MD │ ├── pnd.esm.config │ ├── pnd.gds.config │ ├── pnd.meta.config │ └── pnd.plm.config ├── NotificationExample │ ├── .clang-format │ ├── .editorconfig │ ├── .gitignore │ ├── CMakeLists.txt │ ├── Engineer │ │ ├── Notifications_Example.pcwef │ │ └── Notifications_ExampleFlat │ │ │ ├── content │ │ │ ├── AXLF_Mast~Arp.Io.Axl~0000.libmeta │ │ │ ├── AXLF_Mast~Arp.Io.Axl~0001.compmeta │ │ │ ├── Applikation~Profiles~0000.hmiprofiles │ │ │ ├── Applikatio~Variables~0000.hmivar │ │ │ ├── Applikati~Navigation~0000.hminav │ │ │ ├── CFG_34E4C28~DataList~0000.dl │ │ │ ├── CFG_34E4C~0a2e5357-e~0000.ds │ │ │ ├── CFG_34E4C~PlmConfigu~0000.plmc │ │ │ ├── EIP_Maste~Arp.Io.Eth~0000.libmeta │ │ │ ├── EIP_Maste~Controller~0000.compmeta │ │ │ ├── HMI_Server~DataList~0000.dlr4hmi │ │ │ ├── Hardware~f69cc705-29~0000.DataLink │ │ │ ├── Hardware~f69cc705-29~0001.Transport │ │ │ ├── IB_Master~Arp.Io.Ib.~0000.compmeta │ │ │ ├── IB_Master~Arp.Io.Ib~0000.libmeta │ │ │ ├── Logical Elemen~CRC32~0000.crc │ │ │ ├── Logical E~GeneratedD~0000.dt │ │ │ ├── NewProgram.pou~Code~0000.st │ │ │ ├── NewProgram.~Metadata~0000.meta │ │ │ ├── NewProgram~Variables~0000.var │ │ │ ├── PLCnext~EsmConfigura~0000.esmc │ │ │ ├── PN_Master~Arp.Io.Pn~0000.libmeta │ │ │ ├── PN_Master~Controller~0000.compmeta │ │ │ ├── PROJECT~PROJECT~0000.proj │ │ │ ├── RES_370726C~DataList~0000.dlr4var │ │ │ ├── RES_37072~Arp.Plc.Ec~0000.libmeta │ │ │ ├── RES_37072~EclrCompon~0000.compmeta │ │ │ ├── RES_37072~GlobalVari~0000.var │ │ │ ├── RES_37072~IOConfigur~0000.ioc │ │ │ ├── RES_37072~ResourceSe~0000.set │ │ │ ├── Safety~0000.xml │ │ │ ├── Safety~0000 │ │ │ │ ├── Inventori~SafetyInve~0000.xml │ │ │ │ └── Logs~SafetyMessageLo~0000.xml │ │ │ ├── StorageContent~0000.xml │ │ │ └── StorageProperties~0000.xml │ │ │ └── structure.xml │ ├── MyNmDebug.config │ ├── MyNmDebug.settings │ ├── My_Nm.acf.config │ ├── My_Nm_Logger.config │ ├── README.MD │ ├── plcnext.proj │ ├── plcnext.proj.bak │ └── src │ │ ├── COMP_Notifications.cpp │ │ ├── COMP_Notifications.hpp │ │ ├── ExamplePayload.hpp │ │ ├── PG_ReactToNotification.cpp │ │ ├── PG_ReactToNotification.hpp │ │ ├── PG_SendNotification.cpp │ │ └── PG_SendNotification.hpp ├── OpcPlcManager │ ├── PlcManager.xml │ ├── README.MD │ ├── img │ │ └── method.png │ └── src │ │ ├── OpcPlcManagerComponent.cpp │ │ ├── OpcPlcManagerComponent.hpp │ │ └── OpcPlcManagerLibrary.acf.config ├── ProgramComponentInteraction │ ├── PLCnextEngineer │ │ ├── Debug_PCC_Interaction.pcwef │ │ └── Debug_PCC_InteractionFlat │ │ │ ├── content │ │ │ ├── AXLF_Mast~Arp.Io.Axl~0000.libmeta │ │ │ ├── AXLF_Mast~Arp.Io.Axl~0001.compmeta │ │ │ ├── Applikation~Profiles~0000.hmiprofiles │ │ │ ├── Applikatio~Variables~0000.hmivar │ │ │ ├── Applikati~Navigation~0000.hminav │ │ │ ├── CFG_1379F20~DataList~0000.dl │ │ │ ├── CFG_1379F~6aff7cb6-d~0000.ds │ │ │ ├── CFG_1379F~PlmConfigu~0000.plmc │ │ │ ├── EIP_Maste~Arp.Io.Eth~0000.libmeta │ │ │ ├── EIP_Maste~Controller~0000.compmeta │ │ │ ├── HMI_Server~DataList~0000.dlr4hmi │ │ │ ├── Hardware~Description~0000.rtf │ │ │ ├── Hardware~VersionHist~0000.usermeta │ │ │ ├── Hardware~ba87f980-c6~0000.DataLink │ │ │ ├── Hardware~ba87f980-c6~0001.Transport │ │ │ ├── Hardware~ba87f980-c6~0002.projset │ │ │ ├── IB_Master~Arp.Io.Ib.~0000.compmeta │ │ │ ├── IB_Master~Arp.Io.Ib~0000.libmeta │ │ │ ├── Logical Elemen~CRC32~0000.crc │ │ │ ├── Logical E~GeneratedD~0000.dt │ │ │ ├── NewProgram.pou~Code~0000.st │ │ │ ├── NewProgram.pou~User~0000.locres │ │ │ ├── NewProgram.~Metadata~0000.meta │ │ │ ├── NewProgram~Variables~0000.var │ │ │ ├── NewProgra~Descriptio~0000.rtf │ │ │ ├── NewProgra~Descriptio~0001.html │ │ │ ├── NewProgra~Variables.~0000.locres │ │ │ ├── NewProgra~VersionHis~0000.usermeta │ │ │ ├── PLCnext~6aff7cb6-d8e~0000.datalogger │ │ │ ├── PLCnext~EsmConfigura~0000.esmc │ │ │ ├── PN_Master~Arp.Io.Pn~0000.libmeta │ │ │ ├── PN_Master~Controller~0000.compmeta │ │ │ ├── PROJECT~PROJECT~0000.proj │ │ │ ├── RES_B9EDE5F~DataList~0000.dlr4var │ │ │ ├── RES_B9EDE~Arp.Plc.Ec~0000.libmeta │ │ │ ├── RES_B9EDE~EclrCompon~0000.compmeta │ │ │ ├── RES_B9EDE~GlobalVari~0000.var │ │ │ ├── RES_B9EDE~IOConfigur~0000.ioc │ │ │ ├── RES_B9EDE~ResourceSe~0000.set │ │ │ ├── Safety~0000.xml │ │ │ ├── Safety~0000 │ │ │ │ ├── Inventori~SafetyInve~0000.xml │ │ │ │ └── Logs~SafetyMessageLo~0000.xml │ │ │ ├── StorageContent~0000.xml │ │ │ └── StorageProperties~0000.xml │ │ │ └── structure.xml │ ├── README.md │ ├── mermaid-diagram.svg │ └── src │ │ ├── CounterComponent.cpp │ │ ├── CounterComponent.hpp │ │ ├── Helpers │ │ └── Enums.hpp │ │ └── Programs │ │ ├── DownCounterProgram.cpp │ │ ├── DownCounterProgram.hpp │ │ ├── UpCounterProgram.cpp │ │ └── UpCounterProgram.hpp ├── Subscriptions │ ├── README.MD │ ├── SubscriptionData.pcwlx │ └── src │ │ ├── Internal │ │ └── TimestampedValue.hpp │ │ ├── SubscriptionsComponent.cpp │ │ ├── SubscriptionsComponent.hpp │ │ ├── SubscriptionsComponent2.cpp │ │ ├── SubscriptionsComponent2.hpp │ │ ├── SubscriptionsComponent3.cpp │ │ ├── SubscriptionsComponent3.hpp │ │ ├── SubscriptionsComponent4.cpp │ │ └── SubscriptionsComponent4.hpp ├── ThreadExample │ ├── .gitignore │ ├── README.md │ └── src │ │ ├── ThreadExampleComponent.cpp │ │ ├── ThreadExampleComponent.hpp │ │ ├── ThreadExampleProgram.cpp │ │ └── ThreadExampleProgram.hpp └── TraceControl │ ├── README.MD │ └── src │ ├── TraceControlComponent.cpp │ └── TraceControlComponent.hpp ├── LICENSE ├── MAINTAINERS.md ├── README.md ├── SECURITY.md └── tools └── build.sh /.gitatributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.sh text eol=lf 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: feature-request 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 11 | 12 | 13 | **Is your feature request related to a problem? Please describe.** 14 | A clear and concise description of what the problem is. 15 | 16 | **Describe the solution you'd like** 17 | A clear and concise description of what you want to happen. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: The issue tracker is not for questions. Please visit [https://plcnext-community.net](https://plcnext-community.net). 4 | title: "[QUESTION]" 5 | labels: invalid 6 | assignees: '' 7 | 8 | --- 9 | 10 | 🚨 The issue tracker is not for questions 🚨 11 | 12 | If you have a question, please ask it on 13 | [https://plcnext-community.net](https://plcnext-community.net). 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | #PLCNext 35 | *.pcwlx 36 | *.pcweax 37 | 38 | build/* 39 | deploy/* 40 | .vscode 41 | -------------------------------------------------------------------------------- /.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/.gitkeep -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [OSSPLCnext@phoenixcontact.com](mailto:OSSPLCnext@phoenixcontact.com). All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | This is an open source project, and we appreciate your help! 4 | 5 | We use the GitHub issue tracker to discuss new features and bugs. 6 | 7 | In addition to the issue tracker, the PLCnext Technology [Forum](https://www.plcnext-community.net/index.php?option=com_easydiscuss&view=categories&Itemid=221&lang=en) is the best way to get into contact with the project's maintainers. 8 | 9 | To contribute code or documentation for available projects, please use an issue with an *easy-pick* label. 10 | Our [maintainers](MAINTAINERS.md) will review and implement the changes. 11 | 12 | If you are interested in contributing to the PLCnext platform organisation, please contact CommunityExamples@phoenixcontact.com. 13 | After reviewing, we will decide together, if your project will be forked from our organisation or if you get a member and transfer the repository to the organisation. -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | # Contributors 2 | 3 | This is the official list of the ##PLCnext_CppExamples## project contributors. 4 | 7 | 8 | * Phoenix Contact GmbH & Co. KG 9 | - Marcel Luhmann 10 | - Oliver Warneke 11 | - Eduard Münz 12 | - Gundula Breder 13 | - Martin Boers 14 | -------------------------------------------------------------------------------- /Examples/.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | #PLCNext 35 | *.pcwlx 36 | *.pcweax 37 | 38 | build/* 39 | 40 | -------------------------------------------------------------------------------- /Examples/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/.gitkeep -------------------------------------------------------------------------------- /Examples/BufferedExchange/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | external/ 3 | intermediate/ 4 | CmakeLists.txt 5 | plcnext.proj -------------------------------------------------------------------------------- /Examples/BufferedExchange/src/BufferedExchangeComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "BufferedExchangeComponent.hpp" 2 | #include "Arp/Plc/Commons/Esm/ProgramComponentBase.hpp" 3 | #include "BufferedExchangeLibrary.hpp" 4 | 5 | namespace BufferedExchange { 6 | 7 | BufferedExchangeComponent::BufferedExchangeComponent(IApplication &application, 8 | const String &name) : 9 | ComponentBase(application,::BufferedExchange::BufferedExchangeLibrary::GetInstance(),name, ComponentCategory::Custom), 10 | programProvider(*this), 11 | ProgramComponentBase(::BufferedExchange::BufferedExchangeLibrary::GetInstance().GetNamespace(), programProvider), 12 | // 13 | delegateThread(ThreadSettings("-DelegateThread", 0, 0, 0), Arp::make_delegate(&wD, &BufferedExchange::MyWorker::Run)) { 14 | log.Info("-------------------BufferedExchangeComponent Constructor"); 15 | } 16 | 17 | void BufferedExchangeComponent::Initialize() { 18 | // never remove next line 19 | ProgramComponentBase::Initialize(); 20 | 21 | // subscribe events from the event system (Nm) here 22 | } 23 | 24 | void BufferedExchangeComponent::LoadConfig() { 25 | // load project config here 26 | 27 | } 28 | 29 | void BufferedExchangeComponent::SetupConfig() { 30 | // never remove next line 31 | ProgramComponentBase::SetupConfig(); 32 | 33 | // setup project config here 34 | } 35 | 36 | void BufferedExchangeComponent::ResetConfig() { 37 | // never remove next line 38 | ProgramComponentBase::ResetConfig(); 39 | log.Info("---------------- ResetConfig"); 40 | 41 | // implement this inverse to SetupConfig() and LoadConfig() 42 | } 43 | 44 | void BufferedExchangeComponent::Start(void) { 45 | log.Info("---------------- Start"); 46 | try { 47 | wD.Stop = false; 48 | delegateThread.Start(); 49 | } catch (Exception &e) { 50 | log.Error("---------------- Error thread start:{0}", e.GetMessage()); 51 | } 52 | } 53 | 54 | void BufferedExchangeComponent::Stop(void) { 55 | log.Info("----------------Stop:"); 56 | try { 57 | StopT(wD, delegateThread); 58 | } catch (Exception &e) { 59 | log.Error("---------------- Error thread Stop:{0}", e.GetMessage()); 60 | } 61 | } 62 | template 63 | void BufferedExchangeComponent::StopWT(MyWorker &W, WorkerThread &T) { 64 | log.Info("---------------- Thread:{0} Running:{1} ", "Worker", 65 | T.IsRunning()); 66 | W.Stop = true; 67 | // Stopping WorkerThread synchronously. 68 | T.Stop(); 69 | } 70 | template 71 | void BufferedExchangeComponent::StopT(MyWorker &W, Thread &T) { 72 | log.Info("---------------- Thread:{0} Running:{1} Joinable:{2}", 73 | T.GetName(), T.IsRunning(), T.IsJoinable()); 74 | 75 | // Stopping thread loops 76 | W.Stop = true; 77 | 78 | // If thread is still running after setting "Stop" call interrupt 79 | // to ensure thread shutdown. 80 | if (T.IsRunning()){ 81 | T.Interrupt(); 82 | } 83 | 84 | // Wait for the thread to finish. 85 | if (T.IsJoinable()) { 86 | T.Join(); 87 | } 88 | } 89 | } // end of namespace BufferedExchange 90 | -------------------------------------------------------------------------------- /Examples/BufferedExchange/src/BufferedExchangeComponent.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Arp/System/Core/Arp.h" 3 | #include "Arp/System/Acf/ComponentBase.hpp" 4 | #include "Arp/System/Acf/IApplication.hpp" 5 | #include "Arp/Plc/Commons/Esm/ProgramComponentBase.hpp" 6 | #include "Arp/Plc/Commons/Meta/MetaLibraryBase.hpp" 7 | #include "Arp/System/Commons/Logging.h" 8 | #include "BufferedExchangeComponentProgramProvider.hpp" 9 | 10 | #include "Arp/System/Acf/IControllerComponent.hpp" 11 | 12 | #include "Arp/System/Commons/Threading/WorkerThread.hpp" 13 | #include "Arp/System/Commons/Threading/Thread.hpp" 14 | 15 | #include "MyWorker.hpp" 16 | 17 | namespace BufferedExchange { 18 | 19 | using namespace Arp; 20 | using namespace Arp::System::Acf; 21 | using namespace Arp::Plc::Commons::Esm; 22 | using namespace Arp::Plc::Commons::Meta; 23 | using namespace Arp::System::Commons::Threading; 24 | 25 | //#component 26 | class BufferedExchangeComponent: public ComponentBase, 27 | public ProgramComponentBase, 28 | public IControllerComponent, 29 | private Loggable { 30 | public: // typedefs 31 | 32 | public: // construction/destruction 33 | BufferedExchangeComponent(IApplication &application, const String &name); 34 | virtual ~BufferedExchangeComponent() = default; 35 | 36 | public: // Component operations 37 | void Initialize() override; 38 | void LoadConfig() override; 39 | void SetupConfig() override; 40 | void ResetConfig() override; 41 | 42 | public: // IControllerComponent 43 | void Start(); 44 | void Stop(); 45 | 46 | public: // ProgramComponentBase operations 47 | void RegisterComponentPorts() override; 48 | 49 | private: // methods 50 | BufferedExchangeComponent(const BufferedExchangeComponent &arg) = delete; 51 | BufferedExchangeComponent& operator=(const BufferedExchangeComponent &arg) = delete; 52 | 53 | public: // static factory operations 54 | static IComponent::Ptr Create(Arp::System::Acf::IApplication &application, 55 | const String &name); 56 | 57 | private: // fields 58 | BufferedExchangeComponentProgramProvider programProvider; 59 | 60 | public: 61 | MyWorker wD; // Thread execution environment 62 | int RunCounter { 0 }; 63 | Thread delegateThread; 64 | 65 | 66 | public: 67 | template 68 | void StopWT(MyWorker &W, WorkerThread &T); 69 | 70 | template 71 | void StopT(MyWorker &W, Thread &T); 72 | }; 73 | 74 | inline IComponent::Ptr BufferedExchangeComponent::Create(Arp::System::Acf::IApplication &application, const String &name) { 75 | return IComponent::Ptr(new BufferedExchangeComponent(application, name)); 76 | } 77 | 78 | } // end of namespace BufferedExchange 79 | -------------------------------------------------------------------------------- /Examples/BufferedExchange/src/BufferedExchangeProgram.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Arp/System/Commons/Logging.h" 3 | #include "Arp/System/Core/ByteConverter.hpp" 4 | 5 | namespace BufferedExchange 6 | { 7 | 8 | void BufferedExchangeProgram::Execute() 9 | { 10 | //implement program 11 | if (count % 1000 == 0) 12 | { 13 | log.Info("---------------- Execute: {0} ", count); 14 | } 15 | count++; 16 | 17 | //Watch out this is blocking! 18 | if(!error_LastCycle || retry ) 19 | { 20 | if (!bufferedExchangeComponent.wD.SetData( count)) 21 | { 22 | // ensure the log does not get flooded. 23 | if(!error_LastCycle){ 24 | log.Warning("-------------- Instance:{1} DataLost: {0} ", count, this->GetFullName()); 25 | error_LastCycle = true; 26 | } 27 | }else{ 28 | error_LastCycle = false; 29 | } 30 | } 31 | } 32 | 33 | } // end of namespace BufferedExchange 34 | -------------------------------------------------------------------------------- /Examples/BufferedExchange/src/BufferedExchangeProgram.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Arp/System/Core/Arp.h" 4 | #include "Arp/Plc/Commons/Esm/ProgramBase.hpp" 5 | #include "Arp/System/Commons/Logging.h" 6 | 7 | namespace BufferedExchange { 8 | 9 | using namespace Arp; 10 | using namespace Arp::System::Commons::Diagnostics::Logging; 11 | using namespace Arp::Plc::Commons::Esm; 12 | 13 | //#program 14 | //#component(BufferedExchange::BufferedExchangeComponent) 15 | class BufferedExchangeProgram: public ProgramBase, private Loggable { 16 | public: // typedefs 17 | 18 | public: // construction/destruction 19 | BufferedExchangeProgram( 20 | BufferedExchange::BufferedExchangeComponent &bufferedExchangeComponentArg, 21 | const String &name); 22 | BufferedExchangeProgram(const BufferedExchangeProgram &arg) = delete; 23 | virtual ~BufferedExchangeProgram() = default; 24 | 25 | public: // operators 26 | BufferedExchangeProgram& operator=(const BufferedExchangeProgram &arg) = delete; 27 | 28 | public: // properties 29 | 30 | public: // operations 31 | void Execute() override; 32 | 33 | private: // fields 34 | BufferedExchange::BufferedExchangeComponent &bufferedExchangeComponent; 35 | long int count { 0 }; 36 | bool error_LastCycle { false }; 37 | public: 38 | //#port 39 | //#attributes(Input) 40 | //#name(retry_sending) 41 | boolean retry{false}; 42 | }; 43 | 44 | /////////////////////////////////////////////////////////////////////////////// 45 | // inline methods of class ProgramBase 46 | inline BufferedExchangeProgram::BufferedExchangeProgram( 47 | BufferedExchange::BufferedExchangeComponent &bufferedExchangeComponentArg, 48 | const String &name) : 49 | ProgramBase(name), 50 | bufferedExchangeComponent(bufferedExchangeComponentArg) { 51 | } 52 | 53 | } // end of namespace BufferedExchange 54 | -------------------------------------------------------------------------------- /Examples/ComponentPorts/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | project(ComponentPorts) 4 | 5 | if(NOT CMAKE_BUILD_TYPE) 6 | set(CMAKE_BUILD_TYPE Release) 7 | endif() 8 | 9 | ################# create target ####################################################### 10 | 11 | file(GLOB_RECURSE Headers CONFIGURE_DEPENDS src/*.h src/*.hpp src/*.hxx intermediate/code/*.h intermediate/code/*.hpp intermediate/code/*.hxx) 12 | file(GLOB_RECURSE Sources CONFIGURE_DEPENDS src/*.cpp intermediate/code/*.cpp) 13 | add_library(ComponentPorts SHARED ${Headers} ${Sources}) 14 | 15 | ####################################################################################### 16 | 17 | ################# project include-paths ############################################### 18 | 19 | target_include_directories(ComponentPorts 20 | PUBLIC 21 | $ 22 | $) 23 | 24 | ####################################################################################### 25 | 26 | ################# include arp cmake module path ####################################### 27 | 28 | list(INSERT CMAKE_MODULE_PATH 0 "${ARP_TOOLCHAIN_CMAKE_MODULE_PATH}") 29 | 30 | ####################################################################################### 31 | 32 | ################# set RPATH to ORIGIN for third party libraries ####################### 33 | # Only by setting this is it possible to use libraries which are not already # 34 | # installed in the default install locations on the target. # 35 | ####################################################################################### 36 | 37 | if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows" AND NOT "$ENV{SHELL}" MATCHES ".*[\/\\]bash($|.exe$)") 38 | # With Windows there is a known issue with CMake: https://gitlab.kitware.com/cmake/cmake/-/issues/21291 39 | # This is currently the only way to set the RPATH to $ORIGIN in Windows 40 | target_link_libraries(ComponentPorts PRIVATE "-Wl,-rpath,\$$ORIGIN") 41 | else() 42 | set_target_properties(ComponentPorts PROPERTIES INSTALL_RPATH $ORIGIN) 43 | endif() 44 | 45 | ####################################################################################### 46 | 47 | ################# set link options #################################################### 48 | # WARNING: Without --no-undefined the linker will not check, whether all necessary # 49 | # libraries are linked. When a library which is necessary is not linked, # 50 | # the firmware will crash and there will be NO indication why it crashed. # 51 | ####################################################################################### 52 | 53 | target_link_options(ComponentPorts PRIVATE LINKER:--no-undefined) 54 | 55 | ####################################################################################### 56 | 57 | ################# add link targets #################################################### 58 | 59 | find_package(ArpDevice REQUIRED) 60 | find_package(ArpProgramming REQUIRED) 61 | 62 | target_link_libraries(ComponentPorts PRIVATE ArpDevice ArpProgramming) 63 | 64 | ####################################################################################### 65 | 66 | ################# install ############################################################ 67 | 68 | string(REGEX REPLACE "^.*\\(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*$" "\\1" _ARP_SHORT_DEVICE_VERSION ${ARP_DEVICE_VERSION}) 69 | install(TARGETS ComponentPorts 70 | LIBRARY DESTINATION ${ARP_DEVICE}_${_ARP_SHORT_DEVICE_VERSION}/$/lib 71 | ARCHIVE DESTINATION ${ARP_DEVICE}_${_ARP_SHORT_DEVICE_VERSION}/$/lib 72 | RUNTIME DESTINATION ${ARP_DEVICE}_${_ARP_SHORT_DEVICE_VERSION}/$/bin) 73 | unset(_ARP_SHORT_DEVICE_VERSION) 74 | 75 | ####################################################################################### -------------------------------------------------------------------------------- /Examples/ComponentPorts/README.md: -------------------------------------------------------------------------------- 1 | # Component Ports 2 | 3 | ## Table of contents 4 | 5 | 6 | 7 | - [Introduction](#Introduction) 8 | - [Background](#Background) 9 | - [Details](#Details) 10 | 11 | 12 | 13 | ## Introduction 14 | 15 | In PLM projects it is possible to implement Inports and Outports for programs. Additionally member variables of the component can be declared as ports. This declaration is basically explained in the components header file created by PLCnCLI. Since the life-time of a component differs from the programs life-time, **some additional implementation is necessary if the component ports shall be initialized similar to program ports regarding to the Cold/Warm Start behavior of the PLC application!** This example demonstrates the necessary implementation. 16 | 17 | ## Background 18 | 19 | The PLCnext firmware creates program instances according to the ESM configuration when the PLC program is loaded. Program instances are deleted when the PLC application is unloaded. This holds true for component instances as well. Additionally (and in contrast to component instances) program instances are also deleted and created again when the PLC application is started (Cold as well as Warm Start). During this creation all member variables of the program are initialized by the C++ code. If the PLC is started by a warm start, program ports which are marked with the `Retain` attribute are restored to their last saved value. This is handled for program instances by the firmware but for component instances dedicated C++ code has to be provided within the component. 20 | 21 | This dedicated C++ code consists basically of one method added to the component. This method has to be registered at the firmware to be called when the PLC application is started. The input parameter of this method then indicates the start kind (warm/cold) of the PLC application. 22 | 23 | ## Details 24 | 25 | **Precondition:** The header files `Arp/Plc/Commons/Domain/PlcStartKind.hpp` and `Arp/Plc/Commons/Domain/PlcDomainProxy.hpp` need to be included as well as the namespace `Arp::Plc::Commons::Domain` needs to be used. 26 | 27 | The `ComponentWithPort` in this example declares the ports `retainPort1` and `nonretainPort1` and the first port is marked with the `Retain` attribute. Furthermore the method **`OnPlcStarting(PlcStartKind)`** is defined. The component registers this method to the firmware `PlcDomainProxy` within its `Initialize()` method. It is important to unregister this method when the components life-time ends. This is done within the `Dispose()` method. Please note that this method may not be declared automatically when PLCnCLI creates a new component. 28 | 29 | Within the `OnPlcStarting(PlcStartKind)` method the input `startkind` is checked: 30 | 31 | - The value `Warm` indicates a Warm Start of the PLC application. Such Warm Start can be performed using PLCnext Engineer or after the PLC has booted. 32 | - The value `RestoreWarm` indicates a Warm Start of the PLC application in the context of the PLCnext Engineer function "Restore last saved retain data". 33 | - The value `Cold` indicates a Cold Start of the PLC application which can be performed using PLCnext Engineer. 34 | - The value `Hot` indicates a Hot Start of the PLC application which can be performed using PLCnext Engineer. In this case all ports are expected to keep their values, so no action is required. 35 | 36 | Note: The program in this example is created by PLCnCLI and has not been changed. In PLCnext Engineer this program needs to be instantiated in order to create an instance of `ComponentWithPorts`. 37 | -------------------------------------------------------------------------------- /Examples/ComponentPorts/external/ADD_DEPENDENT_LIBRARIES_HERE.txt: -------------------------------------------------------------------------------- 1 | The CLI will automatically set the CMAKE_PREFIX_PATH to find CMake packages to 2 | this directory or a sub-directory of this directory. To decide which directory 3 | to use for the CMAKE_PREFIX_PATH the CLI looks for a directory with the name 4 | _. 5 | 6 | To choose such a directory the target_name must match the current build target 7 | name and the version must be lower or equal to the current build target 8 | version. If such a directory is found the CLI looks whether the directory 9 | contains the current build type (Release, Debug, ...). If no such directory is 10 | found it looks for a directory named "Release". 11 | 12 | If the CLI finds the build type directory or the "Release" directory it uses 13 | this directory as CMAKE_PREFIX_PATH. If not it uses as fallback the found 14 | target specific directory. If that is not found it uses the external directory. 15 | If the CMAKE_PREFIX_PATH is already set by a command line option it will not 16 | override the set value. 17 | 18 | Please make sure that if the libraries which are used by this project use other 19 | libraries themself, that the library must have the RPATH set to $ORIGIN. -------------------------------------------------------------------------------- /Examples/ComponentPorts/src/ComponentWithPorts.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Copyright (c) 2021 Phoenix Contact GmbH & Co. KG. All rights reserved. 4 | * Licensed under the MIT. See LICENSE file in the project root for full license information. 5 | * 6 | ******************************************************************************/ 7 | 8 | #include "ComponentWithPorts.hpp" 9 | #include "Arp/Plc/Commons/Esm/ProgramComponentBase.hpp" 10 | #include "ComponentPortsLibrary.hpp" 11 | 12 | namespace ComponentPorts 13 | { 14 | 15 | ComponentWithPorts::ComponentWithPorts(IApplication& application, const String& name) 16 | : ComponentBase(application, ::ComponentPorts::ComponentPortsLibrary::GetInstance(), name, ComponentCategory::Custom) 17 | , programProvider(*this) 18 | , ProgramComponentBase(::ComponentPorts::ComponentPortsLibrary::GetInstance().GetNamespace(), programProvider) 19 | { 20 | } 21 | 22 | void ComponentWithPorts::Initialize() 23 | { 24 | // never remove next line 25 | ProgramComponentBase::Initialize(); 26 | 27 | // subscribe events from the event system (Nm) here 28 | 29 | PlcDomainProxy& plcDomainProxy = PlcDomainProxy::GetInstance(); 30 | 31 | // register all Plc event handler 32 | plcDomainProxy.PlcStarting += make_delegate(this, &ComponentWithPorts::OnPlcStarting); 33 | // Do not forget to unregister these handlers, e.g. in the dispose() method! 34 | } 35 | 36 | void ComponentWithPorts::LoadConfig() 37 | { 38 | // load project config here 39 | } 40 | 41 | void ComponentWithPorts::SetupConfig() 42 | { 43 | // never remove next line 44 | ProgramComponentBase::SetupConfig(); 45 | 46 | // setup project config here 47 | } 48 | 49 | void ComponentWithPorts::ResetConfig() 50 | { 51 | // never remove next line 52 | ProgramComponentBase::ResetConfig(); 53 | 54 | // implement this inverse to SetupConfig() and LoadConfig() 55 | } 56 | 57 | void ComponentWithPorts::Dispose() 58 | { 59 | PlcDomainProxy& plcDomainProxy = PlcDomainProxy::GetInstance(); 60 | 61 | // unregister all Plc event handler 62 | plcDomainProxy.PlcStarting -= make_delegate(this, &ComponentWithPorts::OnPlcStarting); 63 | 64 | // never remove next line 65 | ComponentBase::Dispose(); 66 | } 67 | 68 | void ComponentWithPorts::PowerDown() 69 | { 70 | // implement this only if data must be retained even on power down event 71 | // Available with 2021.6 FW 72 | } 73 | 74 | void ComponentWithPorts::OnPlcStarting(PlcStartKind startKind) 75 | { 76 | // this event handler is called before starting the PLC 77 | log.Info("'{0}({1})' invoked of object with instance name '{2}' from thread '{3}'", __FUNCTION__, startKind, this->GetFullName(), pthread_self()); 78 | 79 | if (PlcStartKind::Warm == startKind || 80 | PlcStartKind::RestoreWarm == startKind || 81 | PlcStartKind::Cold == startKind) 82 | { 83 | // initialize non-retain ports anyhow (in all 3 cases) 84 | // if necessary, further member variables can be initialized, too 85 | ports.nonretainPort1 = 1; 86 | 87 | if (PlcStartKind::Cold == startKind) 88 | { // initialize retain ports, too 89 | ports.retainPort1 = 1; 90 | } 91 | } 92 | // no special action required in case of PlcStartKind::Hot 93 | } 94 | 95 | } // end of namespace ComponentPorts 96 | -------------------------------------------------------------------------------- /Examples/ComponentPorts/src/ComponentWithPorts.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Copyright (c) 2021 Phoenix Contact GmbH & Co. KG. All rights reserved. 4 | * Licensed under the MIT. See LICENSE file in the project root for full license information. 5 | * 6 | ******************************************************************************/ 7 | #pragma once 8 | #include "Arp/System/Core/Arp.h" 9 | #include "Arp/System/Acf/ComponentBase.hpp" 10 | #include "Arp/System/Acf/IApplication.hpp" 11 | #include "Arp/Plc/Commons/Esm/ProgramComponentBase.hpp" 12 | #include "ComponentWithPortsProgramProvider.hpp" 13 | #include "Arp/Plc/Commons/Meta/MetaLibraryBase.hpp" 14 | #include "Arp/System/Commons/Logging.h" 15 | 16 | // added to the template 17 | #include "Arp/Plc/Commons/Domain/PlcStartKind.hpp" 18 | #include "Arp/Plc/Commons/Domain/PlcDomainProxy.hpp" 19 | 20 | namespace ComponentPorts 21 | { 22 | 23 | using namespace Arp; 24 | using namespace Arp::System::Acf; 25 | using namespace Arp::Plc::Commons::Esm; 26 | using namespace Arp::Plc::Commons::Meta; 27 | 28 | // "using" added to the template 29 | using namespace Arp::Plc::Commons::Domain; 30 | 31 | //#component 32 | class ComponentWithPorts : public ComponentBase, public ProgramComponentBase, private Loggable 33 | { 34 | public: // typedefs 35 | 36 | public: // construction/destruction 37 | ComponentWithPorts(IApplication& application, const String& name); 38 | virtual ~ComponentWithPorts() = default; 39 | 40 | public: // IComponent operations 41 | void Initialize() override; 42 | void LoadConfig() override; 43 | void SetupConfig() override; 44 | void ResetConfig() override; 45 | // "Dispose()" added to the template 46 | void Dispose() override; 47 | void PowerDown() override; 48 | 49 | public: // ProgramComponentBase operations 50 | void RegisterComponentPorts() override; 51 | 52 | // "Handler methods" added to the template 53 | private: // Plc event handler methods 54 | void OnPlcStarting(PlcStartKind startKind); 55 | 56 | private: // methods 57 | ComponentWithPorts(const ComponentWithPorts& arg) = delete; 58 | ComponentWithPorts& operator= (const ComponentWithPorts& arg) = delete; 59 | 60 | public: // static factory operations 61 | static IComponent::Ptr Create(Arp::System::Acf::IApplication& application, const String& name); 62 | 63 | private: // fields 64 | ComponentWithPortsProgramProvider programProvider; 65 | 66 | public: /* Ports 67 | ===== 68 | Component ports are defined in the following way: 69 | */ 70 | //#attributes(Hidden) 71 | struct Ports 72 | { 73 | //#name(retainPort) 74 | //#attributes(Output|Retain|Opc) 75 | int16 retainPort1 = 1; 76 | // The GDS name is "/NameOfPort" if the struct is declared as Hidden 77 | // otherwise the GDS name is "/PORTS.NameOfPort" 78 | //#attributes(Output|Opc) 79 | int16 nonretainPort1 = 1; 80 | }; 81 | 82 | //#port 83 | Ports ports; 84 | /* 85 | Create one (and only one) instance of this struct. 86 | Apart from this single struct instance, it is recommended, that there should be no other Component variables 87 | declared with the #port comment. 88 | The only attribute that is allowed on the struct instance is "Hidden", and this is optional. The attribute 89 | will hide the structure field and simulate that the struct fields are direct ports of the component. In the 90 | above example that would mean the component has only one port with the name "NameOfPort". 91 | When there are two struts with the attribute "Hidden" and both structs have a field with the same name, there 92 | will be an exception in the firmware. That is why only one struct is recommended. If multiple structs need to 93 | be used the "Hidden" attribute should be omitted. 94 | The struct can contain as many members as necessary. 95 | The #name comment can be applied to each member of the struct, and is optional. 96 | The #name comment defines the GDS name of an individual port element. If omitted, the member variable name is used as the GDS name. 97 | The members of the struct can be declared with any of the attributes allowed for a Program port. 98 | */ 99 | }; 100 | 101 | inline IComponent::Ptr ComponentWithPorts::Create(Arp::System::Acf::IApplication& application, const String& name) 102 | { 103 | return IComponent::Ptr(new ComponentWithPorts(application, name)); 104 | } 105 | 106 | } // end of namespace ComponentPorts 107 | -------------------------------------------------------------------------------- /Examples/ComponentPorts/src/MyProgram.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Copyright (c) 2021 Phoenix Contact GmbH & Co. KG. All rights reserved. 4 | * Licensed under the MIT. See LICENSE file in the project root for full license information. 5 | * 6 | ******************************************************************************/ 7 | #include "MyProgram.hpp" 8 | #include "Arp/System/Commons/Logging.h" 9 | #include "Arp/System/Core/ByteConverter.hpp" 10 | 11 | namespace ComponentPorts 12 | { 13 | 14 | void MyProgram::Execute() 15 | { 16 | //implement program 17 | } 18 | 19 | } // end of namespace ComponentPorts 20 | -------------------------------------------------------------------------------- /Examples/ComponentPorts/src/MyProgram.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Copyright (c) 2021 Phoenix Contact GmbH & Co. KG. All rights reserved. 4 | * Licensed under the MIT. See LICENSE file in the project root for full license information. 5 | * 6 | ******************************************************************************/ 7 | 8 | #pragma once 9 | #include "Arp/System/Core/Arp.h" 10 | #include "Arp/Plc/Commons/Esm/ProgramBase.hpp" 11 | #include "Arp/System/Commons/Logging.h" 12 | #include "ComponentWithPorts.hpp" 13 | 14 | namespace ComponentPorts 15 | { 16 | 17 | using namespace Arp; 18 | using namespace Arp::System::Commons::Diagnostics::Logging; 19 | using namespace Arp::Plc::Commons::Esm; 20 | 21 | //#program 22 | //#component(ComponentPorts::ComponentWithPorts) 23 | class MyProgram : public ProgramBase, private Loggable 24 | { 25 | public: // typedefs 26 | 27 | public: // construction/destruction 28 | MyProgram(ComponentPorts::ComponentWithPorts& componentWithPortsArg, const String& name); 29 | MyProgram(const MyProgram& arg) = delete; 30 | virtual ~MyProgram() = default; 31 | 32 | public: // operators 33 | MyProgram& operator=(const MyProgram& arg) = delete; 34 | 35 | public: // properties 36 | 37 | public: // operations 38 | void Execute() override; 39 | 40 | public: /* Ports 41 | ===== 42 | Ports are defined in the following way: 43 | //#port 44 | //#attributes(Input|Retain) 45 | //#name(NameOfPort) 46 | boolean portField; 47 | 48 | The attributes comment define the port attributes and is optional. 49 | The name comment defines the name of the port and is optional. Default is the name of the field. 50 | */ 51 | 52 | private: // fields 53 | ComponentPorts::ComponentWithPorts& componentWithPorts; 54 | 55 | }; 56 | 57 | /////////////////////////////////////////////////////////////////////////////// 58 | // inline methods of class ProgramBase 59 | inline MyProgram::MyProgram(ComponentPorts::ComponentWithPorts& componentWithPortsArg, const String& name) 60 | : ProgramBase(name) 61 | , componentWithPorts(componentWithPortsArg) 62 | { 63 | } 64 | 65 | } // end of namespace ComponentPorts 66 | -------------------------------------------------------------------------------- /Examples/CppDataTypeTest/README.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | 4 | 5 | 1. [Introduction](#introduction) 6 | 2. [Example details](#example-details) 7 | 3. [Preconditions](#preconditions) 8 | 4. [Project compiling in Eclipse](#project-compiling-in-eclipse) 9 | 5. [PLCnext Engineer project](#plcnext-engineer-project) 10 | 6. [Start-Up instructions](#start-up-instructions) 11 | 12 | 13 | 14 | ## Introduction 15 | 16 | This example demonstrates the creation and usage of port variables in PLCnext Engineer and C++ applications for data exchange via elementary data types. 17 | All supported elementary data types are documented in the [PLCnext Info Center](https://www.plcnext.help/te/PLCnext_Runtime/Available_data_types.htm). 18 | 19 | ## Example details 20 | 21 | |Description | Value | 22 | |------------ |-----------| 23 | |Controller| AXC F 2152 | 24 | |FW | 2021.9 | 25 | |SDK | 2021.9 | 26 | |PLCnext CLI| 2021.6 | 27 | |PLCnext Engineer| 2021.9 | 28 | 29 | ## Preconditions 30 | 31 | - PLCnext Control AXC F 2152 with firmware 2021.6 or later 32 | - PLCnext Engineer 2021.6 or later 33 | - Eclipse® IDE "Photon" or later 34 | 35 | ## Project compiling in Eclipse 36 | 37 | 1. In Eclipse create a project "CppDataTypeTest" with component "CppDataTypeTestComponent" and program "CppDataTypeTestProgram". 38 | 1. In the project replace the files "CppDataTypeTestProgram.cpp" and "CppDataTypeTestProgram.hpp" with files from this repository. Alternatively you can create your own project with component and programs and include the source code of "CppDataTypeTestProgram.cpp" and "CppDataTypeTestProgram.hpp" in your source code files. 39 | 1. Compile the Eclipse project. 40 | 1. After successful project compilation, the PLCnext Engineer .pcwlx library will be created automatically. You can find it in the Eclipse workspace folder; e.g.: "workspace\CppDataTypeTest\bin\CppDataTypeTest.pcwlx". 41 | 42 | ## PLCnext Engineer project 43 | 44 | 1. In PLCnext Engineer create a new project and add the user library "CppDataTypeTest.pcwlx" to the project. 45 | 1. Instantiate the program "CppDataTypeTestProgram" under a previously defined task. 46 | 1. In the "COMPONENT" area under "Programming" -> "Datatypes" create an new datatype worksheet and include the following user-defined datatypes: 47 | 48 | ```text 49 | TYPE 50 | STRING420:STRING[420]; 51 | WSTRING420:WSTRING[420]; 52 | 53 | bool_array: ARRAY[0..9] OF BOOL; 54 | //8Bit 55 | sint_array: ARRAY[0..9] OF SINT; 56 | usint_array: ARRAY[0..9] OF USINT; 57 | //16Bit 58 | int_array: ARRAY[0..9] OF INT; 59 | uint_array: ARRAY[0..9] OF UINT; 60 | //32Bit 61 | dint_array: ARRAY[0..9] OF DINT; 62 | udint_array: ARRAY[0..9] OF UDINT; 63 | //64Bit 64 | lint_array: ARRAY[0..9] OF LINT; 65 | ulint_array: ARRAY[0..9] OF ULINT; 66 | //8Bit 67 | byte_array: ARRAY[0..9] OF BYTE; 68 | //16Bit 69 | word_array: ARRAY[0..9] OF WORD; 70 | //32Bit 71 | doubleword_array: ARRAY[0..9] OF DWORD; 72 | //64Bit 73 | Lword_array: ARRAY[0..9] OF LWORD; 74 | //xx digit precision 75 | real_array: ARRAY[0..9] OF REAL; 76 | //xx digit precision 77 | Lreal_array: ARRAY[0..9] OF LREAL; 78 | //Strings 79 | String_array: ARRAY[0..9] OF STRING; 80 | Wide_string_array: ARRAY[0..9] OF WSTRING; 81 | END_TYPE 82 | ``` 83 | 84 | 1. Declare one IN port variable for each of the user-defined and elementary datatypes in a program, e.g. "Main". Find a table of elementary datatypes in the [PLCnext Info Center](https://www.plcnext.help/te/PLCnext_Runtime/Available_data_types.htm). 85 | 1. Connect the C++ port variables and IEC 61131 port variables under the "PLCnext" node in the "PLANT" area of PLCnext Engineer. 86 | 1. Download the PLCnext Engineer project to the PLCnext Control. 87 | 88 | ## Start-up instructions 89 | 90 | - If the project is successfully implemented and downloaded, you can follow the data exchange in PLCnext Engineer running in debug mode and/or in the watch window of PLCnext Engineer. 91 | - If the project did not start successfully, please see the error messages in Output.log file on the PLCnext target: /opt/plcnext/logs/Output.log 92 | -------------------------------------------------------------------------------- /Examples/CppDataTypeTest/src/CppDataTypeTestComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "CppDataTypeTestComponent.hpp" 2 | #include "Arp/Plc/Commons/Esm/ProgramComponentBase.hpp" 3 | #include "CppDataTypeTestLibrary.hpp" 4 | namespace CppDataTypeTest 5 | { 6 | 7 | CppDataTypeTestComponent::CppDataTypeTestComponent(IApplication& application, const String& name) 8 | : ComponentBase(application, ::CppDataTypeTest::CppDataTypeTestLibrary::GetInstance(), name, ComponentCategory::Custom) 9 | , programProvider(*this) 10 | , ProgramComponentBase(::CppDataTypeTest::CppDataTypeTestLibrary::GetInstance().GetNamespace(), programProvider) 11 | { 12 | } 13 | void CppDataTypeTestComponent::Initialize() 14 | { 15 | // never remove next line 16 | ProgramComponentBase::Initialize(); 17 | 18 | // subscribe events from the event system (Nm) here 19 | } 20 | 21 | void CppDataTypeTestComponent::LoadConfig() 22 | { 23 | // load project config here 24 | } 25 | 26 | void CppDataTypeTestComponent::SetupConfig() 27 | { 28 | // never remove next line 29 | ProgramComponentBase::SetupConfig(); 30 | 31 | // setup project config here 32 | } 33 | 34 | void CppDataTypeTestComponent::ResetConfig() 35 | { 36 | // never remove next line 37 | ProgramComponentBase::ResetConfig(); 38 | 39 | // implement this inverse to SetupConfig() and LoadConfig() 40 | } 41 | 42 | } // end of namespace CppDataTypeTest 43 | -------------------------------------------------------------------------------- /Examples/CppDataTypeTest/src/CppDataTypeTestComponent.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Arp/System/Core/Arp.h" 3 | #include "Arp/System/Acf/ComponentBase.hpp" 4 | #include "Arp/System/Acf/IApplication.hpp" 5 | #include "Arp/Plc/Commons/Esm/ProgramComponentBase.hpp" 6 | #include "CppDataTypeTestComponentProgramProvider.hpp" 7 | #include "Arp/Plc/Commons/Meta/MetaLibraryBase.hpp" 8 | #include "Arp/System/Commons/Logging.h" 9 | 10 | namespace CppDataTypeTest 11 | { 12 | 13 | using namespace Arp; 14 | using namespace Arp::System::Acf; 15 | using namespace Arp::Plc::Commons::Esm; 16 | using namespace Arp::Plc::Commons::Meta; 17 | 18 | //#component 19 | class CppDataTypeTestComponent : public ComponentBase, public ProgramComponentBase, private Loggable 20 | { 21 | public: // typedefs 22 | 23 | public: // construction/destruction 24 | CppDataTypeTestComponent(IApplication& application, const String& name); 25 | virtual ~CppDataTypeTestComponent() = default; 26 | 27 | public: // IComponent operations 28 | void Initialize() override; 29 | void LoadConfig() override; 30 | void SetupConfig() override; 31 | void ResetConfig() override; 32 | 33 | public: // ProgramComponentBase operations 34 | void RegisterComponentPorts() override; 35 | 36 | private: // methods 37 | CppDataTypeTestComponent(const CppDataTypeTestComponent& arg) = delete; 38 | CppDataTypeTestComponent& operator= (const CppDataTypeTestComponent& arg) = delete; 39 | 40 | public: // static factory operations 41 | static IComponent::Ptr Create(Arp::System::Acf::IApplication& application, const String& name); 42 | 43 | private: // fields 44 | CppDataTypeTestComponentProgramProvider programProvider; 45 | 46 | public: /* Ports 47 | ===== 48 | Component ports are defined in the following way: 49 | //#port 50 | //#name(NameOfPort) 51 | boolean portField; 52 | 53 | The name comment defines the name of the port and is optional. Default is the name of the field. 54 | Attributes which are defined for a component port are IGNORED. If component ports with attributes 55 | are necessary, define a single structure port where attributes can be defined foreach field of the 56 | structure. 57 | */ 58 | }; 59 | 60 | /////////////////////////////////////////////////////////////////////////////// 61 | // inline methods of class CppDataTypeTestComponent 62 | 63 | inline IComponent::Ptr CppDataTypeTestComponent::Create(Arp::System::Acf::IApplication& application, const String& name) 64 | { 65 | return IComponent::Ptr(new CppDataTypeTestComponent(application, name)); 66 | } 67 | 68 | } // end of namespace CppDataTypeTest 69 | -------------------------------------------------------------------------------- /Examples/CppDataTypeTest/src/CppDataTypeTestProgram.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Copyright (c) Phoenix Contact GmbH & Co. KG. All rights reserved. 4 | * Licensed under the MIT. See LICENSE file in the project root for full license information. 5 | * 6 | * CppDataTypeTestProgram.cpp 7 | * 8 | * Created on: 21.02.2019 9 | * Author: Eduard Münz, Oliver Warneke, Martin Boers 10 | * 11 | ******************************************************************************/ 12 | 13 | /******************************************************************************/ 14 | /* INCLUDES */ 15 | /******************************************************************************/ 16 | 17 | #include "CppDataTypeTestProgram.hpp" 18 | #include "Arp/System/Commons/Logging.h" 19 | #include "Arp/System/Core/ByteConverter.hpp" 20 | 21 | namespace CppDataTypeTest 22 | { 23 | 24 | void CppDataTypeTestProgram::Execute() 25 | { 26 | //implement program 27 | 28 | if(outBoolean == true) 29 | outBoolean = false; 30 | else 31 | outBoolean = true; 32 | 33 | outInt8++; //SINT 34 | outUint8++; //USINT 35 | outStruct.outInt8++; //StructElement 36 | outStruct.outUint8++; //StructElement 37 | 38 | outInt16++; //INT 39 | outUint16++;//UINT 40 | outStruct.outInt16++; //StructElement 41 | outStruct.outUint16++; //StructElement 42 | 43 | outInt32++; //DINT 44 | outUint32++;//UDINT 45 | outStruct.outInt32++; //StructElement 46 | outStruct.outUint32++; //StructElement 47 | 48 | outInt64++; //LINT 49 | outUint64++;//ULINT 50 | outStruct.outInt64++; //StructElement 51 | outStruct.outUint64++; //StructElement 52 | 53 | outFloat32++;//REAL 54 | outFloat64++;//LREAL 55 | outStruct.outFloat32++; //StructElement 56 | outStruct.outFloat64++; //StructElement 57 | 58 | outByte++; //Byte 59 | outWord++; //Word 60 | outDword++; //DWORD 61 | outLword++; //Lword 62 | outStruct.outByte++; //StructElement 63 | outStruct.outWord++; //StructElement 64 | outStruct.outDword++; //StructElement 65 | outStruct.outLword++; //StructElement 66 | 67 | outString = "This is a standard IEC 61131 string (max. 80 char)."; 68 | outString420 = "This is a custom length string - in this case, with a maximum of 420 chars, but can be up to 32766 chars."; 69 | outStruct.outString = "This is a standard IEC 61131 string (max. 80 char)."; //StructElement 70 | 71 | outWString = "This is a standard IEC 61131 wide string (max. 80 char)."; 72 | outWString420 = "This is a custom length wide string - in this case, with a maximum of 420 chars, but can be up to 32766 chars."; 73 | outStruct.outWString = "This is a standard IEC 61131 wide string (max. 80 char)."; //StructElement 74 | 75 | for(int i=0; i < 10;i++) 76 | { 77 | if(outarrayBoolean[i] == true) 78 | outarrayBoolean[i] = false; 79 | else 80 | outarrayBoolean[i] = true; 81 | 82 | outarrayInt8[i]++; //SINT 83 | outarrayUint8[i]++; //USINT 84 | 85 | outarrayInt16[i]++; //INT 86 | outarrayUint16[i]++; //UINT 87 | 88 | outarrayInt32[i]++; //DINT 89 | outarrayUint32[i]++; //UDINT 90 | 91 | outarrayInt64[i]++; //LINT 92 | outarrayUint64[i]++; //ULINT 93 | 94 | outarrayFloat32[i]++; //REAL 95 | outarrayFloat64[i]++; //LREAL 96 | 97 | outarrayByte[i]++; //Byte 98 | outarrayWord[i]++; //Word 99 | outarrayDword[i]++; //DWORD 100 | outarrayLword[i]++; //Lword 101 | 102 | outarrayString[i] = "This is a standard IEC 61131 string (max. 80 chars)."; 103 | outarrayWString[i] = "This is a standard IEC 61131 wide string (max. 80 chars)."; 104 | } 105 | } 106 | 107 | } // end of namespace CppDataTypeTest 108 | -------------------------------------------------------------------------------- /Examples/DataAccess/DataAccess.pcwlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/DataAccess/DataAccess.pcwlx -------------------------------------------------------------------------------- /Examples/DataAccess/EngineerProject.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/DataAccess/EngineerProject.zip -------------------------------------------------------------------------------- /Examples/DataAccess/README.MD: -------------------------------------------------------------------------------- 1 | # Data Access Service 2 | 3 | ## Table of contents 4 | 5 | 6 | 7 | - [Introduction](#introduction) 8 | - [Guide details](#guide-details) 9 | - [References](#references) 10 | - [Quick-start example](#quick-start-example) 11 | 12 | 13 | 14 | ## Introduction 15 | 16 | The PLCnext Runtime provides an RSC service, called `IDataAccessService`, that a client can use to read and write Global Data Space (GDS) variables. From the API documentation for `IDataAccessService`: 17 | 18 | > The direct access functionality is a way for reading and writing values from and to variables. This is the fastest way, with a minimum of influence to the real time process, but it is not guaranteed that the data will be read/write in the same task cycle. For task consistent reading the subscription service `Arp.Plc.Gds.Services.ISubscriptionService` has to be used. 19 | 20 | ## Guide details 21 | |Description | Value | 22 | |------------ |-----------| 23 | |Created | 7.01.2021 | 24 | |Last modified| 7.01.2021 | 25 | |Controller| AXC F 2152 | 26 | |FW| 2021.0.0 LTS | 27 | |Arpversion| 21.0.0.35466 | 28 | |SVN Revision| 35466 | 29 | |SDK| 2021.0.0 LTS (21.0.0.35466) | 30 | |PLCnext CLI | 21.0.0 LTS (21.0.0.489) | 31 | 32 | ## References 33 | 34 | A complete description of the Data Access service is available from these sources: 35 | 36 | - [PLCnext Info Center](https://www.plcnext.help/te/Service_Components/Remote_Service_Calls_RSC/RSC_GDS_services.htm#IDataAccessService) 37 | - [API documentation](https://api.plcnext.help/api_docs_2021-0-LTS/classArp_1_1Plc_1_1Gds_1_1Services_1_1IDataAccessService.html) 38 | 39 | ## Quick-start example 40 | 41 | This example demonstrates features of the Data Access RSC service. 42 | 43 | It is assumed that the user has some experience [building C++ Components and Programs for PLCnext Control](https://www.plcnext.help/te/Programming/Cpp/Cpp_programming/Cpp_programs_in_PLCnext.htm). 44 | 45 | Prerequisites: 46 | 47 | - PLCnext Command Line Interface (CLI) tool, version 2021.0. This is included in the "PLCnext Technology C++ tool chain", available on the Phoenix Contact website. 48 | 49 | - A Software Development Kit (SDK) for the AXC F 2152 PLCnext Control, version 2021.0.0 or later. This is also included in the "PLCnext Technology C++ tool chain". 50 | 51 | - (optional) Eclipse IDE, with the PLCnext Technology feature installed. 52 | 53 | - (optional) Visual Studio, with the PLCnext Technology add-in installed. 54 | 55 | - PLCnext Engineer version 2021.0.1 or later. 56 | 57 | Procedure: 58 | 59 | - Clone this repository, e.g. 60 | 61 | ```sh 62 | git clone https://github.com/PLCnext/CppExamples.git 63 | ``` 64 | 65 | - Create the GDS variables that will be accessed: 66 | - Create a new PLCnext Engineer project for your target PLC. 67 | - Create one cyclic task. 68 | - Add the User Library "DataAccess.pcwlx", which is included in the `Examples/DataAccess` directory of this repository. This library contains one Program, called "DataAccess". 69 | - Create one instance of the "DataAccess" program in the cyclic task. 70 | - Name the program instance `DataAccessInstance`. 71 | - Write and start the project on the PLC. 72 | 73 | - Create a new **ACF project** using either the PLCnext CLI tool, or Eclipse, or Visual Studio, with the following settings: 74 | - Project name: `DataAccess` 75 | - Component name: `DataAccessComponent` 76 | - Project namespace: `DataAccess` 77 | 78 | - Copy the contents of the `Examples/DataAccess/src` directory in this repository, to the `src` directory of the ACF project. Replace the existing source files with the same name. 79 | 80 | - Build the ACF project. 81 | 82 | - Deploy the ACF project to the PLC. 83 | 84 | - Restart the PLCnext Runtime. 85 | 86 | - Check the contents of the file `/opt/plcnext/logs/Output.log`. It should contain messages showing the values of some OUT port variables from the `DataAccessInstance` program instance. 87 | 88 | - In the PLCnext Engineer project, in Debug mode, add the IN port variables from `DataAccessInstance` to the Watch window. The values of some of these variables are being written by the C++ component using the Data Access RSC service. 89 | -------------------------------------------------------------------------------- /Examples/DataAccess/src/DataAccessLibrary.acf.config: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Examples/DataAccess/test.bats: -------------------------------------------------------------------------------- 1 | # This script is designed to be executed by bats (https://github.com/bats-core/) 2 | # It requires: 3 | # - bats-core to be installed, along with the submodules bats-support and bats-assert 4 | # - PLC login credentials in the following environment variables: IP_ADDR, USERNAME, PASSWORD 5 | 6 | setup() { 7 | load 'bats-support/load' 8 | load 'bats-assert/load' 9 | } 10 | 11 | @test "DataAccess Example" { 12 | # (Re)start the PLCnext Runtime 13 | run sshpass -p ${PASSWORD} ssh ${USERNAME}@${IP_ADDR} "echo ${PASSWORD} | sudo -S /etc/init.d/plcnext restart" 14 | assert_output --partial 'plcnext started' 15 | 16 | # Check the Output.log file for the expected messages 17 | run sshpass -p ${PASSWORD} ssh ${USERNAME}@${IP_ADDR} "timeout 60s tail -f -n 0 /opt/plcnext/logs/Output.log" 18 | assert_output --partial 'Array_OUT[0] from DataAccess Read() =' 19 | assert_output --partial 'Struct_OUT.MyInt16 from DataAccess Read() =' 20 | assert_output --partial 'Struct_OUT.MyString from DataAccess Read() =' 21 | assert_output --partial 'read from ReadSingle()' 22 | } 23 | 24 | #teardown() { 25 | #} 26 | -------------------------------------------------------------------------------- /Examples/DynamicPorts/dynaports.gds.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Examples/DynamicPorts/dynaports.json: -------------------------------------------------------------------------------- 1 | { 2 | "digital_device":[ 3 | { 4 | "name":"sitting_room_light", 5 | "attributes":36 6 | }, 7 | { 8 | "name":"outside_light", 9 | "attributes":36 10 | }, 11 | { 12 | "name":"outside_movement", 13 | "attributes":34 14 | }, 15 | { 16 | "name":"outside_daytime", 17 | "attributes":34 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /Examples/DynamicPorts/src/DynamicPortsProgram.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Arp/System/Core/Arp.h" 3 | #include "Arp/Plc/Commons/Esm/DynamicPortsProgramBase.hpp" 4 | #include "Arp/System/Commons/Logging.h" 5 | #include "DynamicPortsComponent.hpp" 6 | #include "DynamicPortsLibrary.hpp" 7 | 8 | #include 9 | #include "nlohmann/json.hpp" 10 | 11 | namespace DynamicPorts 12 | { 13 | 14 | using namespace Arp; 15 | using namespace Arp::System::Commons::Diagnostics::Logging; 16 | using namespace Arp::Plc::Commons::Esm; 17 | 18 | //#program 19 | //#component(DynamicPorts::DynamicPortsComponent) 20 | class DynamicPortsProgram : public DynamicPortsProgramBase, private Loggable 21 | { 22 | public: // typedefs 23 | 24 | public: // construction/destruction 25 | DynamicPortsProgram(DynamicPorts::DynamicPortsComponent& dynamicPortsComponentArg, const String& name); 26 | DynamicPortsProgram(const DynamicPortsProgram& arg) = delete; 27 | virtual ~DynamicPortsProgram() = default; 28 | 29 | public: // operators 30 | DynamicPortsProgram& operator=(const DynamicPortsProgram& arg) = delete; 31 | 32 | public: // properties 33 | 34 | public: // operations 35 | void Execute() override; 36 | 37 | public: /* Ports 38 | ===== 39 | Ports are defined in the following way: 40 | //#port 41 | //#attributes(Input|Retain) 42 | //#name(NameOfPort) 43 | boolean portField; 44 | 45 | The attributes comment define the port attributes and is optional. 46 | The name comment defines the name of the port and is optional. Default is the name of the field. 47 | */ 48 | 49 | // An empty double-ended queue that will hold digital device values 50 | // (note that a vector of booleans will not work in this case). 51 | std::deque digital_device; 52 | 53 | private: // fields 54 | DynamicPorts::DynamicPortsComponent& dynamicPortsComponent; 55 | 56 | }; 57 | 58 | /////////////////////////////////////////////////////////////////////////////// 59 | // inline methods of class ProgramBase 60 | inline DynamicPortsProgram::DynamicPortsProgram(DynamicPorts::DynamicPortsComponent& dynamicPortsComponentArg, const String& name) 61 | : DynamicPortsProgramBase(name, DynamicPortsLibrary::GetInstance().GetTypeDomain()) 62 | , dynamicPortsComponent(dynamicPortsComponentArg) 63 | { 64 | // Read configuration from a specific file, in JSON format. 65 | // For simplicity, no error checks are done on the configuration. 66 | using json = nlohmann::json; 67 | 68 | std::ifstream ifs("/opt/plcnext/dynaports.json", std::ios::in); 69 | json config = json::parse(ifs); 70 | 71 | // Allocate the configured number of digital devices 72 | digital_device.resize(config["digital_device"].size(), false); 73 | 74 | // Create one GDS port for each digital device, with the user-specified configuration 75 | int i = 0; 76 | for (auto dd : config["digital_device"]) 77 | { 78 | this->AddPort(dd["name"], digital_device.at(i), dd["attributes"]); 79 | i++; 80 | } 81 | 82 | // Change the program type definition to use dynamic ports 83 | this->ReplaceProgramTypeDefinition(); 84 | 85 | TypeDefinition typeDefinition(this->GetDynamicPortsBuilder().GetTypeDefinition()); 86 | Log::Info("Number of dynamic ports used: {0}", static_cast(typeDefinition.GetFields().size())); 87 | } 88 | 89 | } // end of namespace DynamicPorts 90 | -------------------------------------------------------------------------------- /Examples/E_Learning_InternalFunctionExtensions/Picture/Architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/E_Learning_InternalFunctionExtensions/Picture/Architecture.png -------------------------------------------------------------------------------- /Examples/E_Learning_InternalFunctionExtensions/data/AxioReadConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "Configurations": [ 3 | { 4 | "Index": 1, 5 | "Subindex": 0, 6 | "DisplayAsText": true 7 | }, 8 | { 9 | "Index": 4, 10 | "Subindex": 0, 11 | "DisplayAsText": true 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /Examples/E_Learning_InternalFunctionExtensions/data/AxioReadConfig.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$id": "http://json-schema.org/draft-07/schema#", 3 | "title": "Axio_Read_Config", 4 | "description": "Validation file for the JSON based configuration", 5 | "type": "object", 6 | 7 | "properties": { 8 | 9 | "Configurations": { 10 | "type": "array", 11 | "items": { "$ref": "#/definitions/Configuration" } 12 | } 13 | }, 14 | "definitions": { 15 | "Configuration": { 16 | "type": "object", 17 | "required": ["Index", "Subindex", "DisplayAsText"], 18 | "properties": { 19 | "Index": { 20 | "type": "integer", 21 | "description": "The object index" 22 | }, 23 | "Subindex": { 24 | "type": "integer", 25 | "description": "The object subindex" 26 | }, 27 | "DisplayAsText": { 28 | "type": "boolean", 29 | "description": "The output is an ASCI string" 30 | } 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Examples/E_Learning_InternalFunctionExtensions/data/LIB_AxioReadLibrary.acf.config: -------------------------------------------------------------------------------- 1 |  2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Examples/E_Learning_InternalFunctionExtensions/src/COMP_AxioRead.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Arp/System/Core/Arp.h" 3 | #include "Arp/System/Acf/ComponentBase.hpp" 4 | #include "Arp/System/Acf/IApplication.hpp" 5 | #include "LIB_AxioReadLibrary.hpp" 6 | #include "Arp/Plc/Commons/Meta/MetaComponentBase.hpp" 7 | #include "Arp/System/Commons/Logging.h" 8 | 9 | //added header 10 | #include "Arp/System/Rsc/ServiceManager.hpp" 11 | #include "Arp/Io/Axioline/Services/IAcyclicCommunicationService.hpp" 12 | #include "Arp/System/Commons/Threading/WorkerThread.hpp" 13 | 14 | namespace LIB_AxioRead 15 | { 16 | 17 | using namespace Arp; 18 | using namespace Arp::System::Acf; 19 | using namespace Arp::Plc::Commons::Meta; 20 | 21 | using namespace Arp::System::Rsc; 22 | using namespace Arp::Io::Axioline::Services; 23 | using namespace Arp::System::Commons::Threading; 24 | 25 | //#acfcomponent 26 | class COMP_AxioRead : public ComponentBase, public MetaComponentBase, private Loggable 27 | { 28 | 29 | public: // typedefs 30 | 31 | public: // construction/destruction 32 | COMP_AxioRead(IApplication& application, const String& name); 33 | virtual ~COMP_AxioRead() = default; 34 | 35 | public: // IComponent operations 36 | void Initialize() override; 37 | void SubscribeServices()override; 38 | void LoadSettings(const String& settingsPath)override; 39 | void SetupSettings()override; 40 | void PublishServices()override; 41 | void LoadConfig() override; 42 | void SetupConfig() override; 43 | void ResetConfig() override; 44 | void Dispose()override; 45 | void PowerDown()override; 46 | 47 | public: // MetaComponentBase operations 48 | void RegisterComponentPorts() override; 49 | 50 | private: // methods 51 | COMP_AxioRead(const COMP_AxioRead& arg) = delete; 52 | COMP_AxioRead& operator= (const COMP_AxioRead& arg) = delete; 53 | 54 | public: // static factory operations 55 | static IComponent::Ptr Create(Arp::System::Acf::IApplication& application, const String& name); 56 | 57 | private: 58 | IAcyclicCommunicationService::Ptr pAcyclicCommunicationService; 59 | 60 | public: // declarations 61 | FILE * pConfigFile{}; 62 | 63 | struct stConfigParam { // structure definition 64 | uint16 Index = 0; 65 | uint8 Subindex = 0; 66 | bool DisplayAsText = false; 67 | }; 68 | 69 | stConfigParam arConfigs[100]; // limit array size to 100 elements 70 | int n = 0; // counter of configurations (data sets) 71 | 72 | WorkerThread WorkerThreadInstance; 73 | void WorkerThreadBody(void); 74 | 75 | 76 | PdiParam paramProcessData; // definition of the PDI parameter variable 77 | 78 | PdiParam param; // PDI parameters defined by switch status and JSON file 79 | 80 | uint8 switchFlag = 0; // flag to detect change of switch status 81 | 82 | }; 83 | 84 | /////////////////////////////////////////////////////////////////////////////// 85 | // inline methods of class COMP_AxioRead 86 | inline COMP_AxioRead::COMP_AxioRead(IApplication& application, const String& name) 87 | : ComponentBase(application, ::LIB_AxioRead::LIB_AxioReadLibrary::GetInstance(), name, ComponentCategory::Custom) 88 | , MetaComponentBase(::LIB_AxioRead::LIB_AxioReadLibrary::GetInstance().GetNamespace()) 89 | // thread with the name Thread_1, called each 10 seconds 90 | , WorkerThreadInstance(make_delegate(this, &COMP_AxioRead::WorkerThreadBody), 100, "Thread_1") { 91 | } 92 | 93 | inline IComponent::Ptr COMP_AxioRead::Create(Arp::System::Acf::IApplication& application, const String& name) 94 | { 95 | return IComponent::Ptr(new COMP_AxioRead(application, name)); 96 | } 97 | 98 | inline void COMP_AxioRead::RegisterComponentPorts(){} 99 | 100 | } // end of namespace LIB_AxioRead 101 | -------------------------------------------------------------------------------- /Examples/FileStreamExample/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | external/ 3 | intermediate/ 4 | CMakeLists.txt 5 | plcnext.proj -------------------------------------------------------------------------------- /Examples/FileStreamExample/src/FileStreamExampleComponent.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Arp/System/Core/Arp.h" 3 | #include "Arp/System/Acf/ComponentBase.hpp" 4 | #include "Arp/System/Acf/IApplication.hpp" 5 | #include "Arp/Plc/Commons/Esm/ProgramComponentBase.hpp" 6 | #include "FileStreamExampleComponentProgramProvider.hpp" 7 | #include "Arp/Plc/Commons/Meta/MetaLibraryBase.hpp" 8 | #include "Arp/System/Commons/Logging.h" 9 | 10 | namespace FileStreamExample { 11 | 12 | using namespace Arp; 13 | using namespace Arp::System::Acf; 14 | using namespace Arp::Plc::Commons::Esm; 15 | using namespace Arp::Plc::Commons::Meta; 16 | 17 | //#component 18 | class FileStreamExampleComponent: public ComponentBase, 19 | public ProgramComponentBase, 20 | private Loggable { 21 | public: // typedefs 22 | 23 | public: // construction/destruction 24 | FileStreamExampleComponent(IApplication &application, const String &name); 25 | virtual ~FileStreamExampleComponent() = default; 26 | 27 | public: // IComponent operations 28 | void Initialize() override; 29 | void LoadConfig() override; 30 | void SetupConfig() override; 31 | void ResetConfig() override; 32 | 33 | public: // ProgramComponentBase operations 34 | void RegisterComponentPorts() override; 35 | 36 | private: // methods 37 | FileStreamExampleComponent(const FileStreamExampleComponent &arg) = delete; 38 | FileStreamExampleComponent& operator=(const FileStreamExampleComponent &arg) = delete; 39 | 40 | void WriteToFile(String textToWrite); 41 | String ReadFromFile(); 42 | 43 | public: // static factory operations 44 | static IComponent::Ptr Create(Arp::System::Acf::IApplication &application, 45 | const String &name); 46 | 47 | private: // fields 48 | FileStreamExampleComponentProgramProvider programProvider; 49 | const Arp::String filePath = "/opt/plcnext/logs/TestFile.txt"; 50 | bool newbin{false}; 51 | bool nofile{false}; 52 | public: 53 | boolean bReset { false }; 54 | }; 55 | 56 | inline IComponent::Ptr FileStreamExampleComponent::Create(Arp::System::Acf::IApplication &application, const String &name) { 57 | return IComponent::Ptr(new FileStreamExampleComponent(application, name)); 58 | } 59 | 60 | } // end of namespace FileStreamExample 61 | -------------------------------------------------------------------------------- /Examples/FileStreamExample/src/FileStreamExampleProgram.cpp: -------------------------------------------------------------------------------- 1 | #include "FileStreamExampleProgram.hpp" 2 | #include "Arp/System/Commons/Logging.h" 3 | #include "Arp/System/Core/ByteConverter.hpp" 4 | 5 | namespace FileStreamExample 6 | { 7 | 8 | void FileStreamExampleProgram::Execute() 9 | { 10 | //implement program 11 | //log.Info("bReset={0} , portfield={1}", fileStreamExampleComponent.bReset, portField); 12 | fileStreamExampleComponent.bReset = portField; 13 | } 14 | 15 | } // end of namespace FileStreamExample 16 | -------------------------------------------------------------------------------- /Examples/FileStreamExample/src/FileStreamExampleProgram.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Arp/System/Core/Arp.h" 3 | #include "Arp/Plc/Commons/Esm/ProgramBase.hpp" 4 | #include "Arp/System/Commons/Logging.h" 5 | #include "FileStreamExampleComponent.hpp" 6 | 7 | namespace FileStreamExample 8 | { 9 | 10 | using namespace Arp; 11 | using namespace Arp::System::Commons::Diagnostics::Logging; 12 | using namespace Arp::Plc::Commons::Esm; 13 | 14 | //#program 15 | //#component(FileStreamExample::FileStreamExampleComponent) 16 | class FileStreamExampleProgram : public ProgramBase, private Loggable 17 | { 18 | public: // typedefs 19 | 20 | public: // construction/destruction 21 | FileStreamExampleProgram(FileStreamExample::FileStreamExampleComponent& fileStreamExampleComponentArg, const String& name); 22 | FileStreamExampleProgram(const FileStreamExampleProgram& arg) = delete; 23 | virtual ~FileStreamExampleProgram() = default; 24 | 25 | public: // operators 26 | FileStreamExampleProgram& operator=(const FileStreamExampleProgram& arg) = delete; 27 | 28 | public: // properties 29 | 30 | public: // operations 31 | void Execute() override; 32 | 33 | public: /* Ports 34 | ===== 35 | Ports are defined in the following way: 36 | //#port 37 | //#attributes(Input|Retain) 38 | //#name(NameOfPort) 39 | boolean portField; 40 | 41 | The attributes comment define the port attributes and is optional. 42 | The name comment defines the name of the port and is optional. Default is the name of the field. 43 | */ 44 | //#port 45 | //#attributes(Input) 46 | //#name(DeleteFileAtNextStart) 47 | boolean portField{false}; 48 | private: // fields 49 | FileStreamExample::FileStreamExampleComponent& fileStreamExampleComponent; 50 | 51 | }; 52 | 53 | /////////////////////////////////////////////////////////////////////////////// 54 | // inline methods of class ProgramBase 55 | inline FileStreamExampleProgram::FileStreamExampleProgram(FileStreamExample::FileStreamExampleComponent& fileStreamExampleComponentArg, const String& name) 56 | : ProgramBase(name) 57 | , fileStreamExampleComponent(fileStreamExampleComponentArg) 58 | { 59 | log.Info("---Constructor:{0}",GetFullName()); 60 | } 61 | 62 | } // end of namespace FileStreamExample 63 | -------------------------------------------------------------------------------- /Examples/Force/Force.pcwex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/Force/Force.pcwex -------------------------------------------------------------------------------- /Examples/Force/README.MD: -------------------------------------------------------------------------------- 1 | # Force Service 2 | 3 | ## Table of contents 4 | 5 | 6 | 7 | - [Introduction](#introduction) 8 | - [Guide details](#guide-details) 9 | - [References](#references) 10 | - [Quick-start example](#quick-start-example) 11 | 12 | 13 | 14 | ## Introduction 15 | 16 | The PLCnext Runtime provides an RSC service, called `IForceService`, that a client can use to force some Global Data Space (GDS) variables. From the PLCnext Engineer help system: 17 | 18 | > What is the difference between forcing and overwriting? 19 | > 20 | > Overwriting is possible for local and global variables (marker variables without assigned process data item) as well as for I/O variables (assigned to process data item). The value is overwritten (set) only once at the beginning of the task execution cycle. Then, the variable is processed normally. Thus, the new value of the variable remains until a write access is performed. A write access can be performed by a programmed store operation or by remote access (e.g. by the OPC server) or by initializing the variable in case of a controller cold start. 21 | > 22 | > Forcing is possible for variables and ports which are connected to process data items, i.e., I/O variables/ports. Forcing means setting the I/O variable/port permanently to the force value until forcing is reset by the user. 23 | 24 | ## Guide details 25 | 26 | |Description | Value | 27 | |------------ |-----------| 28 | |Created | 7.01.2021 | 29 | |Last modified| 7.01.2021 | 30 | |Controller| AXC F 2152 | 31 | |FW| 2021.0.0 LTS | 32 | |Arpversion| 21.0.0.35466 | 33 | |SVN Revision| 35466 | 34 | |SDK| 2021.0.0 LTS (21.0.0.35466) | 35 | |PLCnext CLI | 21.0.0 LTS (21.0.0.489) | 36 | 37 | ## References 38 | 39 | A complete description of the Force service is available from this source: 40 | 41 | - [API documentation](https://api.plcnext.help/api_docs_2021-0-LTS/classArp_1_1Plc_1_1Gds_1_1Services_1_1IForceService.html) 42 | 43 | ## Quick-start example 44 | 45 | This example demonstrates features of the Force RSC service. 46 | 47 | It is assumed that the user has some experience [building C++ Components and Programs for PLCnext Control](https://www.plcnext.help/te/Programming/Cpp/Cpp_programming/Cpp_programs_in_PLCnext.htm). 48 | 49 | Prerequisites: 50 | 51 | - AXC F x152 controller with AXL F DI8/3 DO8/3 2H (2702071) digital input/output module. Other hardware arrangements will require modifications to the sample code. 52 | 53 | - PLCnext Command Line Interface (CLI) tool, version 2021.0. This is included in the "PLCnext Technology C++ tool chain", available on the Phoenix Contact website. 54 | 55 | - A Software Development Kit (SDK) for the AXC F 2152 PLCnext Control, version 2021.0.0 or later. This is also included in the "PLCnext Technology C++ tool chain". 56 | 57 | - (optional) Eclipse IDE, with the PLCnext Technology feature installed. 58 | 59 | - (optional) Visual Studio, with the PLCnext Technology add-in installed. 60 | 61 | - PLCnext Engineer version 2021.0.1 or later. 62 | 63 | Procedure: 64 | 65 | - Clone this repository, e.g. 66 | 67 | ```sh 68 | git clone https://github.com/PLCnext/CppExamples.git 69 | ``` 70 | 71 | - Create the variables that will be forced: 72 | - In PLCnext Engineer, open the PLCnext Engineer project in the `Examples/Force` directory of this repository. 73 | - Check that the controller model and firmware version in the project matches the controller you are using. 74 | - Send the project to the PLC and check that the PLC starts OK. 75 | 76 | - Create a new **ACF project** using either the PLCnext CLI tool, or Eclipse, or Visual Studio, with the following settings: 77 | - Project name: `Force` 78 | - Component name: `ForceComponent` 79 | - Project namespace: `Force` 80 | 81 | - Copy the contents of the `Examples/Force/src` directory in this repository, to the `src` directory of the ACF project. Replace the existing source files with the same name. 82 | 83 | - Build the ACF project. 84 | 85 | - Deploy the ACF project to the PLC. 86 | 87 | - Restart the PLCnext Runtime. 88 | 89 | - Check the contents of the file `/opt/plcnext/logs/Output.log`. It should contain messages from your ACF component and from the `GdsForceManager` firmware component. 90 | -------------------------------------------------------------------------------- /Examples/Force/src/ForceComponent.hpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////" 2 | // 3 | // Copyright PHOENIX CONTACT Electronics GmbH 4 | // 5 | /////////////////////////////////////////////////////////////////////////////// 6 | #pragma once 7 | #include "Arp/System/Core/Arp.h" 8 | #include "Arp/System/Acf/ComponentBase.hpp" 9 | #include "Arp/System/Acf/IApplication.hpp" 10 | #include "Arp/Plc/Commons/Meta/MetaComponentBase.hpp" 11 | #include "Arp/System/Commons/Logging.h" 12 | #include "Arp/System/Commons/Threading/WorkerThread.hpp" 13 | #include "Arp/Plc/Gds/Services/IForceService.hpp" 14 | 15 | namespace Force 16 | { 17 | 18 | using namespace Arp; 19 | using namespace Arp::System::Acf; 20 | using namespace Arp::Plc::Commons::Meta; 21 | using namespace Arp::Plc::Gds::Services; 22 | using namespace Arp::System::Commons::Threading; 23 | 24 | /// 25 | /// ########################### 26 | /// Force example 27 | /// ########################### 28 | /// 29 | /// In this example, Forcing of GDS variables (including I/O) is demonstrated: 30 | /// 31 | /// It is assumed that all operations succeed, so return codes are generally ignored. 32 | /// 33 | /// Values forced by this component can be seen in the PLCnext Engineer project, using Debug mode. 34 | /// 35 | /// 36 | 37 | //#acfcomponent 38 | class ForceComponent : public ComponentBase, public MetaComponentBase, private Loggable 39 | { 40 | public: // typedefs 41 | 42 | public: // construction/destruction 43 | ForceComponent(IApplication& application, const String& name); 44 | virtual ~ForceComponent() = default; 45 | 46 | public: // IComponent operations 47 | void Initialize() override; 48 | void SubscribeServices()override; 49 | void LoadSettings(const String& settingsPath)override; 50 | void SetupSettings()override; 51 | void PublishServices()override; 52 | void LoadConfig() override; 53 | void SetupConfig() override; 54 | void ResetConfig() override; 55 | void Dispose()override; 56 | void PowerDown()override; 57 | 58 | public: // MetaComponentBase operations 59 | void RegisterComponentPorts() override; 60 | 61 | private: // force methods 62 | void StartForce(void); 63 | void StopForce(void); 64 | void ForceData(void); 65 | 66 | private: // Plc event handlers 67 | void OnPlcLoaded(void); 68 | void OnPlcStarted(void); 69 | void OnPlcStopping(void); 70 | void OnPlcUnloading(bool onError); 71 | void OnPlcChanging(void); 72 | void OnPlcChanged(bool success); 73 | 74 | private: // methods 75 | ForceComponent(const ForceComponent& arg) = delete; 76 | ForceComponent& operator= (const ForceComponent& arg) = delete; 77 | 78 | public: // static factory operations 79 | static IComponent::Ptr Create(Arp::System::Acf::IApplication& application, const String& name); 80 | 81 | private: // fields 82 | // Service thread that reads and writes data and writes log messages 83 | WorkerThread forceThread; 84 | IForceService::Ptr forceServicePtr = nullptr; 85 | 86 | int16 step {0}; // Step sequencer 87 | 88 | public: /* Ports 89 | ===== 90 | Component ports are defined in the following way: 91 | 92 | //#attributes(Hidden) 93 | struct Ports 94 | { 95 | //#name(NameOfPort) 96 | //#attributes(Input|Retain|Opc) 97 | Arp::boolean portField = false; 98 | // The GDS name is "/NameOfPort" if the struct is declared as Hidden 99 | // otherwise the GDS name is "/PORTS.NameOfPort" 100 | }; 101 | 102 | //#port 103 | Ports ports; 104 | 105 | Create one (and only one) instance of this struct. 106 | Apart from this single struct instance, there must be no other Component variables declared with the #port comment. 107 | The only attribute that is allowed on the struct instance is "Hidden", and this is optional. 108 | The struct can contain as many members as necessary. 109 | The #name comment can be applied to each member of the struct, and is optional. 110 | The #name comment defines the GDS name of an individual port element. If omitted, the member variable name is used as the GDS name. 111 | The members of the struct can be declared with any of the attributes allowed for a Program port. 112 | */ 113 | 114 | }; 115 | 116 | inline IComponent::Ptr ForceComponent::Create(Arp::System::Acf::IApplication& application, const String& name) 117 | { 118 | return IComponent::Ptr(new ForceComponent(application, name)); 119 | } 120 | 121 | } // end of namespace Force 122 | -------------------------------------------------------------------------------- /Examples/IncludeOpenSourceLibrary/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/IncludeOpenSourceLibrary/.gitkeep -------------------------------------------------------------------------------- /Examples/NoEngineer/pnd.esm.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Examples/NoEngineer/pnd.gds.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/NoEngineer/pnd.meta.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Examples/NoEngineer/pnd.plm.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Examples/NotificationExample/.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | Standard: Cpp11 3 | UseTab: Never 4 | IndentWidth: 4 5 | AccessModifierOffset: -4 6 | BreakBeforeBraces: Allman 7 | BreakConstructorInitializers: BeforeComma 8 | Cpp11BracedListStyle: true 9 | DerivePointerAlignment: true 10 | FixNamespaceComments: true 11 | AllowShortIfStatementsOnASingleLine: false 12 | IndentCaseLabels: false 13 | ColumnLimit: 0 14 | -------------------------------------------------------------------------------- /Examples/NotificationExample/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | indent_style = space 6 | indent_size = 4 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.{md,markdown}] 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /Examples/NotificationExample/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | build 3 | bin 4 | intermediate 5 | -------------------------------------------------------------------------------- /Examples/NotificationExample/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | project(NotificationExample) 4 | 5 | if(NOT CMAKE_BUILD_TYPE) 6 | set(CMAKE_BUILD_TYPE Release) 7 | endif() 8 | 9 | ################# create target ####################################################### 10 | 11 | set (WILDCARD_SOURCE *.cpp) 12 | set (WILDCARD_HEADER *.h *.hpp *.hxx) 13 | 14 | file(GLOB_RECURSE Headers src/${WILDCARD_HEADER} intermediate/code/${WILDCARD_HEADER}) 15 | file(GLOB_RECURSE Sources src/${WILDCARD_SOURCE} intermediate/code/${WILDCARD_SOURCE}) 16 | add_library(NotificationExample SHARED ${Headers} ${Sources}) 17 | 18 | ####################################################################################### 19 | 20 | ################# project include-paths ############################################### 21 | 22 | target_include_directories(NotificationExample 23 | PUBLIC 24 | $ 25 | $) 26 | 27 | ####################################################################################### 28 | 29 | ################# include arp cmake module path ####################################### 30 | 31 | list(INSERT CMAKE_MODULE_PATH 0 "${ARP_TOOLCHAIN_CMAKE_MODULE_PATH}") 32 | 33 | ####################################################################################### 34 | 35 | ################# set link options #################################################### 36 | # WARNING: Without --no-undefined the linker will not check, whether all necessary # 37 | # libraries are linked. When a library which is necessary is not linked, # 38 | # the firmware will crash and there will be NO indication why it crashed. # 39 | ####################################################################################### 40 | 41 | target_link_options(NotificationExample PRIVATE LINKER:--no-undefined) 42 | 43 | ####################################################################################### 44 | 45 | ################# add link targets #################################################### 46 | 47 | find_package(ArpDevice REQUIRED) 48 | find_package(ArpProgramming REQUIRED) 49 | 50 | target_link_libraries(NotificationExample PRIVATE ArpDevice ArpProgramming) 51 | 52 | ####################################################################################### 53 | 54 | ################# install ############################################################ 55 | 56 | string(REGEX REPLACE "^.*\\(([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*$" "\\1" _ARP_SHORT_DEVICE_VERSION ${ARP_DEVICE_VERSION}) 57 | install(TARGETS NotificationExample 58 | LIBRARY DESTINATION ${ARP_DEVICE}_${_ARP_SHORT_DEVICE_VERSION}/$/lib 59 | ARCHIVE DESTINATION ${ARP_DEVICE}_${_ARP_SHORT_DEVICE_VERSION}/$/lib 60 | RUNTIME DESTINATION ${ARP_DEVICE}_${_ARP_SHORT_DEVICE_VERSION}/$/bin) 61 | unset(_ARP_SHORT_DEVICE_VERSION) 62 | 63 | ####################################################################################### -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_Example.pcwef: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/NotificationExample/Engineer/Notifications_Example.pcwef -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/AXLF_Mast~Arp.Io.Axl~0000.libmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/AXLF_Mast~Arp.Io.Axl~0001.compmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/Applikation~Profiles~0000.hmiprofiles: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/Applikatio~Variables~0000.hmivar: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/Applikati~Navigation~0000.hminav: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/CFG_34E4C~PlmConfigu~0000.plmc: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/EIP_Maste~Arp.Io.Eth~0000.libmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/EIP_Maste~Controller~0000.compmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/HMI_Server~DataList~0000.dlr4hmi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | HmiTagRoleConfiguration.xml 5 | HmiTagDataListConfiguration.xml 6 | 7 | HmiTag 8 | Any 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/Hardware~f69cc705-29~0000.DataLink: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/Hardware~f69cc705-29~0001.Transport: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 192.168.1.2 5 | 192.168.100.254 6 | 7 | 255.255.0.0 8 | [UTF-8;6E6574776F726B3031] 9 | 10 | 11 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/IB_Master~Arp.Io.Ib.~0000.compmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/IB_Master~Arp.Io.Ib~0000.libmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/Logical Elemen~CRC32~0000.crc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/Logical Elemen~CRC32~0000.crc -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/Logical E~GeneratedD~0000.dt: -------------------------------------------------------------------------------- 1 | TYPE 2 | ByteArray35 : ARRAY[0..35] OF BYTE; 3 | END_TYPE 4 | TYPE 5 | IP_ADDRESS_ARRAY : ARRAY[0..3] OF BYTE; 6 | END_TYPE 7 | TYPE 8 | EIPD_IO_ARRAY : ARRAY[0..127] OF WORD; 9 | END_TYPE 10 | TYPE 11 | HMI_STATUS_STRUCT : STRUCT 12 | SESSION_ID : STRING; 13 | STATION_ID : STRING; 14 | LAST_REQ : LINT; 15 | IP_ADDRESS : IP_ADDRESS_ARRAY; 16 | END_STRUCT 17 | END_TYPE 18 | TYPE 19 | HMI_CONTROL_STRUCT : STRUCT 20 | DISABLE : BOOL; 21 | END_STRUCT 22 | END_TYPE 23 | TYPE 24 | HMI_STATUS_ARRAY : ARRAY[1..256] OF HMI_STATUS_STRUCT; 25 | END_TYPE 26 | TYPE 27 | HMI_CONTROL_ARRAY : ARRAY[1..256] OF HMI_CONTROL_STRUCT; 28 | END_TYPE 29 | TYPE 30 | HMI_STATUS_TYPE : STRUCT 31 | CLIENT_COUNT : UINT; 32 | CLIENTS : HMI_STATUS_ARRAY; 33 | END_STRUCT 34 | END_TYPE 35 | TYPE 36 | HMI_CONTROL_TYPE : STRUCT 37 | CLIENTS : HMI_CONTROL_ARRAY; 38 | END_STRUCT 39 | END_TYPE 40 | TYPE 41 | TASK_INFO : STRUCT 42 | INTERVAL : LINT; 43 | PRIORITY : INT; 44 | WATCHDOG : LINT; 45 | LAST_EXEC_DURATION : LINT; 46 | MIN_EXEC_DURATION : LINT; 47 | MAX_EXEC_DURATION : LINT; 48 | LAST_ACTIVATION_DELAY : LINT; 49 | MIN_ACTIVATION_DELAY : LINT; 50 | MAX_ACTIVATION_DELAY : LINT; 51 | EXEC_TIME_THRESHOLD : LINT; 52 | EXEC_TIME_THRESHOLD_CNT : UDINT; 53 | NAME : STRING; 54 | END_STRUCT 55 | END_TYPE 56 | TYPE 57 | TASK_INFO_ARRAY : ARRAY[1..16] OF TASK_INFO; 58 | END_TYPE 59 | TYPE 60 | ESM_INFO : STRUCT 61 | TASK_COUNT : UINT; 62 | TICK_COUNT : UDINT; 63 | TICK_INTERVAL : UDINT; 64 | TASK_INFOS : TASK_INFO_ARRAY; 65 | END_STRUCT 66 | END_TYPE 67 | TYPE 68 | STRING512 : STRING[512]; 69 | END_TYPE 70 | TYPE 71 | ESM_INFO_ARRAY : ARRAY[1..2] OF ESM_INFO; 72 | END_TYPE 73 | TYPE 74 | ESM_EXCEPTION_INFO : STRUCT 75 | TYPE_ID : UDINT; 76 | SUB_TYPE : STRING512; 77 | SUB_TYPE_ID : UDINT; 78 | TASK_NAME : STRING; 79 | PROGRAM_NAME : STRING512; 80 | INFORMATION : STRING512; 81 | END_STRUCT 82 | END_TYPE 83 | TYPE 84 | ESM_EXCEPTION_INFO_ARRAY : ARRAY[1..2] OF ESM_EXCEPTION_INFO; 85 | END_TYPE 86 | TYPE 87 | ESM_DAT : STRUCT 88 | ESM_COUNT : USINT; 89 | ESM_INFOS : ESM_INFO_ARRAY; 90 | EXCEPTION_COUNT : USINT; 91 | EXCEPTION_INFOS : ESM_EXCEPTION_INFO_ARRAY; 92 | END_STRUCT 93 | END_TYPE 94 | TYPE 95 | PND_IO_512 : ARRAY[0..511] OF BYTE; 96 | END_TYPE 97 | TYPE 98 | RTC_TYPE : STRUCT 99 | HOURS : USINT; 100 | MINUTES : USINT; 101 | SECONDS : USINT; 102 | DAY : USINT; 103 | MONTH : USINT; 104 | YEAR : UINT; 105 | END_STRUCT 106 | END_TYPE 107 | TYPE 108 | CPU_LOAD_PER_CORE_ARRAY : ARRAY[1..2] OF USINT; 109 | END_TYPE 110 | TYPE 111 | DEVICE_STATE_2152_TYPE : STRUCT 112 | BOARD_TEMPERATURE : SINT; 113 | reserved1 : BOOL; 114 | reserved2 : USINT; 115 | CPU_LOAD_ALL_CORES : USINT; 116 | CPU_LOAD_PER_CORE : CPU_LOAD_PER_CORE_ARRAY; 117 | END_STRUCT 118 | END_TYPE 119 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/NewProgram.pou~Code~0000.st: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/NewProgram.~Metadata~0000.meta: -------------------------------------------------------------------------------- 1 | 2 | 3 | Program 4 | Program 5 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/NewProgram~Variables~0000.var: -------------------------------------------------------------------------------- 1 | { CustomGroupDefinition('ff869203-6c1d-44c7-a561-1c6ca8f9cb95', '') } 2 | 3 | VAR_GLOBAL 4 | test : UINT { CustomGroupReference('ff869203-6c1d-44c7-a561-1c6ca8f9cb95'), OutputPort } {Id('733db651-4e48-4aa6-84eb-63d5f11c97af')}; 5 | test2 : UINT { CustomGroupReference('ff869203-6c1d-44c7-a561-1c6ca8f9cb95'), OutputPort } {Id('cde62c24-7cbc-4632-b804-28593c3561e0')}; 6 | END_VAR 7 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/PLCnext~EsmConfigura~0000.esmc: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/PN_Master~Arp.Io.Pn~0000.libmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/PN_Master~Controller~0000.compmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/RES_370726C~DataList~0000.dlr4var: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | VariableRoleConfiguration.xml 5 | VariableDataListConfiguration.xml 6 | 7 | Variable 8 | Any 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/RES_37072~Arp.Plc.Ec~0000.libmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/RES_37072~EclrCompon~0000.compmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/RES_37072~IOConfigur~0000.ioc: -------------------------------------------------------------------------------- 1 | (*********************************************************************) 2 | (* The following I/O configuration was generated by the application. *) 3 | (* Do not modify the lines below, any changes will be overwritten *) 4 | (* when they are regenerated. *) 5 | (*********************************************************************) 6 | 7 | (* No auto-generated I/O configuration available *) 8 | 9 | (*********************************************************************) 10 | (* End of auto-generated I/O configuration. User defined I/O groups *) 11 | (* can be defined after these lines. *) 12 | (*********************************************************************) 13 | 14 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/RES_37072~ResourceSe~0000.set: -------------------------------------------------------------------------------- 1 | { Type('AXCF2152') } 2 | RESOURCE SPS 3 | { DeviceProfileWorksheet('DeviceProfile', Id := '4a419ff9-d618-48f7-bf57-f0789745ed54') } 4 | { DeviceProfile( 5 | Name := 'RES_370726C867AB44398EB197A05A7DE670', 6 | Parent := ( Name := 'AXCF2152', Version := '2019.6.0'), 7 | UpdateType := 'Manual', 8 | FilesIni := 9 | [ 10 | ], 11 | CommunicationMetadata := 'UniqueId=TCP/IP;IsBackup=False', 12 | CommunicationType := 'TcpIp', 13 | CommunicationParameters := 'DLL socomm.dll -ip192.168.1.10 -p41100 -to2000', 14 | DownloadFiles := 15 | [ 16 | ] 17 | )} 18 | 19 | 20 | TASK GO (INTERVAL := T#100ms, PRIORITY := 0) { Watchdog(T#100ms), Id('8a13b8b7-9b21-4ea2-9822-ae8efe229495') }; 21 | 22 | PROGRAM NewProgram1 WITH GO : NewProgram { Id('425e4476-85fe-4d2c-9811-a5e43b447d70') }; 23 | 24 | END_RESOURCE 25 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/Safety~0000.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/Safety~0000/Inventori~SafetyInve~0000.xml: -------------------------------------------------------------------------------- 1 | pUaNl0K1GS5N5YfmDAofMHm9sL0=SafetyInventory -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/Safety~0000/Logs~SafetyMessageLo~0000.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | HRDpEKxXcfsyw401rsisgivydwo= 4 | 5 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/StorageContent~0000.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/content/StorageProperties~0000.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Notifications_Example 4 | 5d4c72f7-cb8e-42e8-bacf-5366d8e415cf 5 | Project 6 | 7 | Areas 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Examples/NotificationExample/Engineer/Notifications_ExampleFlat/structure.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Examples/NotificationExample/MyNmDebug.config: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | Info 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Examples/NotificationExample/MyNmDebug.settings: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Examples/NotificationExample/My_Nm.acf.config: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Examples/NotificationExample/My_Nm_Logger.config: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Examples/NotificationExample/plcnext.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | AXCF2152,2021.0.0 LTS (21.0.0.35466) 4 | d2650cb2-0629-4666-91e9-f94d07a80772 5 | 1.1 6 | 7 | -------------------------------------------------------------------------------- /Examples/NotificationExample/plcnext.proj.bak: -------------------------------------------------------------------------------- 1 | 2 | 3 | AXCF2152,2020.6.1 (20.6.1.30859) 4 | 31347408-0ad8-4c55-ad54-da85bcea94ee 5 | -------------------------------------------------------------------------------- /Examples/NotificationExample/src/COMP_Notifications.hpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////" 2 | // 3 | // Copyright PHOENIX CONTACT Electronics GmbH 4 | // 5 | /////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | #include "Arp/System/Core/Arp.h" 9 | #include "Arp/System/Acf/ComponentBase.hpp" 10 | #include "Arp/System/Acf/IApplication.hpp" 11 | #include "Arp/Plc/Commons/Esm/ProgramComponentBase.hpp" 12 | #include "COMP_NotificationsProgramProvider.hpp" 13 | #include "Arp/Plc/Commons/Meta/MetaLibraryBase.hpp" 14 | #include "Arp/System/Commons/Logging.h" 15 | 16 | #include "Arp/Plc/Commons/Domain/PlcState.hpp" 17 | #include "Arp/System/Nm/NotificationManager.hpp" 18 | #include "Arp/System/NmPayload/Plc/PlcStateChangedPayload.hpp" 19 | #include "Arp/System/NmPayload/Device/NetworkConfigurationChangedPayload.hpp" 20 | #include "ExamplePayload.hpp" 21 | 22 | namespace NotificationExample 23 | { 24 | 25 | using namespace Arp; 26 | using namespace Arp::System::Acf; 27 | using namespace Arp::Plc::Commons::Esm; 28 | using namespace Arp::Plc::Commons::Meta; 29 | 30 | //#component 31 | class COMP_Notifications : public ComponentBase, public ProgramComponentBase, private Loggable 32 | { 33 | public: // typedefs 34 | 35 | public: // construction/destruction 36 | COMP_Notifications(IApplication& application, const String& name); 37 | virtual ~COMP_Notifications() = default; 38 | 39 | public: // IComponent operations 40 | void Initialize() override; 41 | void LoadConfig() override; 42 | void SetupConfig() override; 43 | void ResetConfig() override; 44 | 45 | public: // ProgramComponentBase operations 46 | void RegisterComponentPorts() override; 47 | 48 | private: // methods 49 | COMP_Notifications(const COMP_Notifications& arg) = delete; 50 | COMP_Notifications& operator= (const COMP_Notifications& arg) = delete; 51 | 52 | public: // static factory operations 53 | static IComponent::Ptr Create(Arp::System::Acf::IApplication& application, const String& name); 54 | 55 | private: // SubscriptionCallbacks 56 | void NM_Subscription1_Callback(const Arp::System::Nm::Notification& notification); 57 | void NM_Subscription2_Callback(const Arp::System::Nm::Notification& notification); 58 | void NetworkConfigurationChanged_Callback(const Arp::System::Nm::Notification& notification); 59 | void PlcStateChanged_Callback(const Arp::System::Nm::Notification& notification); 60 | 61 | 62 | private: // fields 63 | COMP_NotificationsProgramProvider programProvider; 64 | 65 | Arp::System::Nm::NotificationManager& nm = NotificationManager::GetInstance(); 66 | Arp::System::Nm::NotificationSubscriber Custom_subscription; 67 | Arp::System::Nm::NotificationSubscriber Custom_subscription2; 68 | Arp::System::Nm::NotificationSubscriber NetworkConfigurationChanged_subscription; 69 | Arp::System::Nm::NotificationSubscriber PlcStateChanged_subscription; 70 | 71 | 72 | public: /* Ports 73 | ===== 74 | Component ports are defined in the following way: 75 | 76 | //#attributes(Hidden) 77 | struct Ports 78 | { 79 | //#name(NameOfPort) 80 | //#attributes(Input|Retain|Opc) 81 | Arp::boolean portField = false; 82 | // The GDS name is "/NameOfPort" if the struct is declared as Hidden 83 | // otherwise the GDS name is "/PORTS.NameOfPort" 84 | }; 85 | 86 | //#port 87 | Ports ports; 88 | 89 | Create one (and only one) instance of this struct. 90 | Apart from this single struct instance, there must be no other Component variables declared with the #port comment. 91 | The only attribute that is allowed on the struct instance is "Hidden", and this is optional. 92 | The struct can contain as many members as necessary. 93 | The #name comment can be applied to each member of the struct, and is optional. 94 | The #name comment defines the GDS name of an individual port element. If omitted, the member variable name is used as the GDS name. 95 | The members of the struct can be declared with any of the attributes allowed for a Program port. 96 | */ 97 | int OP_uiValue1{}; 98 | int OP_uiValue2{}; 99 | }; 100 | 101 | inline IComponent::Ptr COMP_Notifications::Create(Arp::System::Acf::IApplication& application, const String& name) 102 | { 103 | return IComponent::Ptr(new COMP_Notifications(application, name)); 104 | } 105 | 106 | } // end of namespace NotificationExample 107 | -------------------------------------------------------------------------------- /Examples/NotificationExample/src/ExamplePayload.hpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////" 2 | // 3 | // Copyright PHOENIX CONTACT Electronics GmbH 4 | // 5 | /////////////////////////////////////////////////////////////////////////////// 6 | 7 | /* 8 | * ExamplePayload.hpp 9 | * 10 | * Created on: 07.05.2019 11 | * 12 | */ 13 | 14 | #ifndef EXAMPLEPAYLOAD_HPP_ 15 | #define EXAMPLEPAYLOAD_HPP_ 16 | 17 | #pragma once 18 | // 1. Include header "SpecializedPayload.hpp" 19 | #include "Arp/System/Nm/SpecializedPayload.hpp" 20 | 21 | // 2. Use project namespace 22 | namespace NotificationExample{ 23 | // 3. Use Arp namespace 24 | using namespace Arp; 25 | // and namespace of the notification manager 26 | using namespace Arp::System::Nm; 27 | // 4. Define payload 28 | class ExamplePayload : public SpecializedPayload 29 | { 30 | public: 31 | // definition of the payload values 32 | ExamplePayload(const uint16& uiPortValue, const String & sMyMessage) 33 | : SpecializedPayload("The value is: {0}") // definition of the payload string 34 | { 35 | this->SetFieldValue(this->fieldIndexMyValue, uiPortValue); // relation variable value to index 36 | this->SetFieldValue(this->fieldIndexMyString, sMyMessage); // relation variable value to index 37 | } 38 | 39 | ExamplePayload(const Notification& notification) 40 | : SpecializedPayload(notification) 41 | { 42 | } 43 | // 5. Method for receiving the notification 44 | const uint16 GetMyValue() const 45 | { 46 | return this->GetFieldValueAs( this->fieldIndexMyValue); 47 | } 48 | 49 | const String GetMyString() const 50 | { 51 | return this->GetFieldValueAs( this->fieldIndexMyString); 52 | } 53 | 54 | private: 55 | // 6. Define field index 56 | size_t fieldIndexMyValue = this->AddField(); 57 | size_t fieldIndexMyString = this->AddField(); 58 | 59 | }; 60 | 61 | } // end of namespace 62 | 63 | #endif /* EXAMPLEPAYLOAD_HPP_ */ 64 | -------------------------------------------------------------------------------- /Examples/NotificationExample/src/PG_ReactToNotification.cpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////" 2 | // 3 | // Copyright PHOENIX CONTACT Electronics GmbH 4 | // 5 | /////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "PG_ReactToNotification.hpp" 8 | #include "Arp/System/Commons/Logging.h" 9 | #include "Arp/System/Core/ByteConverter.hpp" 10 | 11 | namespace NotificationExample 12 | { 13 | 14 | void PG_ReactToNotification::Execute() 15 | { 16 | //implement program 17 | this->OP_uiInfoValue = this->cOMP_Notifications.OP_uiValue1; 18 | this->OP_uiWarningValue = this->cOMP_Notifications.OP_uiValue2; 19 | 20 | // Copy values from Component to Program 21 | 22 | // Do other stuff with component values 23 | // if(this->cOMP_Notifications.OP_uiValue1 >10){ 24 | // log.Info("Value1:{0}",this->cOMP_Notifications.OP_uiValue1); 25 | // log.Info("Value1:{0}",this->cOMP_Notifications.OP_uiValue2); 26 | // } 27 | } 28 | 29 | } // end of namespace NotificationExample 30 | -------------------------------------------------------------------------------- /Examples/NotificationExample/src/PG_ReactToNotification.hpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////" 2 | // 3 | // Copyright PHOENIX CONTACT Electronics GmbH 4 | // 5 | /////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | #include "Arp/System/Core/Arp.h" 9 | #include "Arp/Plc/Commons/Esm/ProgramBase.hpp" 10 | #include "Arp/System/Commons/Logging.h" 11 | #include "COMP_Notifications.hpp" 12 | 13 | namespace NotificationExample 14 | { 15 | 16 | using namespace Arp; 17 | using namespace Arp::System::Commons::Diagnostics::Logging; 18 | using namespace Arp::Plc::Commons::Esm; 19 | 20 | //#program 21 | //#component(NotificationExample::COMP_Notifications) 22 | class PG_ReactToNotification : public ProgramBase, private Loggable 23 | { 24 | public: // typedefs 25 | 26 | public: // construction/destruction 27 | PG_ReactToNotification(NotificationExample::COMP_Notifications& cOMP_NotificationsArg, const String& name); 28 | PG_ReactToNotification(const PG_ReactToNotification& arg) = delete; 29 | virtual ~PG_ReactToNotification() = default; 30 | 31 | public: // operators 32 | PG_ReactToNotification& operator=(const PG_ReactToNotification& arg) = delete; 33 | 34 | public: // properties 35 | 36 | public: // operations 37 | void Execute() override; 38 | 39 | public: /* Ports 40 | ===== 41 | Ports are defined in the following way: 42 | //#port 43 | //#attributes(Input|Retain) 44 | //#name(NameOfPort) 45 | boolean portField; 46 | 47 | The attributes comment define the port attributes and is optional. 48 | The name comment defines the name of the port and is optional. Default is the name of the field. 49 | */ 50 | //#port 51 | //#attributes(Output) 52 | uint16 OP_uiInfoValue = 0; 53 | 54 | //#port 55 | //#attributes(Output) 56 | uint16 OP_uiWarningValue = 0; 57 | 58 | private: // fields 59 | NotificationExample::COMP_Notifications& cOMP_Notifications; 60 | 61 | }; 62 | 63 | /////////////////////////////////////////////////////////////////////////////// 64 | // inline methods of class ProgramBase 65 | inline PG_ReactToNotification::PG_ReactToNotification(NotificationExample::COMP_Notifications& cOMP_NotificationsArg, const String& name) 66 | : ProgramBase(name) 67 | , cOMP_Notifications(cOMP_NotificationsArg) 68 | { 69 | } 70 | 71 | } // end of namespace NotificationExample 72 | -------------------------------------------------------------------------------- /Examples/NotificationExample/src/PG_SendNotification.cpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////" 2 | // 3 | // Copyright PHOENIX CONTACT Electronics GmbH 4 | // 5 | /////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "PG_SendNotification.hpp" 8 | #include "Arp/System/Commons/Logging.h" 9 | #include "Arp/System/Core/ByteConverter.hpp" 10 | 11 | namespace NotificationExample 12 | { 13 | // Get Time for time stamp 14 | Arp::DateTime PG_SendNotification::now() const 15 | { 16 | return DateTime::FromUnixTimeMicroseconds(std::chrono::duration_cast 17 | (std::chrono::system_clock::now().time_since_epoch()).count()); 18 | } 19 | 20 | 21 | void PG_SendNotification::Execute() 22 | { 23 | // Date time stamp in each cycle 24 | TimeStamp = now(); 25 | // Compare port value of "IP_uiInfoValue" with previous value to detect a change 26 | if(IP_uiInfoValue != uiPrevInfoValue) 27 | { 28 | MySenderRegistration1.SendNotificationWithTimestamp(TimeStamp, ExamplePayload{IP_uiInfoValue,"This is a placeholder message" }); 29 | uiPrevInfoValue = IP_uiInfoValue; 30 | } 31 | 32 | // Compare port value of "IP_uiWarningValue" with previous value to detect a change 33 | if(IP_uiWarningValue != uiPrevWarningValue) 34 | { 35 | String aStringVariable = "What happens when I pass in a String Variable"; 36 | MySenderRegistration2.SendNotificationWithTimestamp(TimeStamp, ExamplePayload{IP_uiWarningValue, aStringVariable}); 37 | aStringVariable = "And now I do change the String content."; 38 | aStringVariable = "And now I do change the String but make it way way way Loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooonger"; 39 | MySenderRegistration2.SendNotificationWithTimestamp(TimeStamp, ExamplePayload{IP_uiWarningValue, aStringVariable}); 40 | uiPrevWarningValue = IP_uiWarningValue; 41 | } 42 | 43 | } 44 | 45 | } // end of namespace NotificationExample 46 | -------------------------------------------------------------------------------- /Examples/NotificationExample/src/PG_SendNotification.hpp: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////////" 2 | // 3 | // Copyright PHOENIX CONTACT Electronics GmbH 4 | // 5 | /////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | #include "Arp/System/Core/Arp.h" 9 | #include "Arp/Plc/Commons/Esm/ProgramBase.hpp" 10 | #include "Arp/System/Commons/Logging.h" 11 | #include "COMP_Notifications.hpp" 12 | // 1. Added header files 13 | #include "Arp/System/Nm/NotificationManager.hpp" 14 | #include "ExamplePayload.hpp" 15 | 16 | 17 | namespace NotificationExample 18 | { 19 | 20 | using namespace Arp; 21 | using namespace Arp::System::Commons::Diagnostics::Logging; 22 | using namespace Arp::Plc::Commons::Esm; 23 | 24 | // 2. Added namespace use 25 | using namespace Arp::System::Nm; 26 | 27 | //#program 28 | //#component(NotificationExample::COMP_Notifications) 29 | class PG_SendNotification : public ProgramBase, private Loggable 30 | { 31 | public: // typedefs 32 | 33 | public: // construction/destruction 34 | PG_SendNotification(NotificationExample::COMP_Notifications& cOMP_NotificationsArg, const String& name); 35 | PG_SendNotification(const PG_SendNotification& arg) = delete; 36 | virtual ~PG_SendNotification() = default; 37 | 38 | public: // operators 39 | PG_SendNotification& operator=(const PG_SendNotification& arg) = delete; 40 | 41 | public: // properties 42 | 43 | public: // operations 44 | void Execute() override; 45 | 46 | private: 47 | // 3. Needed for the time stamp 48 | DateTime now() const; 49 | 50 | public: /* Ports 51 | ===== 52 | Ports are defined in the following way: 53 | //#port 54 | //#attributes(Input|Retain) 55 | //#name(NameOfPort) 56 | boolean portField; 57 | 58 | The attributes comment define the port attributes and is optional. 59 | The name comment defines the name of the port and is optional. Default is the name of the field. 60 | */ 61 | // 4. Added port variables 62 | //#port 63 | //#attributes(Input) 64 | uint16 IP_uiInfoValue = 0; 65 | 66 | //#port 67 | //#attributes(Input) 68 | uint16 IP_uiWarningValue = 0; 69 | 70 | // 5. Added local variables to save the previous value of the ports 71 | uint16 uiPrevInfoValue = 0; 72 | uint16 uiPrevWarningValue = 0; 73 | 74 | // 6. Manager instance and registrations 75 | NotificationManager& nm = NotificationManager::GetInstance(); 76 | NonBlockingNotificationRegistration MySenderRegistration1; // non-blocking needed because of real-time code execution 77 | NonBlockingNotificationRegistration MySenderRegistration2; 78 | 79 | private: // fields 80 | NotificationExample::COMP_Notifications& cOMP_Notifications; 81 | DateTime TimeStamp; // 7. Time stamp 82 | }; 83 | 84 | /////////////////////////////////////////////////////////////////////////////// 85 | // inline methods of class ProgramBase 86 | inline PG_SendNotification::PG_SendNotification(NotificationExample::COMP_Notifications& cOMP_NotificationsArg, const String& name) 87 | : ProgramBase(name) 88 | , cOMP_Notifications(cOMP_NotificationsArg) 89 | , MySenderRegistration1("My.NameSpace.1", name, Severity::Info, nm) // 8. Registrations for the two notifications to be sent 90 | , MySenderRegistration2("My.NameSpace.2", name, Severity::Warning, nm) 91 | { 92 | } 93 | 94 | } // end of namespace NotificationExample 95 | -------------------------------------------------------------------------------- /Examples/OpcPlcManager/README.MD: -------------------------------------------------------------------------------- 1 | # OPC UA Method Example 2 | 3 | ## Table of contents 4 | 5 | 6 | 7 | - [Introduction](#introduction) 8 | - [Guide details](#guide-details) 9 | - [Quick-start example](#quick-start-example) 10 | 11 | 12 | 13 | ## Introduction 14 | 15 | This example shows how to use OPC UA methods to execute functions in an ACF component written in C++. 16 | 17 | To understand how to create and use OPC UA methods with PLCnext Control devices, the following tutorial should be completed: 18 | 19 | https://github.com/PLCnext/OpcUaMethods 20 | 21 | The concepts and procedures demonstrated in that tutorial were used to prepare this example. 22 | 23 | This example also uses the [PLC Manager](https://api.plcnext.help/api_docs_2021-0-LTS/classArp_1_1Plc_1_1Domain_1_1Services_1_1IPlcManagerService2.html) RSC service. 24 | 25 | ## Guide details 26 | 27 | |Description | Value | 28 | |------------ |-----------| 29 | |Created | 19.03.2021 | 30 | |Last modified| 19.03.2021 | 31 | |Controller| AXC F 2152 | 32 | |FW| 2021.0.3 LTS | 33 | |Arpversion| 21.0.3.35554 | 34 | |SVN Revision| 35554 | 35 | |SDK| 2021.0.3 LTS (21.0.3.35554) | 36 | |PLCnext CLI | 21.0.0 LTS (21.0.0.489) | 37 | 38 | ## Quick-start example 39 | 40 | It is assumed that the user has some experience [building C++ Components and Programs for PLCnext Control](https://plcnext.help/te/Programming/Cplusplus/Cpp_programs_in_PLCnext.htm). 41 | 42 | Prerequisites: 43 | 44 | - AXC F x152 controller. 45 | 46 | - PLCnext Command Line Interface (CLI) tool, version 2021.0. This is included in the "PLCnext Technology C++ tool chain", available on the Phoenix Contact website. 47 | 48 | - A Software Development Kit (SDK) for the AXC F x152 PLCnext Control. This is also included in the "PLCnext Technology C++ tool chain". 49 | 50 | - PLCnext Engineer software. 51 | 52 | - (optional) Eclipse IDE, with the PLCnext Technology feature installed. 53 | 54 | - (optional) Visual Studio, with the PLCnext Technology add-in installed. 55 | 56 | - [UaExpert](https://www.unified-automation.com/products/development-tools/uaexpert.html) from Unified Automation. 57 | 58 | Procedure: 59 | 60 | - In PLCnext Engineer, create a new project based on the template for your PLC and firmware version. 61 | 62 | - Change the [OPC UA server settings](https://plcnext.help/te/Communication_interfaces/OPC_UA/OPCUA_server_configuration.htm) so that "Visibility of variables" is set to either "Marked" or "All". 63 | 64 | - Write and start the PLCnext Engineer project on the PLC. The only purpose of this PLCnext Engineer project is to configure the OPC UA server to make the GDS port variables, defined in our ACF component, available to OPC UA clients. 65 | 66 | - Clone this repository, e.g. 67 | 68 | ```sh 69 | git clone https://github.com/PLCnext/CppExamples.git 70 | ``` 71 | 72 | - Copy the OPC UA Node Set file to the PLC (replacing the IP address with the IP address of your PLC), e.g: 73 | 74 | ```sh 75 | cd CppExamples/Examples/OpcPlcManager 76 | scp PlcManager.xml admin@192.168.1.10:~/projects/Default/Services/OpcUA/NodeSets 77 | ``` 78 | 79 | This `.xml` file, in OPC UA Node Set format, defines the OPC UA methods that are implemented by our ACF component. 80 | 81 | - Create a new **ACF project** using either the PLCnext CLI tool, or Eclipse, or Visual Studio, with the following settings: 82 | - Project name: `OpcPlcManager` 83 | - Component name: `OpcPlcManagerComponent` 84 | - Project namespace: `OpcPlcManager` 85 | 86 | - Copy the contents of the `Examples/OpcPlcManager/src` directory in this repository, to the `src` directory of the ACF project. Replace the existing source files with the same name. 87 | 88 | - Build the ACF project. 89 | 90 | - Deploy the ACF project to the PLC, using the `.acf.config` file in the `Examples/OpcPlcManager/src` directory. This configuration file includes the name of the component instance that is referenced by the Node Set configuration file. 91 | 92 | - Restart the PLCnext Runtime. 93 | 94 | - Start UA Expert. 95 | 96 | - Connect to the OPC UA server on the PLC. 97 | 98 | - Call the methods in the "PlcManager" node to read the current PLC state, and to stop and start the PLC component of the PLCnext Runtime. 99 | 100 | ![Method](img/method.png) 101 | -------------------------------------------------------------------------------- /Examples/OpcPlcManager/img/method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/OpcPlcManager/img/method.png -------------------------------------------------------------------------------- /Examples/OpcPlcManager/src/OpcPlcManagerComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "OpcPlcManagerComponent.hpp" 2 | #include "Arp/Plc/Commons/Domain/PlcDomainProxy.hpp" 3 | #include "OpcPlcManagerLibrary.hpp" 4 | #include "Arp/System/Rsc/ServiceManager.hpp" 5 | 6 | namespace OpcPlcManager 7 | { 8 | 9 | using namespace Arp::Plc::Commons::Domain; 10 | using Arp::System::Rsc::ServiceManager; 11 | 12 | OpcPlcManagerComponent::OpcPlcManagerComponent(IApplication& application, const String& name) 13 | : ComponentBase(application, ::OpcPlcManager::OpcPlcManagerLibrary::GetInstance(), name, ComponentCategory::Custom) 14 | , MetaComponentBase(::OpcPlcManager::OpcPlcManagerLibrary::GetInstance().GetNamespace()) 15 | , workerThreadInstance(make_delegate(this, &OpcPlcManagerComponent::workerThreadBody) , 1000, "WorkerThreadName") 16 | { 17 | } 18 | 19 | void OpcPlcManagerComponent::Initialize() 20 | { 21 | // never remove next line 22 | PlcDomainProxy::GetInstance().RegisterComponent(*this, true); 23 | 24 | // subscribe events from the event system (Nm) here 25 | } 26 | 27 | void OpcPlcManagerComponent::SubscribeServices() 28 | { 29 | // gets the IDataAccessService pointer 30 | this->plcManagerService2Ptr = ServiceManager::GetService();} 31 | 32 | void OpcPlcManagerComponent::LoadSettings(const String& /*settingsPath*/) 33 | { 34 | // load firmware settings here 35 | } 36 | 37 | void OpcPlcManagerComponent::SetupSettings() 38 | { 39 | // never remove next line 40 | MetaComponentBase::SetupSettings(); 41 | 42 | // setup firmware settings here 43 | } 44 | 45 | void OpcPlcManagerComponent::PublishServices() 46 | { 47 | // publish the services of this component here 48 | } 49 | 50 | void OpcPlcManagerComponent::LoadConfig() 51 | { 52 | // load project config here 53 | } 54 | 55 | void OpcPlcManagerComponent::SetupConfig() 56 | { 57 | // setup project config here 58 | Log::Info("OpcPlcManagerComponent: Starting worker thread."); 59 | workerThreadInstance.Start(); 60 | } 61 | 62 | void OpcPlcManagerComponent::ResetConfig() 63 | { 64 | // implement this inverse to SetupConfig() and LoadConfig() 65 | Log::Info("OpcPlcManagerComponent: Stopping worker thread."); 66 | workerThreadInstance.Stop(); 67 | } 68 | 69 | void OpcPlcManagerComponent::Dispose() 70 | { 71 | // never remove next line 72 | MetaComponentBase::Dispose(); 73 | 74 | // implement this inverse to SetupSettings(), LoadSettings() and Initialize() 75 | } 76 | 77 | void OpcPlcManagerComponent::PowerDown() 78 | { 79 | // implement this only if data must be retained even on power down event 80 | } 81 | 82 | // Thread Body 83 | void OpcPlcManagerComponent::workerThreadBody(void) 84 | { 85 | // Check if each method has been called from the UA Client. 86 | // If so, call the corresponding method on the RSC service, 87 | // and return the result. 88 | 89 | if (this->GetPlcState.UA_MethodState == 1) 90 | { 91 | Log::Info("OpcPlcManagerComponent: GetPlcState."); 92 | 93 | // Get the PLC state from the RSC service 94 | this->GetPlcState.state = static_cast(this->plcManagerService2Ptr->GetPlcState()); 95 | 96 | // Signal that the method has completed successfully 97 | this->GetPlcState.UA_StatusCode = 0; 98 | this->GetPlcState.UA_MethodState = 0; 99 | } 100 | 101 | if (this->Start.UA_MethodState == 1) 102 | { 103 | Log::Info("OpcPlcManagerComponent: Start: {0:d} {1}", this->Start.startKind, (this->Start.async ? "asynchronous" : "synchronous")); 104 | 105 | // Start the PLC via the RSC service 106 | this->plcManagerService2Ptr->Start((PlcStartKind)this->Start.startKind, this->Start.async); 107 | 108 | // Signal that the method has completed successfully 109 | this->Start.UA_StatusCode = 0; 110 | this->Start.UA_MethodState = 0; 111 | } 112 | 113 | if (this->Stop.UA_MethodState == 1) 114 | { 115 | Log::Info("OpcPlcManagerComponent: Stop {0}.", (this->Stop.async ? "asynchronous" : "synchronous")); 116 | 117 | // Stop the PLC via the RSC service 118 | this->plcManagerService2Ptr->Stop(this->Stop.async); 119 | 120 | // Signal that the method has completed successfully 121 | this->Stop.UA_StatusCode = 0; 122 | this->Stop.UA_MethodState = 0; 123 | } 124 | } 125 | 126 | } // end of namespace OpcPlcManager 127 | -------------------------------------------------------------------------------- /Examples/OpcPlcManager/src/OpcPlcManagerComponent.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Arp/System/Core/Arp.h" 3 | #include "Arp/System/Acf/ComponentBase.hpp" 4 | #include "Arp/System/Acf/IApplication.hpp" 5 | #include "Arp/Plc/Commons/Meta/MetaComponentBase.hpp" 6 | #include "Arp/System/Commons/Logging.h" 7 | #include "Arp/System/Commons/Threading/WorkerThread.hpp" 8 | #include "Arp/Plc/Domain/Services/IPlcManagerService2.hpp" 9 | 10 | namespace OpcPlcManager 11 | { 12 | 13 | using namespace Arp; 14 | using namespace Arp::System::Acf; 15 | using namespace Arp::Plc::Commons::Meta; 16 | using namespace Arp::Plc::Domain::Services; 17 | using namespace Arp::System::Commons::Threading; 18 | 19 | //#acfcomponent 20 | class OpcPlcManagerComponent : public ComponentBase, public MetaComponentBase, private Loggable 21 | { 22 | public: // typedefs 23 | 24 | public: // construction/destruction 25 | OpcPlcManagerComponent(IApplication& application, const String& name); 26 | virtual ~OpcPlcManagerComponent() = default; 27 | 28 | public: // IComponent operations 29 | void Initialize() override; 30 | void SubscribeServices()override; 31 | void LoadSettings(const String& settingsPath)override; 32 | void SetupSettings()override; 33 | void PublishServices()override; 34 | void LoadConfig() override; 35 | void SetupConfig() override; 36 | void ResetConfig() override; 37 | void Dispose()override; 38 | void PowerDown()override; 39 | 40 | public: // MetaComponentBase operations 41 | void RegisterComponentPorts() override; 42 | 43 | private: // methods 44 | OpcPlcManagerComponent(const OpcPlcManagerComponent& arg) = delete; 45 | OpcPlcManagerComponent& operator= (const OpcPlcManagerComponent& arg) = delete; 46 | 47 | public: // static factory operations 48 | static IComponent::Ptr Create(Arp::System::Acf::IApplication& application, const String& name); 49 | 50 | private: // fields 51 | WorkerThread workerThreadInstance; 52 | IPlcManagerService2::Ptr plcManagerService2Ptr = nullptr; 53 | 54 | private: // methods 55 | void workerThreadBody(void); 56 | 57 | public: // ports 58 | 59 | // One struct is defined for each OPC UA method 60 | // Each struct contains the method input and output parameters, 61 | // and two special UA_* variables. 62 | 63 | struct GET_PLC_STATE 64 | { 65 | //#attributes(Input|Opc) 66 | Arp::int16 UA_MethodState = 0; 67 | 68 | //#attributes(Output|Opc) 69 | Arp::uint32 state = 0; 70 | //#attributes(Output|Opc) 71 | Arp::uint32 UA_StatusCode = 0; 72 | }; 73 | 74 | struct START 75 | { 76 | //#attributes(Input|Opc) 77 | Arp::uint8 startKind = 0; 78 | //#attributes(Input|Opc) 79 | Arp::boolean async = false; 80 | //#attributes(Input|Opc) 81 | Arp::int16 UA_MethodState = 0; 82 | 83 | //#attributes(Output|Opc) 84 | Arp::uint32 UA_StatusCode = 0; 85 | }; 86 | 87 | struct STOP 88 | { 89 | //#attributes(Input|Opc) 90 | Arp::boolean async = false; 91 | //#attributes(Input|Opc) 92 | Arp::int16 UA_MethodState = 0; 93 | 94 | //#attributes(Output|Opc) 95 | Arp::uint32 UA_StatusCode = 0; 96 | }; 97 | 98 | // Now the port variables themselves 99 | 100 | //#port 101 | GET_PLC_STATE GetPlcState; 102 | //#port 103 | START Start; 104 | //#port 105 | STOP Stop; 106 | }; 107 | 108 | inline IComponent::Ptr OpcPlcManagerComponent::Create(Arp::System::Acf::IApplication& application, const String& name) 109 | { 110 | return IComponent::Ptr(new OpcPlcManagerComponent(application, name)); 111 | } 112 | 113 | } // end of namespace OpcPlcManager 114 | -------------------------------------------------------------------------------- /Examples/OpcPlcManager/src/OpcPlcManagerLibrary.acf.config: -------------------------------------------------------------------------------- 1 |  2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_Interaction.pcwef: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_Interaction.pcwef -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/AXLF_Mast~Arp.Io.Axl~0000.libmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/AXLF_Mast~Arp.Io.Axl~0001.compmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Applikation~Profiles~0000.hmiprofiles: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Applikatio~Variables~0000.hmivar: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Applikati~Navigation~0000.hminav: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/CFG_1379F~PlmConfigu~0000.plmc: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/EIP_Maste~Arp.Io.Eth~0000.libmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/EIP_Maste~Controller~0000.compmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/HMI_Server~DataList~0000.dlr4hmi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | HmiTagRoleConfiguration.xml 5 | HmiTagDataListConfiguration.xml 6 | 7 | HmiTag 8 | Any 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Hardware~Description~0000.rtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Hardware~Description~0000.rtf -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Hardware~VersionHist~0000.usermeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Hardware~ba87f980-c6~0000.DataLink: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Hardware~ba87f980-c6~0001.Transport: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 192.168.1.2 5 | 192.168.254.254 6 | 7 | 255.255.0.0 8 | [UTF-8;6E6574776F726B3031] 9 | 10 | public 11 | private 12 | 13 | 2 14 | 1 15 | 16 | 1 17 | 18 | 19 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Hardware~ba87f980-c6~0002.projset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Hardware~ba87f980-c6~0002.projset -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/IB_Master~Arp.Io.Ib.~0000.compmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/IB_Master~Arp.Io.Ib~0000.libmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Logical Elemen~CRC32~0000.crc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Logical Elemen~CRC32~0000.crc -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Logical E~GeneratedD~0000.dt: -------------------------------------------------------------------------------- 1 | TYPE 2 | ByteArray35 : ARRAY[0..35] OF BYTE; 3 | END_TYPE 4 | TYPE 5 | IP_ADDRESS_ARRAY : ARRAY[0..3] OF BYTE; 6 | END_TYPE 7 | TYPE 8 | EIPD_IO_ARRAY : ARRAY[0..127] OF WORD; 9 | END_TYPE 10 | TYPE 11 | HMI_STATUS_STRUCT : STRUCT 12 | SESSION_ID : STRING; 13 | STATION_ID : STRING; 14 | LAST_REQ : LINT; 15 | IP_ADDRESS : IP_ADDRESS_ARRAY; 16 | END_STRUCT 17 | END_TYPE 18 | TYPE 19 | HMI_CONTROL_STRUCT : STRUCT 20 | DISABLE : BOOL; 21 | END_STRUCT 22 | END_TYPE 23 | TYPE 24 | HMI_STATUS_ARRAY : ARRAY[1..256] OF HMI_STATUS_STRUCT; 25 | END_TYPE 26 | TYPE 27 | HMI_CONTROL_ARRAY : ARRAY[1..256] OF HMI_CONTROL_STRUCT; 28 | END_TYPE 29 | TYPE 30 | HMI_STATUS_TYPE : STRUCT 31 | CLIENT_COUNT : UINT; 32 | CLIENTS : HMI_STATUS_ARRAY; 33 | END_STRUCT 34 | END_TYPE 35 | TYPE 36 | HMI_CONTROL_TYPE : STRUCT 37 | CLIENTS : HMI_CONTROL_ARRAY; 38 | END_STRUCT 39 | END_TYPE 40 | TYPE 41 | TASK_INFO : STRUCT 42 | INTERVAL : LINT; 43 | PRIORITY : INT; 44 | WATCHDOG : LINT; 45 | LAST_EXEC_DURATION : LINT; 46 | MIN_EXEC_DURATION : LINT; 47 | MAX_EXEC_DURATION : LINT; 48 | LAST_ACTIVATION_DELAY : LINT; 49 | MIN_ACTIVATION_DELAY : LINT; 50 | MAX_ACTIVATION_DELAY : LINT; 51 | EXEC_TIME_THRESHOLD : LINT; 52 | EXEC_TIME_THRESHOLD_CNT : UDINT; 53 | NAME : STRING; 54 | END_STRUCT 55 | END_TYPE 56 | TYPE 57 | TASK_INFO_ARRAY : ARRAY[1..16] OF TASK_INFO; 58 | END_TYPE 59 | TYPE 60 | ESM_INFO : STRUCT 61 | TASK_COUNT : UINT; 62 | TICK_COUNT : UDINT; 63 | TICK_INTERVAL : UDINT; 64 | TASK_INFOS : TASK_INFO_ARRAY; 65 | END_STRUCT 66 | END_TYPE 67 | TYPE 68 | STRING512 : STRING[512]; 69 | END_TYPE 70 | TYPE 71 | ESM_INFO_ARRAY : ARRAY[1..2] OF ESM_INFO; 72 | END_TYPE 73 | TYPE 74 | ESM_EXCEPTION_INFO : STRUCT 75 | TYPE_ID : UDINT; 76 | SUB_TYPE : STRING512; 77 | SUB_TYPE_ID : UDINT; 78 | TASK_NAME : STRING; 79 | PROGRAM_NAME : STRING512; 80 | INFORMATION : STRING512; 81 | END_STRUCT 82 | END_TYPE 83 | TYPE 84 | ESM_EXCEPTION_INFO_ARRAY : ARRAY[1..2] OF ESM_EXCEPTION_INFO; 85 | END_TYPE 86 | TYPE 87 | ESM_DAT : STRUCT 88 | ESM_COUNT : USINT; 89 | ESM_INFOS : ESM_INFO_ARRAY; 90 | EXCEPTION_COUNT : USINT; 91 | EXCEPTION_INFOS : ESM_EXCEPTION_INFO_ARRAY; 92 | END_STRUCT 93 | END_TYPE 94 | TYPE 95 | PND_IO_512 : ARRAY[0..511] OF BYTE; 96 | END_TYPE 97 | TYPE 98 | RTC_TYPE : STRUCT 99 | HOURS : USINT; 100 | MINUTES : USINT; 101 | SECONDS : USINT; 102 | DAY : USINT; 103 | MONTH : USINT; 104 | YEAR : UINT; 105 | END_STRUCT 106 | END_TYPE 107 | TYPE 108 | CPU_LOAD_PER_CORE_ARRAY : ARRAY[1..2] OF USINT; 109 | END_TYPE 110 | TYPE 111 | DEVICE_STATE_2152_TYPE : STRUCT 112 | BOARD_TEMPERATURE : SINT; 113 | reserved1 : BOOL; 114 | reserved2 : USINT; 115 | CPU_LOAD_ALL_CORES : USINT; 116 | CPU_LOAD_PER_CORE : CPU_LOAD_PER_CORE_ARRAY; 117 | END_STRUCT 118 | END_TYPE 119 | TYPE 120 | PARTITION_INFO : STRUCT 121 | MEM_TOTAL : ULINT; 122 | MEM_FREE : ULINT; 123 | MEM_USED : ULINT; 124 | MEM_USAGE : USINT; 125 | END_STRUCT 126 | END_TYPE 127 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/NewProgram.pou~Code~0000.st: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/NewProgram.pou~User~0000.locres: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/NewProgram.~Metadata~0000.meta: -------------------------------------------------------------------------------- 1 | 2 | 3 | PouFolder 4 | Program 5 | Program 6 | 8f648792-27a2-4e84-8378-3af2b74a2a08 7 | 8 | 9 | f46cd104-4648-4d0f-8a0f-9991cec10b07 10 | 11 | 12 | 85bc5479-e82e-4888-bc34-01cf44e7738a 13 | .st 14 | .st 15 | 0 16 | 17 | 18 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/NewProgram~Variables~0000.var: -------------------------------------------------------------------------------- 1 | { CustomGroupDefinition('2ac73918-d71f-4466-8d91-3ae704c794c5', '') } 2 | 3 | VAR_GLOBAL 4 | UP : INT { InputPort, CustomGroupReference('2ac73918-d71f-4466-8d91-3ae704c794c5') } {Id('c52fb3ef-8ec8-4e91-8e29-823769eae025')}; 5 | DOWN : INT { InputPort, CustomGroupReference('2ac73918-d71f-4466-8d91-3ae704c794c5') } {Id('69414510-27d8-41de-9e2b-001bbac52f35')}; 6 | END_VAR 7 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/NewProgra~Descriptio~0000.rtf: -------------------------------------------------------------------------------- 1 | {\rtf\ansi\ansicpg1252\uc1\deff0\deflang1033{\fonttbl{\f0 Verdana;}}{\colortbl\red0\green0\blue0 ;\red62\green61\blue64 ;}{\*\defchp\ltrch\f0\fs24\i0\b0\strike0\cf0\ulc0\ulnone}{\*\defpap\sl276\slmult1\ql\sa180\ltrpar}{\stylesheet{\s0\sqformat\spriority0\ltrch\f0\fs24\i0\b0\strike0\cf0\ulc0\ulnone\sl276\slmult1\ql\sa180\ltrpar Normal;}{\*\ts2\tsrowd\spriority59\trbrdrt\brdrnone\trbrdrb\brdrnone\trbrdrl\brdrnone\trbrdrr\brdrnone\trbrdrh\brdrnone\trbrdrv\brdrnone\trgaph0\trpaddl75\trpaddr75\trpaddt0\trpaddb0\clpadft3\clpadt0\clpadfr3\clpadr0\clpadfl3\clpadl0\clpadfb3\clpadb0\tsvertalt\ltrch\f0\fs24\i0\b0\strike0\cf0\ulc0\ulnone\sl276\slmult1\ql\sa180\ltrpar Table Normal;}}\nouicompat\viewkind4\paperw12240\paperh15840\margl1425\margr1425\margt1425\margb1425\deftab720\sectd\pgwsxn12240\pghsxn15840\marglsxn1425\margrsxn1425\margtsxn1425\margbsxn1425\headery720\footery720\pard\s0\sl276\slmult1\ql\sa180\ltrpar{\ltrch\f0\fs24\i0\b0\strike0\cf1\ulc0\ulnone\par}} -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/NewProgra~Descriptio~0001.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/NewProgra~Descriptio~0001.html -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/NewProgra~Variables.~0000.locres: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/NewProgra~VersionHis~0000.usermeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/PLCnext~6aff7cb6-d8e~0000.datalogger: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/PLCnext~EsmConfigura~0000.esmc: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/PN_Master~Arp.Io.Pn~0000.libmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/PN_Master~Controller~0000.compmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/RES_B9EDE5F~DataList~0000.dlr4var: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | VariableRoleConfiguration.xml 5 | VariableDataListConfiguration.xml 6 | 7 | Variable 8 | Any 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/RES_B9EDE~Arp.Plc.Ec~0000.libmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/RES_B9EDE~EclrCompon~0000.compmeta: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/RES_B9EDE~IOConfigur~0000.ioc: -------------------------------------------------------------------------------- 1 | (*********************************************************************) 2 | (* The following I/O configuration was generated by the application. *) 3 | (* Do not modify the lines below, any changes will be overwritten *) 4 | (* when they are regenerated. *) 5 | (*********************************************************************) 6 | 7 | (* No auto-generated I/O configuration available *) 8 | 9 | (*********************************************************************) 10 | (* End of auto-generated I/O configuration. User defined I/O groups *) 11 | (* can be defined after these lines. *) 12 | (*********************************************************************) 13 | 14 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/RES_B9EDE~ResourceSe~0000.set: -------------------------------------------------------------------------------- 1 | { Type('AXCF2152') } 2 | RESOURCE PLC 3 | { DeviceProfileWorksheet('DeviceProfile', Id := 'd1d1ed6c-9510-4a40-9e04-a070d1afd202') } 4 | { DeviceProfile( 5 | Name := 'RES_B9EDE5F589844181B5FD91D1F4D4C5D2', 6 | Parent := ( Name := 'AXCF2152', Version := '2021.0.0'), 7 | UpdateType := 'Manual', 8 | FilesIni := 9 | [ 10 | ], 11 | CommunicationMetadata := 'UniqueId=TCP/IP;IsBackup=False', 12 | DeviceDescription := 13 | ( 14 | MaxProgramSize := '8388608', 15 | MaxDataSize := '16777208', 16 | MaxRetainDataSize := '0', 17 | MaxTaskPriority := '96', 18 | Endianness := 'LittleEndian' 19 | ), 20 | CommunicationType := 'TcpIp', 21 | CommunicationParameters := 'DLL socomm.dll -ip192.168.1.10 -p41100 -to2000', 22 | DownloadFiles := 23 | [ 24 | ] 25 | )} 26 | 27 | 28 | TASK Task_1000ms (INTERVAL := T#1000ms, PRIORITY := 1) { Watchdog(T#800ms), Id('93b5ae55-56fd-4dec-9e38-7606355ecf2a') }; 29 | 30 | PROGRAM NewProgram1 WITH Task_1000ms : NewProgram { Id('0ab741d8-eae8-40ea-b965-8b2533288b14') }; 31 | 32 | END_RESOURCE 33 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Safety~0000.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Safety~0000/Inventori~SafetyInve~0000.xml: -------------------------------------------------------------------------------- 1 | Xc/cYMDtyH/tTOsSVUl9jCguhFU=SafetyInventory -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/Safety~0000/Logs~SafetyMessageLo~0000.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | lyLHa7HYCcWlkNe8iwy1ykJtdMc= 4 | 5 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/StorageContent~0000.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/content/StorageProperties~0000.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug_PCC_Interaction 4 | fc442b60-9552-4f7c-b9d5-0292568092a9 5 | Project 6 | 7 | Areas 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/PLCnextEngineer/Debug_PCC_InteractionFlat/structure.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/README.md: -------------------------------------------------------------------------------- 1 | # Program Component Interaction 2 | This example shows how data can be sent from a program to a component. 3 | The program can also receive data by calling public getter methods of the component. 4 | 5 | The *UpCounterProgram* and *DownCounterProgram* access the *CounterComponent* with these methods. 6 | They use the *CounterComponent.GetCommand()* to receive an *enum* of *Commands* and a *setProgress()* method to inform the component of the state of the program. 7 | Once the program has received a command it will continue to execute this command, and - when finished - execute the *CounterComponent.RefreshState()* method which will then initiate a state change. 8 | 9 | 36 | ![Sequence diagram](mermaid-diagram.svg "Sequence") 37 | 38 | ## Example details 39 | |Description | Value | 40 | |------------ |-----------| 41 | |Controller | AXC F 2152 | 42 | |FW | 2020.0 LTS or later | 43 | |SDK | 2020.0 LTS or later | 44 | |PLCnext Engineer | 2021.0 LTS or later | 45 | 46 | ## Preconditions 47 | 48 | - PLCnext Engineer is installed 49 | - PLCnext Technology SDK for C++ is installed 50 | 51 | ## Start-up instructions 52 | 53 | 1. Create one instance of each Program 54 | 2. Start the PLCnext Control 55 | 3. Login with PLCnext Engineer Debug or SSH. 56 | 4. Check progress 57 | 58 | You can now see the counters going up and down in the *PLCnext - Port List* window in PLCnext Engineer. The value of the `Down_Counter` port on the `DownCounterProgram` instance will decrement from 255 to zero, then the value of the `UP_Counter` port on the `UpCounterProgram` instance will increment from zero to 255. 59 | 60 | You can see also the progress in the *Output.log* file with `tail -f /opt/plcnext/logs/Output.log`. 61 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/src/CounterComponent.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Phoenix Contact GmbH & Co. KG. All rights reserved. 3 | // Licensed under the MIT. See LICENSE file in the project root for full license information. 4 | // 5 | 6 | #include "CounterComponent.hpp" 7 | #include "Arp/Plc/Commons/Esm/ProgramComponentBase.hpp" 8 | 9 | #include "ProgramComponentInteractionLibrary.hpp" 10 | 11 | namespace ProgramComponentInteraction 12 | { 13 | CounterComponent::CounterComponent(IApplication &application, const String &name) 14 | : ComponentBase(application, ::ProgramComponentInteraction::ProgramComponentInteractionLibrary::GetInstance(), name, ComponentCategory::Custom), 15 | programProvider(*this), 16 | ProgramComponentBase(::ProgramComponentInteraction::ProgramComponentInteractionLibrary::GetInstance().GetNamespace(), programProvider) 17 | { 18 | DEBUG_FUNCTION_CALL 19 | } 20 | 21 | void CounterComponent::Initialize() 22 | { 23 | // Allocate and initialize resources here 24 | // Remember to free all allocated resources in the Dispose() method 25 | DEBUG_FUNCTION_CALL 26 | // never remove next line 27 | ProgramComponentBase::Initialize(); 28 | } 29 | 30 | void CounterComponent::LoadConfig() 31 | { 32 | // Load project configuration here 33 | DEBUG_FUNCTION_CALL 34 | } 35 | 36 | void CounterComponent::SetupConfig() 37 | { 38 | // never remove next line 39 | ProgramComponentBase::SetupConfig(); 40 | 41 | // Setup project configuration here 42 | DEBUG_FUNCTION_CALL 43 | } 44 | 45 | void CounterComponent::ResetConfig() 46 | { 47 | // never remove next line 48 | ProgramComponentBase::ResetConfig(); 49 | 50 | DEBUG_FUNCTION_CALL 51 | this->dataInfoProvider.Reset(); 52 | } 53 | 54 | void CounterComponent::RefreshState() 55 | { 56 | DEBUG_FUNCTION_CALL 57 | // 58 | // When RefreshState is called the command gets toggled. 59 | // 60 | 61 | if (IP_Stop) // Component Port IP_Stop can set the Stop Command. 62 | { 63 | command = Command::Stop; 64 | } 65 | else 66 | { 67 | switch (command) 68 | { 69 | case Command::CountDown: 70 | { 71 | command = Command::CountUp; 72 | } 73 | break; 74 | 75 | case Command::CountUp: 76 | { 77 | command = Command::CountDown; 78 | } 79 | break; 80 | 81 | case Command::Stop: 82 | { 83 | command = Command::CountDown; 84 | } 85 | break; 86 | } 87 | } 88 | // Print command and progress to the Output.log file 89 | log.Info("command: {2} progress_DC: {0} progress_UC: {1}", (int)progress_DC, progress_UC, (int)command); 90 | } 91 | 92 | } // namespace ProgramComponentInteraction 93 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/src/CounterComponent.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Phoenix Contact GmbH & Co. KG. All rights reserved. 3 | // Licensed under the MIT. See LICENSE file in the project root for full license information. 4 | // 5 | #pragma once 6 | 7 | #include "Arp/System/Core/Arp.h" 8 | #include "Arp/System/Acf/ComponentBase.hpp" 9 | #include "Arp/System/Acf/IApplication.hpp" 10 | #include "Arp/Plc/Commons/Esm/ProgramComponentBase.hpp" 11 | #include "CounterComponentProgramProvider.hpp" 12 | #include "Arp/Plc/Commons/Meta/MetaLibraryBase.hpp" 13 | #include "Arp/System/Commons/Logging.h" 14 | 15 | #include "Helpers/Enums.hpp" 16 | 17 | namespace ProgramComponentInteraction // Library name 18 | { 19 | 20 | using namespace Arp; 21 | using namespace Arp::System::Acf; 22 | using namespace Arp::Plc::Commons::Esm; 23 | using namespace Arp::Plc::Commons::Meta; 24 | 25 | #ifdef DEBUG 26 | #define DEBUG_FUNCTION_CALL log.Info("'{0}' invoked of object with instance name '{1}'", __FUNCTION__, this->GetFullName()); 27 | #else 28 | #define DEBUG_FUNCTION_CALL 29 | #endif 30 | 31 | //#component 32 | class CounterComponent : public ComponentBase, public ProgramComponentBase, private Loggable 33 | { 34 | 35 | public: // typedefs 36 | 37 | public: // construction/destruction 38 | CounterComponent(IApplication &application, const String &name); 39 | virtual ~CounterComponent() = default; 40 | 41 | public: // IComponent operations 42 | void Initialize(void) override; 43 | void LoadConfig(void) override; 44 | void SetupConfig(void) override; 45 | void ResetConfig(void) override; 46 | 47 | private: // ProgramComponentBase 48 | void RegisterComponentPorts() override; 49 | 50 | private: // methods 51 | CounterComponent(const CounterComponent &arg) = delete; 52 | CounterComponent &operator=(const CounterComponent &arg) = delete; 53 | 54 | public: // static factory operations 55 | static IComponent::Ptr Create(Arp::System::Acf::IApplication &application, const String &name); 56 | 57 | private: // fields 58 | CounterComponentProgramProvider programProvider; 59 | 60 | public: // Component Interaction operations 61 | /// Toggles the Command 62 | void RefreshState(); 63 | 64 | // Set progress of the DownCounterProgram 65 | void SetProgressDC(Progress p) { progress_DC = p; } 66 | // Set progress of the UpCounterProgram 67 | void SetProgressUC(Progress p) { progress_UC = p; } 68 | 69 | // returns the current command 70 | Command GetCommand(void) { return command; } 71 | 72 | private: // member variables for Program Component Interaction 73 | Progress progress_UC = Progress::Stopped; 74 | Progress progress_DC = Progress::Stopped; 75 | Command command{Command::CountDown}; 76 | 77 | public: // ports 78 | 79 | //#port 80 | //#name(StopCounting) 81 | boolean IP_Stop{false}; 82 | }; 83 | 84 | /////////////////////////////////////////////////////////////////////////////// 85 | // inline methods of class CounterComponent 86 | inline IComponent::Ptr CounterComponent::Create(Arp::System::Acf::IApplication &application, const String &name) 87 | { 88 | return IComponent::Ptr(new CounterComponent(application, name)); 89 | } 90 | 91 | } // end of namespace ProgramComponentInteraction 92 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/src/Helpers/Enums.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Phoenix Contact GmbH & Co. KG. All rights reserved. 3 | // Licensed under the MIT. See LICENSE file in the project root for full license information. 4 | // 5 | #pragma once 6 | namespace ProgramComponentInteraction // Library name 7 | { 8 | enum Progress 9 | { 10 | Running, 11 | Done, 12 | Stopped 13 | }; 14 | 15 | enum Command 16 | { 17 | CountUp, 18 | CountDown, 19 | Stop 20 | 21 | }; 22 | } -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/src/Programs/DownCounterProgram.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Phoenix Contact GmbH & Co. KG. All rights reserved. 3 | // Licensed under the MIT. See LICENSE file in the project root for full license information. 4 | // 5 | #include "DownCounterProgram.hpp" 6 | #include "Arp/System/Commons/Logging.h" 7 | #include "Arp/System/Core/ByteConverter.hpp" 8 | 9 | namespace ProgramComponentInteraction 10 | { 11 | 12 | 13 | void DownCounterProgram::Execute() 14 | { 15 | // Print the current progress and the counter value to the Output.log file 16 | Command c = refCounterComponent.GetCommand(); 17 | 18 | switch(progress) 19 | { 20 | // Check if counting shall be started next cycle 21 | case Progress::Done : // idle state 22 | { 23 | 24 | // access GetCommand() funktion of the Component via reference. 25 | if( c == Command::CountDown) 26 | { 27 | log.Info("DC Start"); 28 | progress = Progress::Running; 29 | } 30 | break; 31 | } 32 | // Decrement the OP_Counter 33 | case Progress::Running : 34 | { 35 | this->OP_Counter--; 36 | if( this->OP_Counter <= 0 ) 37 | { 38 | progress = Progress::Stopped; 39 | } 40 | break; 41 | } 42 | // Reset the Counter 43 | case Progress::Stopped :// reinitialize state 44 | { 45 | log.Info("DC Done"); 46 | this->OP_Counter = 255; 47 | refCounterComponent.RefreshState(); 48 | progress = Progress::Done; 49 | break; 50 | } 51 | 52 | default : 53 | progress = Progress::Stopped; 54 | break; 55 | } 56 | 57 | // Push the current progress to the component. 58 | refCounterComponent.SetProgressDC(progress); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/src/Programs/DownCounterProgram.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Phoenix Contact GmbH & Co. KG. All rights reserved. 3 | // Licensed under the MIT. See LICENSE file in the project root for full license information. 4 | // 5 | #pragma once 6 | #include "Arp/System/Core/Arp.h" 7 | #include "Arp/Plc/Commons/Esm/ProgramBase.hpp" 8 | #include "Arp/System/Commons/Logging.h" 9 | #include "../Helpers/Enums.hpp" 10 | 11 | 12 | #include "../CounterComponent.hpp" 13 | 14 | 15 | namespace ProgramComponentInteraction 16 | { 17 | using namespace Arp; 18 | using namespace Arp::System::Commons::Diagnostics::Logging; 19 | using namespace Arp::Plc::Commons::Esm; 20 | 21 | 22 | // Asigning Program to component for the PLCNCLI 23 | //#program 24 | //#component(ProgramComponentInteraction::CounterComponent) 25 | class DownCounterProgram : 26 | public ProgramBase , 27 | private Loggable 28 | { 29 | public: // typedefs 30 | 31 | public: // construction/destruction 32 | DownCounterProgram(CounterComponent& refCounterComponentArg, const String& name); 33 | DownCounterProgram(const DownCounterProgram& arg) = delete; 34 | virtual ~DownCounterProgram(void) = default; 35 | 36 | public: // operators 37 | DownCounterProgram& operator=(const DownCounterProgram& arg) = delete; 38 | 39 | public: // properties 40 | 41 | public: // operations 42 | void Execute(void)override; 43 | 44 | private: // fields 45 | CounterComponent& refCounterComponent; 46 | Progress progress = Progress::Done; 47 | // IComponentInteraction& const CCRef= nullptr; 48 | public: 49 | //#port 50 | //#attributes(Output|Retain) 51 | //#name(Down_Counter) 52 | uint8 OP_Counter = 255; 53 | }; 54 | 55 | /////////////////////////////////////////////////////////////////////////////// 56 | // inline methods of class DownCounterProgram 57 | inline DownCounterProgram::DownCounterProgram(CounterComponent& refCounterComponentArg, const String& name) 58 | : ProgramBase(name) 59 | , refCounterComponent(refCounterComponentArg) 60 | { 61 | log.Info("DC Constructor"); 62 | } 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/src/Programs/UpCounterProgram.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Phoenix Contact GmbH & Co. KG. All rights reserved. 3 | // Licensed under the MIT. See LICENSE file in the project root for full license information. 4 | // 5 | #include "UpCounterProgram.hpp" 6 | #include "Arp/System/Commons/Logging.h" 7 | #include "Arp/System/Core/ByteConverter.hpp" 8 | 9 | namespace ProgramComponentInteraction 10 | { 11 | 12 | void UpCounterProgram::Execute() 13 | { 14 | Command c = refCounterComponent.GetCommand(); 15 | 16 | // This method will be executed each cycle 17 | // We just increase the counter by one here 18 | switch(progress) 19 | { 20 | // Check if counting shall be started next cycle 21 | case Progress::Done :// idle state 22 | { 23 | 24 | if( c == Command::CountUp) 25 | { log.Info("UC Start"); 26 | progress = Progress::Running; 27 | } 28 | break; 29 | } 30 | // Count Up 31 | case Progress::Running : 32 | { 33 | this->OP_Counter++; 34 | if( this->OP_Counter >= 255 ) 35 | { 36 | progress = Progress::Stopped; 37 | } 38 | break; 39 | } 40 | // Reset the Counter 41 | case Progress::Stopped :// reinitialize state 42 | { 43 | log.Info("UC Done"); 44 | this->OP_Counter = 0; 45 | refCounterComponent.RefreshState(); 46 | progress = Progress::Done; 47 | break; 48 | } 49 | 50 | default : 51 | progress = Progress::Stopped; 52 | break; 53 | } 54 | // Push the Progress to the Component. 55 | refCounterComponent.SetProgressUC(progress); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Examples/ProgramComponentInteraction/src/Programs/UpCounterProgram.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Phoenix Contact GmbH & Co. KG. All rights reserved. 3 | // Licensed under the MIT. See LICENSE file in the project root for full license information. 4 | // 5 | #pragma once 6 | #include "Arp/System/Core/Arp.h" 7 | #include "Arp/Plc/Commons/Esm/ProgramBase.hpp" 8 | #include "Arp/System/Commons/Logging.h" 9 | #include "../Helpers/Enums.hpp" 10 | 11 | 12 | #include "../CounterComponent.hpp" 13 | 14 | namespace ProgramComponentInteraction 15 | { 16 | using namespace Arp; 17 | using namespace Arp::System::Commons::Diagnostics::Logging; 18 | using namespace Arp::Plc::Commons::Esm; 19 | 20 | 21 | 22 | // Asigning Program to component for the PLCNCLI 23 | //#program 24 | //#component(ProgramComponentInteraction::CounterComponent) 25 | class UpCounterProgram: 26 | public ProgramBase, 27 | private Loggable 28 | { 29 | public: // typedefs 30 | 31 | public: // construction/destruction 32 | UpCounterProgram(CounterComponent& refCounterComponentArg, const String& name); 33 | UpCounterProgram(const UpCounterProgram& arg) = delete; 34 | virtual ~UpCounterProgram() = default; 35 | 36 | 37 | public: // operators 38 | UpCounterProgram& operator=(const UpCounterProgram& arg) = delete; 39 | 40 | public: // properties 41 | 42 | 43 | public: // operations 44 | void Execute(void)override; 45 | 46 | private: // fields 47 | CounterComponent& refCounterComponent; 48 | Progress progress = Progress::Done; 49 | 50 | public: 51 | //#port 52 | //#attributes(Output|Retain) 53 | //#name(UP_Counter) 54 | uint8 OP_Counter = 0; 55 | }; 56 | 57 | /////////////////////////////////////////////////////////////////////////////// 58 | // inline methods of class UpCounterProgram 59 | inline UpCounterProgram::UpCounterProgram(CounterComponent& refCounterComponentArg, const String& name) 60 | : ProgramBase(name) 61 | , refCounterComponent(refCounterComponentArg) 62 | { 63 | log.Info("UC Constructor"); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Examples/Subscriptions/SubscriptionData.pcwlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PLCnext/CppExamples/b7f67b8277981d76f1abfba2109835ecb20c842a/Examples/Subscriptions/SubscriptionData.pcwlx -------------------------------------------------------------------------------- /Examples/Subscriptions/src/Internal/TimestampedValue.hpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Copyright PHOENIX CONTACT Electronics GmbH 4 | // 5 | /////////////////////////////////////////////////////////////////////////////// 6 | #pragma once 7 | #include "Arp/System/Core/Arp.h" 8 | 9 | namespace Subscriptions { namespace Internal 10 | { 11 | 12 | using namespace Arp; 13 | 14 | struct TimestampedValue 15 | { 16 | String varName; 17 | DateTime timestamp; 18 | uint16 value; 19 | }; 20 | 21 | }} // end of namespace Subscriptions::Internal 22 | -------------------------------------------------------------------------------- /Examples/ThreadExample/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | intermediate 3 | external 4 | CMakeLists.txt 5 | plcnext.proj 6 | -------------------------------------------------------------------------------- /Examples/ThreadExample/src/ThreadExampleProgram.cpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Copyright (c) Phoenix Contact GmbH & Co. KG. All rights reserved. 4 | * Licensed under the MIT. See LICENSE file in the project root for full license information. 5 | * 6 | * ThreadExampleProgram.cpp 7 | * 8 | * Created on: 16.05.2019 9 | * Author: Eduard Münz, Oliver Warneke 10 | * 11 | ******************************************************************************/ 12 | 13 | /******************************************************************************/ 14 | /* INCLUDES */ 15 | /******************************************************************************/ 16 | 17 | #include "ThreadExampleProgram.hpp" 18 | #include "Arp/System/Commons/Logging.h" 19 | #include "Arp/System/Core/ByteConverter.hpp" 20 | 21 | namespace ThreadExample 22 | { 23 | 24 | void ThreadExampleProgram::Execute() 25 | { 26 | //implement program 27 | i_pCounter = threadExampleComponent.GetCounterValue(); 28 | Log::Info("-------------------------------Program Cyclic Call: i_pCounter = {0}", i_pCounter); 29 | 30 | } 31 | 32 | } // end of namespace ThreadExample 33 | -------------------------------------------------------------------------------- /Examples/ThreadExample/src/ThreadExampleProgram.hpp: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * 3 | * Copyright (c) Phoenix Contact GmbH & Co. KG. All rights reserved. 4 | * Licensed under the MIT. See LICENSE file in the project root for full license information. 5 | * 6 | * ThreadExampleProgram.hpp 7 | * 8 | * Created on: 16.05.2019 9 | * Author: Eduard Münz, Oliver Warneke 10 | * 11 | ******************************************************************************/ 12 | 13 | /******************************************************************************/ 14 | /* INCLUDES */ 15 | /******************************************************************************/ 16 | 17 | 18 | #pragma once 19 | #include "Arp/System/Core/Arp.h" 20 | #include "Arp/Plc/Commons/Esm/ProgramBase.hpp" 21 | #include "Arp/System/Commons/Logging.h" 22 | #include "ThreadExampleComponent.hpp" 23 | 24 | namespace ThreadExample 25 | { 26 | 27 | using namespace Arp; 28 | using namespace Arp::System::Commons::Diagnostics::Logging; 29 | using namespace Arp::Plc::Commons::Esm; 30 | 31 | //#program 32 | //#component(ThreadExample::ThreadExampleComponent) 33 | class ThreadExampleProgram : public ProgramBase, private Loggable 34 | { 35 | public: // typedefs 36 | 37 | public: // construction/destruction 38 | ThreadExampleProgram(ThreadExample::ThreadExampleComponent& threadExampleComponentArg, const String& name); 39 | ThreadExampleProgram(const ThreadExampleProgram& arg) = delete; 40 | virtual ~ThreadExampleProgram() = default; 41 | 42 | public: // operators 43 | ThreadExampleProgram& operator=(const ThreadExampleProgram& arg) = delete; 44 | 45 | public: // properties 46 | 47 | public: // operations 48 | void Execute() override; 49 | 50 | public: /* Ports 51 | ===== 52 | Ports are defined in the following way: 53 | //#port 54 | //#attributes(Input|Retain) 55 | //#name(NameOfPort) 56 | boolean portField; 57 | 58 | The attributes comment define the port attributes and is optional. 59 | The name comment defines the name of the port and is optional. Default is the name of the field. 60 | */ 61 | 62 | //#port 63 | //#attributes(Output|Retain) 64 | //#name(i_pCounter) 65 | int16 i_pCounter; 66 | 67 | private: // fields 68 | ThreadExample::ThreadExampleComponent& threadExampleComponent; 69 | 70 | }; 71 | 72 | /////////////////////////////////////////////////////////////////////////////// 73 | // inline methods of class ProgramBase 74 | inline ThreadExampleProgram::ThreadExampleProgram(ThreadExample::ThreadExampleComponent& threadExampleComponentArg, const String& name) 75 | : ProgramBase(name) 76 | , threadExampleComponent(threadExampleComponentArg) 77 | { 78 | } 79 | 80 | } // end of namespace ThreadExample 81 | -------------------------------------------------------------------------------- /Examples/TraceControl/README.MD: -------------------------------------------------------------------------------- 1 | # Trace Controller Service 2 | 3 | ## Table of contents 4 | 5 | 6 | 7 | - [Introduction](#introduction) 8 | - [Guide details](#guide-details) 9 | - [References](#references) 10 | - [Quick-start example](#quick-start-example) 11 | 12 | 13 | 14 | ## Introduction 15 | 16 | The PLCnext Runtime provides an RSC service, called `ITraceControllerService`, that a client application written in C++ can use to manage LTTng trace sessions. This example demonstrates the use of the Trace Controller service using an LTTng trace configuration file that is installed on every PLCnext Control device. This example provides an alternative to the manual setup of the same LTTng configuration, described in the following Knowledge Base article: 17 | 18 | [How to activate the PLCnext Trace Controller (LTTtng)](https://pxc1.esc-eu-central-1.empolisservices.com/gatekeeper/guesttoken/45?app=/service-express/portal/cb?redirect=https://pxc1.esc-eu-central-1.empolisservices.com/service-express/portal/object/esc/en-so-5a5c4287-9d80-4116-9b0a-9b4f01fbc0f7) 19 | 20 | When started, the LTTng session described in the configuration file creates a snapshot trace when triggered by specific fault conditions on the device. 21 | 22 | As with the knowledge base article, this example is not intended to describe how LTTng works, or how to create LTTng configurations, or how to analyse LTTng trace results. 23 | 24 | ## Guide details 25 | 26 | |Description | Value | 27 | |------------ |-----------| 28 | |Created | 4.05.2021 | 29 | |Last modified| 4.05.2021 | 30 | |Controller| AXC F 2152 | 31 | |FW| 2021.0.3 LTS | 32 | |Arpversion| 21.0.3.35554 | 33 | |SVN Revision| 35554 | 34 | |SDK| 2021.0.3 LTS (21.0.3.35554) | 35 | |PLCnext CLI | 21.0.0 LTS (21.0.0.489) | 36 | 37 | ## References 38 | 39 | A complete description of the Trace Controller service is available from this source: 40 | 41 | - [API documentation](https://api.plcnext.help/api_docs_2021-0-LTS/classArp_1_1System_1_1Commons_1_1Diagnostics_1_1TraceController.html) 42 | 43 | General information on LTTng is available from the [LTTng website](https://lttng.org/). 44 | 45 | ## Quick-start example 46 | 47 | This example demonstrates features of the Trace Controller RSC service. 48 | 49 | It is assumed that the user has some experience [building C++ Components and Programs for PLCnext Control](https://www.plcnext.help/te/Programming/Cpp/Cpp_programming/Cpp_programs_in_PLCnext.htm). 50 | 51 | Prerequisites: 52 | 53 | - AXC F x152 controller. 54 | 55 | - PLCnext Command Line Interface (CLI) tool, version 2021.0. This is included in the "PLCnext Technology C++ tool chain", available on the Phoenix Contact website. 56 | 57 | - A Software Development Kit (SDK) for the AXC F 2152 PLCnext Control, version 2021.0.0 or later. This is also included in the "PLCnext Technology C++ tool chain". 58 | 59 | - (optional) Eclipse IDE, with the PLCnext Technology feature installed. 60 | 61 | - (optional) Visual Studio, with the PLCnext Technology add-in installed. 62 | 63 | Procedure: 64 | 65 | - Clone this repository, e.g. 66 | 67 | ```sh 68 | git clone https://github.com/PLCnext/CppExamples.git 69 | ``` 70 | 71 | - Create a new **ACF project** using either the PLCnext CLI tool, or Eclipse, or Visual Studio, with the following settings: 72 | - Project name: `TraceControl` 73 | - Component name: `TraceControlComponent` 74 | - Project namespace: `TraceControl` 75 | 76 | - Copy the contents of the `Examples/TraceControl/src` directory in this repository, to the `src` directory of the ACF project. Replace the existing source files with the same name. 77 | 78 | - Build the ACF project. 79 | 80 | - Deploy the ACF project to the PLC. 81 | 82 | - Restart the PLCnext Runtime. 83 | 84 | - Check the contents of the file `/opt/plcnext/logs/Output.log`. It should contain messages from your ACF component. In the component source code, you can see where these messages are generated in each step of the call sequence. 85 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Phoenix Contact GmbH & Co KG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # MAINTAINER 2 | 3 | Marcel Luhmann - OSSPLCnext@phoenixcontact.com 4 | Oliver Warneke - OSSPLCnext@phoenixcontact.com -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Vulnerablitiys 2 | 3 | Phoenix Contact provides a process to report security issues. 4 | Please visit the website for the [Phoenix Contact PSIRT](https://phoenixcontact.com/psirt) process and follow the instructions. -------------------------------------------------------------------------------- /tools/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # How To use: 4 | # Navigate into the ExampleFolder(cd ~/CppExamples/Examples/CppDataTypeTest) and execute this script. 5 | # please set the version and target you wish to add. 6 | # 7 | 8 | # Chose project 9 | plcncli new project -c DummyC -p DummyP && ls -la src && rm src/Dummy* 10 | # or acfproject 11 | #plcncli new acfproject -c DummyC && ls -la src && rm src/Dummy* 12 | 13 | 14 | # Chose target name and version 15 | plcncli set target --add --name AXCF2152 --version 2021.6 16 | 17 | # Generate Intermediate files 18 | plcncli generate all 19 | plcncli build 20 | plcncli deploy 21 | --------------------------------------------------------------------------------