Tutorial to add IO nodes for Embedded OPC UA Server that represents ioThinx-4533 device IO modules status.
Table of Contents
* Beginners Guide
* User Scenario 1
* User Scenario 2
* User Scenario 3
* Compile Guide
* Appendix and FAQ
Beginners Guide
If you are a total beginner to this, start here!
- make sure your firmware version is above or equal to V1.1
- download embeddedopcuaserver-plugin-dev_<version>_armhf.deb to 4533
- install embeddedopcuaserver-plugin-dev_<version>_armhf.deb
1 dpkg -i embeddedopcuaserver-plugin-dev_<version>_armhf.deb
- Check io.conf under
/usr/local/bin/embeddedopcuaserver/Config
fits your ioThinx-4533 IO modules layout
- Execute
systemctl start embedded-opcua-server
to run up server
- Start using OPC UA client to browse IO data
User Scenario
User Scenario 1: Add an diStatus node(config only)
Add Slot 1/Channel 4 diStatus to OPC UA Server, just modify io.conf under /usr/local/bin/embeddedopcuaserver/Config
to
5 {"ch": 0, "access": 1, "variant_type": 3, "func_type": 10, "name": "diMode", "description": "di mode"},
6 {"ch": 0, "access": 1, "variant_type": 3, "func_type": 11, "name": "diStatus", "description": "di status"},
7 {"ch": 1, "access": 1, "variant_type": 3, "func_type": 11, "name": "diStatus", "description": "di status"},
8 {"ch": 2, "access": 1, "variant_type": 3, "func_type": 11, "name": "diStatus", "description": "di status"},
9 {"ch": 3, "access": 3, "variant_type": 3, "func_type": 12, "name": "diCounterStatus", "description": "di counter status"},
10 {"ch": 3, "access": 3, "variant_type": 7, "func_type": 13, "name": "diCounterValue", "description": "di counter value"},
11 {"ch": 4, "access": 1, "variant_type": 3, "func_type": 11, "name": "diStatus", "description": "di status"}
Please notice:
- slot 1 must be 45MR-1600/45MR-1601/45MR-2606
- follow json format to add your own node
User Scenario 2: Change module slot order(config only)
Adjust io.config to follow ioThinx-4533 real hardware modules order. Now slot 1 is 45MR-1600 and slot 2 is 45MR-2600 which the io.conf may looks like below.
5 {"ch": 0, "access": 1, "variant_type": 3, "func_type": 10, "name": "diMode", "description": "di mode"},
6 {"ch": 0, "access": 1, "variant_type": 3, "func_type": 11, "name": "diStatus", "description": "di status"},
7 {"ch": 1, "access": 1, "variant_type": 3, "func_type": 11, "name": "diStatus", "description": "di status"},
8 {"ch": 2, "access": 1, "variant_type": 3, "func_type": 11, "name": "diStatus", "description": "di status"},
9 {"ch": 3, "access": 3, "variant_type": 3, "func_type": 12, "name": "diCounterStatus", "description": "di counter status"},
10 {"ch": 3, "access": 3, "variant_type": 7, "func_type": 13, "name": "diCounterValue", "description": "di counter value"},
11 {"ch": 4, "access": 1, "variant_type": 3, "func_type": 11, "name": "diStatus", "description": "di status"}
14 {"ch": 0, "access": 1, "variant_type": 3, "func_type": 20, "name": "doMode", "description": "do mode"},
15 {"ch": 0, "access": 3, "variant_type": 3, "func_type": 21, "name": "doStatus", "description": "do status"},
16 {"ch": 1, "access": 3, "variant_type": 3, "func_type": 21, "name": "doStatus", "description": "do status"},
17 {"ch": 2, "access": 3, "variant_type": 3, "func_type": 22, "name": "doPulseStatus", "description": "do pluse status"},
18 {"ch": 2, "access": 3, "variant_type": 7, "func_type": 23, "name": "doPulseCount", "description": "do pluse count"},
19 {"ch": 3, "access": 3, "variant_type": 3, "func_type": 22, "name": "doPulseStatus", "description": "do pluse status"},
20 {"ch": 3, "access": 3, "variant_type": 7, "func_type": 23, "name": "doPulseCount", "description": "do pluse count"}
Now switch slot 1 and slot 2 and insert an 45MR-2404 in between which make ioThinx-4533 hardware modules order into slot 1: 45MR-2600, slot 2: 45MR-2404, slot 3: 45MR-1600 and if we don't want to monitor 45MR-2404, the io.conf may replace like below.
5 {"ch": 0, "access": 1, "variant_type": 3, "func_type": 20, "name": "doMode", "description": "do mode"},
6 {"ch": 0, "access": 3, "variant_type": 3, "func_type": 21, "name": "doStatus", "description": "do status"},
7 {"ch": 1, "access": 3, "variant_type": 3, "func_type": 21, "name": "doStatus", "description": "do status"},
8 {"ch": 2, "access": 3, "variant_type": 3, "func_type": 22, "name": "doPulseStatus", "description": "do pluse status"},
9 {"ch": 2, "access": 3, "variant_type": 7, "func_type": 23, "name": "doPulseCount", "description": "do pluse count"},
10 {"ch": 3, "access": 3, "variant_type": 3, "func_type": 22, "name": "doPulseStatus", "description": "do pluse status"},
11 {"ch": 3, "access": 3, "variant_type": 7, "func_type": 23, "name": "doPulseCount", "description": "do pluse count"}
15 {"ch": 0, "access": 1, "variant_type": 3, "func_type": 10, "name": "diMode", "description": "di mode"},
16 {"ch": 0, "access": 1, "variant_type": 3, "func_type": 11, "name": "diStatus", "description": "di status"},
17 {"ch": 1, "access": 1, "variant_type": 3, "func_type": 11, "name": "diStatus", "description": "di status"},
18 {"ch": 2, "access": 1, "variant_type": 3, "func_type": 11, "name": "diStatus", "description": "di status"},
19 {"ch": 3, "access": 3, "variant_type": 3, "func_type": 12, "name": "diCounterStatus", "description": "di counter status"},
20 {"ch": 3, "access": 3, "variant_type": 7, "func_type": 13, "name": "diCounterValue", "description": "di counter value"},
21 {"ch": 4, "access": 1, "variant_type": 3, "func_type": 11, "name": "diStatus", "description": "di status"}
Please notice:
- slot order is start from 0 and slot 0 means the node from CPU head
- if this io module is no need to be monitor by OPC UA Server, then give an null in the io.conf
User Scenario 3: Add new IO func_type (coding & config)
Define new FUNC_TYPE in DataSet.h
and add read/write function case in io_control_read()
and io_control_write()
of io_node_operator.c
. If this io data need to be configured first during the initialization, then configure function should be add in add_io_nodes()
.
Modify io.conf
to load hello do info and add new func_type 99 as below.
5 {"ch": 0, "access": 1, "variant_type": 3, "func_type": 20, "name": "doMode", "description": "do mode"},
6 {"ch": 3, "access": 1, "variant_type": 3, "func_type": 99, "name": "helloDO", "description": "hello do"}
Compile Guide
Using native toolchain
- Copy sample.tar.gz contained in the programing guide from your PC to ioThinx:
For example, if the IP address of the ioThinx is "192.168.127.254", use the following command: 1 user@Linux:~$ scp sample.tar.gz moxa@192.168.127.254:~
- Extract the sample code
1 moxa@Moxa:~$ tar zxvf sample.tar.gz
- Build IO sample code
1 moxa@Moxa:~$ cd sample/mx_node_sdk/c/io
Build via cmake & make 1 moxa@Moxa:~/sample/mx_node_sdk/c/io$ cmake .
2 moxa@Moxa:~/sample/mx_node_sdk/c/io$ make
- Move
liboperator.so
to OperatorLib
1 moxa@Moxa:~/sample/mx_node_sdk/c/io$ cp liboperator.so /usr/local/bin/embeddedopcuaserver/OperatorLib/IOProtocol/
- Restart server via systemd
1 moxa@Moxa:~/sample/mx_node_sdk/c/io$ sudo systemctl restart embedded-opcua-server
Using cross toolchain
- Copy sample.tar.gz contained in the programing guide to your PC
- Extract the sample code
1 user@Linux:~$ tar zxvf sample.tar.gz
- Build IO sample code
1 user@Linux:~$ cd sample/mx_node_sdk/c/io
Build via cmake & make 1 user@Linux:~/sample/mx_node_sdk/c/io$ cmake . -DCMAKE_TOOLCHAIN_FILE=toolchain-cross.cmake
2 user@Linux:~/sample/mx_node_sdk/c/io$ make
- Copy the sample program to ioThinx:
For example, if the IP address of the ioThinx is "192.168.127.254", use the following command: 1 user@Linux:~/sample/mx_node_sdk/c/io$ scp liboperator.so moxa@192.168.127.254:~
- Move
liboperator.so
to OperatorLib
1 moxa@Moxa:~$ cp liboperator.so /usr/local/bin/embeddedopcuaserver/OperatorLib/IOProtocol/
- Restart server via systemd
1 moxa@Moxa:~$ sudo systemctl restart embedded-opcua-server
Appendix and FAQ
Programming Source Code
- example
- quick example to show 2 data nodes onto OPC UA Server
- demo
- demo sample shows all data types nodes onto OPC UA Server
- io
- io sample shows io data nodes onto OPC UA Server
5 │ ├── demo_node_operator.c
6 │ ├── toolchain-cross.cmake
7 │ └── toolchain-native.cmake
10 │ ├── sample_node_operator.c
11 │ ├── toolchain-cross.cmake
12 │ └── toolchain-native.cmake
18 ├── io_node_operator.c
19 ├── toolchain-cross.cmake
20 └── toolchain-native.cmake
IO Config Format
Explain how to use io.conf to fit your usage
- slot
- follow array index to represent which slot
- access
- Node's access right. Please reference MX_NODE_ACCESS_RIGHT
- variant_type
- MX_Variant's data type. please reference MX_NODE_VALUE_TYPE
- func_type
Execute OPC UA server
1 moxa@Moxa:~$ sudo systemctl start embedded-opcua-server
2 moxa@Moxa:~$ sudo systemctl stop embedded-opcua-server
3 moxa@Moxa:~$ sudo systemctl restart embedded-opcua-server
4 moxa@Moxa:~$ sudo systemctl status embedded-opcua-server
5 moxa@Moxa:~$ sudo systemctl disable embedded-opcua-server
6 moxa@Moxa:~$ sudo systemctl enable embedded-opcua-server
Add/Delete OPC UA server account
1 moxa@Moxa:~$ sudo opcuauser --add moxa
2 moxa@Moxa:~$ sudo opcuauser --del moxa
4 moxa@Moxa:~$ sudo opcuauser --help
5 Usage: opcuauser [options] username
8 -a, --add Add user account
9 -d, --del Delete user account
10 -c, --change Change user password
11 -v, --verion Show version
15 opcuauser Add user account
16 opcuauser username Change user password
17 opcuauser --help Show help
Please notice that embedded-opcua-server should be reboot to take effect of user account list. Current user account list can be verify by checking /etc/opcuauser_passwd
.
Anonymous user account setting
Default Anonymous user account is enable, use opcuauser
command to add or delete anonymous user will not change anything. If OPC UA Server want to delete anonymous user account, please move to file /usr/local/bin/embeddedopcuaserver/OPCUAServerData/Config/OPCUA.json
Modify setting to disable,
Debug
log: Systemd service syslog must be active(running)
- if non-active
- check
systemctl status embedded-opcua-server
.
- if active
- check
/var/log/syslog
to see all debug info during server enable.
Limitation
- This OPC UA Server can only be executed on ioThinx-4533-LX.
- Please backup
/usr/local/bin/embeddedopcuaserver/OPCUAServerData/Config
before FWR upgrade.
- Use Lan1 internet setting as default connection setting.