mirror of
https://github.com/kernelkit/infix.git
synced 2026-08-02 05:43:02 +02:00
package: relocate PROFINET packages to customer repo.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
committed by
Richard Alpe
parent
93fe939f91
commit
de24d0389a
@@ -1 +0,0 @@
|
||||
local7.* -/var/log/profinet.log
|
||||
@@ -9,10 +9,7 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/klish/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/klish-plugin-sysrepo/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/mdnsd/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/net/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/osal/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/p-net/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/podman/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/profeth/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/skeleton-init-finit/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/tetris/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/querierd/Config.in"
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
config BR2_PACKAGE_OSAL
|
||||
bool "osal"
|
||||
depends on BR2_TOOLCHAIN_HAS_THREADS
|
||||
help
|
||||
This package contains an OS abstraction layer. The goal of
|
||||
the abstraction layer is to simplify writing software that
|
||||
runs on many platforms. This abstraction layer is mainly
|
||||
focused on threading functionality.
|
||||
|
||||
https://github.com/rtlabs-com/osal
|
||||
|
||||
comment "osal needs a toolchain w/ threads"
|
||||
depends on !BR2_TOOLCHAIN_HAS_THREADS
|
||||
@@ -1,18 +0,0 @@
|
||||
################################################################################
|
||||
#
|
||||
# osal
|
||||
#
|
||||
################################################################################
|
||||
|
||||
OSAL_VERSION = 0ab080859e3ba6d2b6d2fcac6f471d3c3d08d5f2
|
||||
OSAL_SITE_METHOD = git
|
||||
OSAL_SITE = https://github.com/rtlabs-com/osal
|
||||
OSAL_GIT_SUBMODULES = YES
|
||||
OSAL_INSTALL_STAGING = YES
|
||||
OSAL_LICENSE = BSD-3-Clause
|
||||
OSAL_LICENSE_FILES = LICENSE
|
||||
OSAL_SUPPORTS_IN_SOURCE_BUILD = NO
|
||||
OSAL_CONF_OPTS += \
|
||||
-DBUILD_SHARED_LIBS=true
|
||||
|
||||
$(eval $(cmake-package))
|
||||
@@ -1,42 +0,0 @@
|
||||
menuconfig BR2_PACKAGE_P_NET
|
||||
bool "p-net"
|
||||
depends on BR2_PACKAGE_NETSNMP_SERVER
|
||||
select BR2_PACKAGE_OSAL
|
||||
help
|
||||
The rt-labs PROFINET stack p-net is used for PROFINET device
|
||||
implementations. It is easy to use and provides a small
|
||||
footprint. It is especially well suited for embedded systems
|
||||
where resources are limited and efficiency is crucial.
|
||||
|
||||
It is written in C and can be run on bare-metal hardware, an
|
||||
RTOS such as rt-kernel, or on Linux or Windows. The main
|
||||
requirement is that the platform can send and receive RAW
|
||||
Ethernet Layer 2 frames. The p-net stack is supplied with
|
||||
full sources including a porting layer.
|
||||
|
||||
https://github.com/rtlabs-com/p-net
|
||||
|
||||
if BR2_PACKAGE_P_NET
|
||||
|
||||
config BR2_PACKAGE_P_NET_MAX_SLOTS
|
||||
int "PNET_MAX_SLOTS"
|
||||
default 5
|
||||
help
|
||||
Per API. Should be > 1 to allow at least one I/O module
|
||||
|
||||
config BR2_PACKAGE_P_NET_MAX_SUBSLOTS
|
||||
int "PNET_MAX_SUBSLOTS"
|
||||
default 3
|
||||
help
|
||||
Per slot (DAP requires 2 + PNET_MAX_PHYSICAL_PORTS)
|
||||
|
||||
config BR2_PACKAGE_P_NET_MAX_PHYSICAL_PORTS
|
||||
int "PNET_MAX_PHYSICAL_PORTS"
|
||||
default 1
|
||||
help
|
||||
Max number of physical ports
|
||||
|
||||
endif
|
||||
|
||||
comment "p-net needs the netsnmp server"
|
||||
depends on !BR2_PACKAGE_NETSNMP_SERVER
|
||||
@@ -1,27 +0,0 @@
|
||||
################################################################################
|
||||
#
|
||||
# p-net
|
||||
#
|
||||
################################################################################
|
||||
|
||||
#P_NET_VERSION = a55fce3f0872bad0254040d8fa344f6a35f64d78
|
||||
#P_NET_SITE = https://github.com/rtlabs-com/p-net
|
||||
P_NET_VERSION = 6e4bc6d1842970fb33469c8998e3b4d11ee4c0e6
|
||||
P_NET_SITE = https://github.com/addiva-elektronik/p-net
|
||||
P_NET_SITE_METHOD = git
|
||||
P_NET_GIT_SUBMODULES = YES
|
||||
P_NET_INSTALL_STAGING = YES
|
||||
P_NET_LICENSE = GPL-3.0
|
||||
P_NET_LICENSE_FILES = LICENSE.md
|
||||
P_NET_SUPPORTS_IN_SOURCE_BUILD = NO
|
||||
P_NET_DEPENDENCIES = osal netsnmp
|
||||
# Set LOG_LEVEL to DEBUG for more detailed output
|
||||
P_NET_CONF_OPTS += \
|
||||
-DBUILD_SHARED_LIBS=true \
|
||||
-DPNET_OPTION_SNMP=ON \
|
||||
-DLOG_LEVEL=INFO \
|
||||
-DPNET_MAX_SLOTS=$(BR2_PACKAGE_P_NET_MAX_SLOTS) \
|
||||
-DPNET_MAX_SUBSLOTS=$(BR2_PACKAGE_P_NET_MAX_SUBSLOTS) \
|
||||
-DPNET_MAX_PHYSICAL_PORTS=$(BR2_PACKAGE_P_NET_MAX_PHYSICAL_PORTS)
|
||||
|
||||
$(eval $(cmake-package))
|
||||
@@ -1,18 +0,0 @@
|
||||
config BR2_PACKAGE_PROFETH_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
depends on BR2_PACKAGE_P_NET
|
||||
depends on BR2_PACKAGE_NETSNMP_SERVER
|
||||
|
||||
config BR2_PACKAGE_PROFETH
|
||||
bool "profeth"
|
||||
depends on BR2_PACKAGE_PROFETH_SUPPORTED
|
||||
help
|
||||
Simple profinet switch management.
|
||||
|
||||
Note: to run in Qemu you need the following menuconfig settings:
|
||||
QEMU_NET_TAP=y
|
||||
QEMU_NET_TAP_N=10
|
||||
|
||||
comment "profeth needs p-net"
|
||||
depends on !BR2_PACKAGE_PROFETH_SUPPORTED
|
||||
@@ -1 +0,0 @@
|
||||
PROFETH_ARGS="-i vlan1,e0,e1,e2,e3,e4,e5,e6,e7,e8,e9"
|
||||
@@ -1,37 +0,0 @@
|
||||
################################################################################
|
||||
#
|
||||
# profeth
|
||||
#
|
||||
################################################################################
|
||||
|
||||
PROFETH_VERSION = 1.0
|
||||
PROFETH_LICENSE = GPL-3.0
|
||||
PROFETH_SITE_METHOD = local
|
||||
PROFETH_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/profeth
|
||||
PROFETH_DEPENDENCIES = p-net
|
||||
PROFETH_AUTORECONF = YES
|
||||
|
||||
# Ugly workaround to be able to build standalone applications using the
|
||||
# p-net library. This should probably be addressed with upstream.
|
||||
define PROFETH_POST_RSYNC_INSTALL_OPTS
|
||||
@echo "*** Installing pnal headers and generated options.h from p-net"
|
||||
cp $(P_NET_SRCDIR)/src/ports/linux/pnal_sys.h $(@D)/src/
|
||||
cp $(P_NET_SRCDIR)/src/pnal.h $(@D)/src/
|
||||
cp $(P_NET_BUILDDIR)/src/options.h $(@D)/src/
|
||||
endef
|
||||
PROFETH_POST_RSYNC_HOOKS += PROFETH_POST_RSYNC_INSTALL_OPTS
|
||||
|
||||
define PROFETH_INSTALL_EXTRA
|
||||
cp $(PROFETH_PKGDIR)/sysctl.conf $(TARGET_DIR)/etc/sysctl.d/profeth.conf
|
||||
cp $(PROFETH_PKGDIR)/set_profinet_leds $(TARGET_DIR)/usr/sbin/
|
||||
cp $(PROFETH_PKGDIR)/set_network_parameters $(TARGET_DIR)/usr/sbin/
|
||||
mkdir -p $(TARGET_DIR)/etc/snmp
|
||||
mkdir -p $(TARGET_DIR)/etc/tmpfiles.d
|
||||
mkdir -p $(TARGET_DIR)/etc/default
|
||||
cp $(PROFETH_PKGDIR)/snmpd.conf $(TARGET_DIR)/etc/snmp/
|
||||
cp $(PROFETH_PKGDIR)/tmpfiles.conf $(TARGET_DIR)/etc/tmpfiles.d/profeth.conf
|
||||
cp $(PROFETH_PKGDIR)/default $(TARGET_DIR)/etc/default/profeth
|
||||
endef
|
||||
PROFETH_TARGET_FINALIZE_HOOKS += PROFETH_INSTALL_EXTRA
|
||||
|
||||
$(eval $(autotools-package))
|
||||
@@ -1,89 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
############################################
|
||||
# Script for manipulating network settings #
|
||||
############################################
|
||||
#
|
||||
# This is useful for example on Ubuntu.
|
||||
#
|
||||
# You need to adapt this script to fit your Linux distribution.
|
||||
# Keep the script name, and use the same command line arguments.
|
||||
#
|
||||
# Make sure that the script path is available from your Profinet application.
|
||||
# In case of problems, try the script manually from the directory where your
|
||||
# application is located.
|
||||
|
||||
if [ $# -ne 6 ]; then
|
||||
echo "Usage: ${0} interfacename ip netmask gateway hostname permanent"
|
||||
echo " where:"
|
||||
echo " interfacename: Network interface name, for example eth0"
|
||||
echo " ip: IPv4 address, for example 192.168.0.50"
|
||||
echo " netmask: Netmask"
|
||||
echo " gateway: Default gateway"
|
||||
echo " hostname: Host name, for example my_laptop_3"
|
||||
echo " permanent: 1 if changes are permanent, 0 if temporary"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INTERFACE=$1
|
||||
IP_ADDRESS=$2
|
||||
NETMASK=$3
|
||||
DEFAULT_GATEWAY=$4
|
||||
HOSTNAME=$5
|
||||
SET_VALUES_PERMANENTLY=$6
|
||||
|
||||
# From a Profinet point of view there is no need to change the
|
||||
# host name of the Linux machine. The p-net stack will use the
|
||||
# name as station name internally.
|
||||
SKIP_SETTING_HOSTNAME=true
|
||||
|
||||
echo "Network script for ${INTERFACE}: " \
|
||||
"Set IP ${IP_ADDRESS} " \
|
||||
"Netmask ${NETMASK} " \
|
||||
"Gateway ${DEFAULT_GATEWAY} " \
|
||||
"Permanent: ${SET_VALUES_PERMANENTLY} " \
|
||||
"Hostname: ${HOSTNAME} " \
|
||||
"Skip setting hostname: ${SKIP_SETTING_HOSTNAME}"
|
||||
|
||||
# There is no need to set the changes permanently,
|
||||
# as the p-net stack will set the IP parameters on each start.
|
||||
# You are however free to use it if you like.
|
||||
|
||||
if ! ip address flush label $INTERFACE; then
|
||||
echo "Failed to flush network interface"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! ip address add $IP_ADDRESS/$NETMASK dev $INTERFACE; then
|
||||
echo "Failed to set IP address and netmask"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! ip link set dev $INTERFACE up; then
|
||||
echo "Failed to set network interface up"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "${DEFAULT_GATEWAY}" != "0.0.0.0" ]; then
|
||||
if ! ip route add default via $DEFAULT_GATEWAY; then
|
||||
echo "Failed to set default gateway"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "No valid default gateway given. Skipping setting default gateway."
|
||||
fi
|
||||
|
||||
if [ "$SKIP_SETTING_HOSTNAME" = false ]; then
|
||||
if ! hostname $HOSTNAME; then
|
||||
echo "Failed to set hostname to $HOSTNAME"
|
||||
hostname_len=${#HOSTNAME}
|
||||
if [ $hostname_len -gt 64 ]; then
|
||||
echo "The given hostname length is ${hostname_len} characters." \
|
||||
"Many Linux systems have a limit of 64 characters. The p-net stack uses" \
|
||||
"a longer stationname internally."
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Used by profeth to flash LED(s), only a dummy for now
|
||||
|
||||
if [ $# -ne 2 ]; then
|
||||
echo "Usage: ${0} led_number led_state"
|
||||
echo " where:"
|
||||
echo " led_number: LED number. Number 1 for sample app data LED"
|
||||
echo " Number 2 for mandatory Profinet signal LED"
|
||||
echo " led_state: 1 for on, 0 for off"
|
||||
echo " Exit code: 0 on success, 1 on error"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LED_NUMBER=$1
|
||||
LED_STATE=$2
|
||||
|
||||
if ! [ "${LED_STATE}" = "0" -o "${LED_STATE}" = "1" ]; then
|
||||
echo "Wrong LED state: ${LED_STATE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ${LED_STATE} > "/tmp/pnet_led_${LED_NUMBER}.txt"
|
||||
|
||||
exit 0
|
||||
@@ -1,21 +0,0 @@
|
||||
#rocommunity public
|
||||
#rwcommunity private
|
||||
#sysName infix
|
||||
#sysLocation kernelkit
|
||||
#syscontact kernelkit@googlegroups.com
|
||||
#sysServices 10
|
||||
|
||||
#master agentx
|
||||
#agentXTimeout 5
|
||||
#engineIDType 3
|
||||
#engineIDNic vlan1
|
||||
|
||||
master agentx
|
||||
agentXSocket /var/run/agentx/master
|
||||
|
||||
agentaddress udp:161
|
||||
view systemonly included .1.3.6.1.2.1.1
|
||||
view systemonly included .1.3.6.1.2.1.2.2
|
||||
view systemonly included .1.0.8802.1.1.2
|
||||
rocommunity public default -V systemonly
|
||||
rwcommunity private default -V systemonly
|
||||
@@ -1,2 +0,0 @@
|
||||
# Explicitly required by p-net, <https://rt-labs.com/docs/p-net/additional_linux_details.html?highlight=ip_local_port_range#setting-linux-ephemeral-port-rang>, but also IANA <https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt>
|
||||
net.ipv4.ip_local_port_range = 49152 60999
|
||||
@@ -1 +0,0 @@
|
||||
d /var/lib/profeth - - -
|
||||
@@ -156,14 +156,6 @@ endef
|
||||
SKELETON_INIT_FINIT_TARGET_FINALIZE_HOOKS += SKELETON_INIT_FINIT_SET_OPENSSH
|
||||
endif
|
||||
|
||||
ifeq ($(BR2_PACKAGE_PROFETH),y)
|
||||
define SKELETON_INIT_FINIT_SET_PROFETH
|
||||
cp $(SKELETON_INIT_FINIT_AVAILABLE)/profeth.conf $(FINIT_D)/available/
|
||||
ln -sf ../available/profeth.conf $(FINIT_D)/enabled/
|
||||
endef
|
||||
SKELETON_INIT_FINIT_TARGET_FINALIZE_HOOKS += SKELETON_INIT_FINIT_SET_PROFETH
|
||||
endif
|
||||
|
||||
ifeq ($(BR2_PACKAGE_QUAGGA),y)
|
||||
define SKELETON_INIT_FINIT_SET_QUAGGA
|
||||
cp $(SKELETON_INIT_FINIT_AVAILABLE)/quagga/zebra.conf $(FINIT_D)/available/
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
service [2345789] <net/vlan1/up,pid/snmpd> log:prio:local7.info,tag:profeth \
|
||||
env:-/etc/default/profeth profeth -s infix -p /var/lib/profeth $PROFETH_ARGS -- PROFΞTH daemon
|
||||
@@ -1,32 +0,0 @@
|
||||
*~
|
||||
*.o
|
||||
*.la
|
||||
*.lo
|
||||
*.so
|
||||
.deps
|
||||
.libs
|
||||
|
||||
/aclocal.m4
|
||||
/autom4te.cache/
|
||||
/aux
|
||||
/compile
|
||||
/config.h
|
||||
/config.h.in
|
||||
/config.guess
|
||||
/config.log
|
||||
/config.status
|
||||
/config.sub
|
||||
/configure
|
||||
/depcomp
|
||||
/install-sh
|
||||
/libtool
|
||||
/ltmain.sh
|
||||
/m4
|
||||
/missing
|
||||
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
Makefile
|
||||
Makefile.in
|
||||
|
||||
@@ -1,674 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
@@ -1,178 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<ISO15745Profile xmlns="http://www.profibus.com/GSDML/2003/11/DeviceProfile" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.profibus.com/GSDML/2003/11/DeviceProfile ..\xsd\GSDML-DeviceProfile-V2.43.xsd">
|
||||
|
||||
<ProfileHeader>
|
||||
<ProfileIdentification>PROFINET Device Profile</ProfileIdentification>
|
||||
<ProfileRevision>1.00</ProfileRevision>
|
||||
<ProfileName>Device Profile for PROFINET Devices</ProfileName>
|
||||
<ProfileSource>PROFIBUS Nutzerorganisation e. V. (PNO)</ProfileSource>
|
||||
<ProfileClassID>Device</ProfileClassID>
|
||||
<ISO15745Reference>
|
||||
<ISO15745Part>4</ISO15745Part>
|
||||
<ISO15745Edition>1</ISO15745Edition>
|
||||
<ProfileTechnology>GSDML</ProfileTechnology>
|
||||
</ISO15745Reference>
|
||||
</ProfileHeader>
|
||||
<ProfileBody>
|
||||
<DeviceIdentity VendorID="0x0493" DeviceID="0x0002">
|
||||
<InfoText TextId="IDT_DEV_INFO"/>
|
||||
<VendorName Value="Kernelkit"/>
|
||||
</DeviceIdentity>
|
||||
<DeviceFunction>
|
||||
<Family MainFamily="Network Components" ProductFamily="Infix Switch"/>
|
||||
</DeviceFunction>
|
||||
<ApplicationProcess>
|
||||
<DeviceAccessPointList>
|
||||
<DeviceAccessPointItem ID="DAP_1" PNIO_Version="V2.43" PhysicalSlots="0" ModuleIdentNumber="0x00000001" MinDeviceInterval="4096" DNS_CompatibleName="infix" FixedInSlots="0" ObjectUUID_LocalIndex="1" DeviceAccessSupported="false" MultipleWriteSupported="true" CheckDeviceID_Allowed="true" NameOfStationNotTransferable="false" LLDP_NoD_Supported="true" ResetToFactoryModes="1..2">
|
||||
<ModuleInfo>
|
||||
<Name TextId="IDT_DAP_NAME"/>
|
||||
<InfoText TextId="IDT_DAP_INFO"/>
|
||||
<VendorName Value="Kernelkit"/>
|
||||
<OrderNumber Value="1"/>
|
||||
<HardwareRelease Value="A1"/>
|
||||
<SoftwareRelease Value="1.0.0"/>
|
||||
</ModuleInfo>
|
||||
<CertificationInfo ConformanceClass="B" ApplicationClass="" NetloadClass="I"/>
|
||||
<SubslotList>
|
||||
<SubslotItem SubslotNumber="32768" TextId="IDT_SS_IFACE"/>
|
||||
<SubslotItem SubslotNumber="32769" TextId="IDT_SS_P1"/>
|
||||
<SubslotItem SubslotNumber="32770" TextId="IDT_SS_P2"/>
|
||||
<SubslotItem SubslotNumber="32771" TextId="IDT_SS_P3"/>
|
||||
<SubslotItem SubslotNumber="32772" TextId="IDT_SS_P4"/>
|
||||
<SubslotItem SubslotNumber="32773" TextId="IDT_SS_P5"/>
|
||||
<SubslotItem SubslotNumber="32774" TextId="IDT_SS_P6"/>
|
||||
<SubslotItem SubslotNumber="32775" TextId="IDT_SS_P7"/>
|
||||
<SubslotItem SubslotNumber="32776" TextId="IDT_SS_P8"/>
|
||||
<SubslotItem SubslotNumber="32777" TextId="IDT_SS_P9"/>
|
||||
<SubslotItem SubslotNumber="32778" TextId="IDT_SS_P10"/>
|
||||
</SubslotList>
|
||||
<IOConfigData MaxInputLength="244" MaxOutputLength="244"/>
|
||||
<!-- <IOConfigData MaxInputLength="18" MaxOutputLength="18" MaxDataLength="36"/> -->
|
||||
<VirtualSubmoduleList>
|
||||
<VirtualSubmoduleItem ID="IDS_1" SubmoduleIdentNumber="0x00000001" FixedInSubslots="1" PROFIsafeSupported="false" Writeable_IM_Records="1 2 3" MayIssueProcessAlarm="false">
|
||||
<IOData/>
|
||||
<ModuleInfo>
|
||||
<Name TextId="IDT_DAP_NAME"/>
|
||||
<InfoText TextId="IDT_DAP_INFO"/>
|
||||
</ModuleInfo>
|
||||
</VirtualSubmoduleItem>
|
||||
</VirtualSubmoduleList>
|
||||
<SystemDefinedSubmoduleList>
|
||||
<InterfaceSubmoduleItem ID="IDS_INT1" SubmoduleIdentNumber="0x00008000" SubslotNumber="32768" TextId="IDT_IFACE" SupportedRT_Classes="RT_CLASS_1" SupportedProtocols="SNMP;LLDP" NetworkComponentDiagnosisSupported="false" PTP_BoundarySupported="true" DCP_BoundarySupported="true">
|
||||
<ApplicationRelations StartupMode="Advanced">
|
||||
<TimingProperties SendClock="32" ReductionRatio="1 2 4 8 16 32 64 128 256 512"/>
|
||||
</ApplicationRelations>
|
||||
</InterfaceSubmoduleItem>
|
||||
<PortSubmoduleItem ID="IDS_P1" SubmoduleIdentNumber="0x00008001" SubslotNumber="32769" TextId="IDT_P1" MaxPortRxDelay="350" MaxPortTxDelay="160" PortDeactivationSupported="false" SupportsRingportConfig="false" IsDefaultRingport="false" CheckMAUTypeSupported="false">
|
||||
<MAUTypeList>
|
||||
<MAUTypeItem Value="30"/>
|
||||
<MAUTypeItem Value="16"/>
|
||||
<MAUTypeItem Value="5"/>
|
||||
</MAUTypeList>
|
||||
</PortSubmoduleItem>
|
||||
<PortSubmoduleItem ID="IDS_P2" SubmoduleIdentNumber="0x00008002" SubslotNumber="32770" TextId="IDT_P2" MaxPortRxDelay="350" MaxPortTxDelay="160" PortDeactivationSupported="false" SupportsRingportConfig="false" IsDefaultRingport="false" CheckMAUTypeSupported="false">
|
||||
<MAUTypeList>
|
||||
<MAUTypeItem Value="30"/>
|
||||
<MAUTypeItem Value="16"/>
|
||||
<MAUTypeItem Value="5"/>
|
||||
</MAUTypeList>
|
||||
</PortSubmoduleItem>
|
||||
<PortSubmoduleItem ID="IDS_P3" SubmoduleIdentNumber="0x00008003" SubslotNumber="32771" TextId="IDT_P3" MaxPortRxDelay="350" MaxPortTxDelay="160" PortDeactivationSupported="false" SupportsRingportConfig="false" IsDefaultRingport="false" CheckMAUTypeSupported="false">
|
||||
<MAUTypeList>
|
||||
<MAUTypeItem Value="30"/>
|
||||
<MAUTypeItem Value="16"/>
|
||||
<MAUTypeItem Value="5"/>
|
||||
</MAUTypeList>
|
||||
</PortSubmoduleItem>
|
||||
<PortSubmoduleItem ID="IDS_P4" SubmoduleIdentNumber="0x00008004" SubslotNumber="32772" TextId="IDT_P4" MaxPortRxDelay="350" MaxPortTxDelay="160" PortDeactivationSupported="false" SupportsRingportConfig="false" IsDefaultRingport="false" CheckMAUTypeSupported="false">
|
||||
<MAUTypeList>
|
||||
<MAUTypeItem Value="30"/>
|
||||
<MAUTypeItem Value="16"/>
|
||||
<MAUTypeItem Value="5"/>
|
||||
</MAUTypeList>
|
||||
</PortSubmoduleItem>
|
||||
<PortSubmoduleItem ID="IDS_P5" SubmoduleIdentNumber="0x00008005" SubslotNumber="32773" TextId="IDT_P5" MaxPortRxDelay="350" MaxPortTxDelay="160" PortDeactivationSupported="false" SupportsRingportConfig="false" IsDefaultRingport="false" CheckMAUTypeSupported="false">
|
||||
<MAUTypeList>
|
||||
<MAUTypeItem Value="30"/>
|
||||
<MAUTypeItem Value="16"/>
|
||||
<MAUTypeItem Value="5"/>
|
||||
</MAUTypeList>
|
||||
</PortSubmoduleItem>
|
||||
<PortSubmoduleItem ID="IDS_P6" SubmoduleIdentNumber="0x00008006" SubslotNumber="32774" TextId="IDT_P6" MaxPortRxDelay="350" MaxPortTxDelay="160" PortDeactivationSupported="false" SupportsRingportConfig="false" IsDefaultRingport="false" CheckMAUTypeSupported="false">
|
||||
<MAUTypeList>
|
||||
<MAUTypeItem Value="30"/>
|
||||
<MAUTypeItem Value="16"/>
|
||||
<MAUTypeItem Value="5"/>
|
||||
</MAUTypeList>
|
||||
</PortSubmoduleItem>
|
||||
<PortSubmoduleItem ID="IDS_P7" SubmoduleIdentNumber="0x00008007" SubslotNumber="32775" TextId="IDT_P7" MaxPortRxDelay="350" MaxPortTxDelay="160" PortDeactivationSupported="false" SupportsRingportConfig="false" IsDefaultRingport="false" CheckMAUTypeSupported="false">
|
||||
<MAUTypeList>
|
||||
<MAUTypeItem Value="30"/>
|
||||
<MAUTypeItem Value="16"/>
|
||||
<MAUTypeItem Value="5"/>
|
||||
</MAUTypeList>
|
||||
</PortSubmoduleItem>
|
||||
<PortSubmoduleItem ID="IDS_P8" SubmoduleIdentNumber="0x00008008" SubslotNumber="32776" TextId="IDT_P8" MaxPortRxDelay="350" MaxPortTxDelay="160" PortDeactivationSupported="false" SupportsRingportConfig="false" IsDefaultRingport="false" CheckMAUTypeSupported="false">
|
||||
<MAUTypeList>
|
||||
<MAUTypeItem Value="30"/>
|
||||
<MAUTypeItem Value="16"/>
|
||||
<MAUTypeItem Value="5"/>
|
||||
</MAUTypeList>
|
||||
</PortSubmoduleItem>
|
||||
<PortSubmoduleItem ID="IDS_P9" SubmoduleIdentNumber="0x00008009" SubslotNumber="32777" TextId="IDT_P9" MaxPortRxDelay="350" MaxPortTxDelay="160" PortDeactivationSupported="false" SupportsRingportConfig="false" IsDefaultRingport="false" CheckMAUTypeSupported="false">
|
||||
<MAUTypeList>
|
||||
<MAUTypeItem Value="30"/>
|
||||
<MAUTypeItem Value="16"/>
|
||||
<MAUTypeItem Value="5"/>
|
||||
</MAUTypeList>
|
||||
</PortSubmoduleItem>
|
||||
<PortSubmoduleItem ID="IDS_P10" SubmoduleIdentNumber="0x0000800a" SubslotNumber="32778" TextId="IDT_P10" MaxPortRxDelay="350" MaxPortTxDelay="160" PortDeactivationSupported="false" SupportsRingportConfig="false" IsDefaultRingport="false" CheckMAUTypeSupported="false">
|
||||
<MAUTypeList>
|
||||
<MAUTypeItem Value="30"/>
|
||||
<MAUTypeItem Value="16"/>
|
||||
<MAUTypeItem Value="5"/>
|
||||
</MAUTypeList>
|
||||
</PortSubmoduleItem>
|
||||
</SystemDefinedSubmoduleList>
|
||||
<!-- <Graphics> -->
|
||||
<!-- <GraphicItemRef Type="DeviceSymbol" GraphicItemTarget="Kernelkit_Infix_Switch1"/> -->
|
||||
<!-- </Graphics> -->
|
||||
</DeviceAccessPointItem>
|
||||
</DeviceAccessPointList>
|
||||
|
||||
<!-- <GraphicsList> -->
|
||||
<!-- <GraphicItem ID="Kernelkit_Infix_Switch1" GraphicFile="GSDML_VendorID_DeviceID-Switch-10-Port"/> -->
|
||||
<!-- </GraphicsList> -->
|
||||
|
||||
<ExternalTextList>
|
||||
<PrimaryLanguage>
|
||||
<Text TextId="IDT_DEV_INFO" Value="Infix 10-port Switch"/>
|
||||
<Text TextId="IDT_DAP_NAME" Value="Infix 10-port Switch"/>
|
||||
<Text TextId="IDT_DAP_INFO" Value="Infix 10-port PROFINET Switch, managed, supports Conformance Clas A,B"/>
|
||||
<Text TextId="IDT_IFACE" Value="PN-IO"/>
|
||||
<Text TextId="IDT_SS_IFACE" Value="X1"/>
|
||||
<Text TextId="IDT_SS_P1" Value="X1 P0"/>
|
||||
<Text TextId="IDT_SS_P2" Value="X1 P1"/>
|
||||
<Text TextId="IDT_SS_P3" Value="X1 P2"/>
|
||||
<Text TextId="IDT_SS_P4" Value="X1 P3"/>
|
||||
<Text TextId="IDT_SS_P5" Value="X1 P4"/>
|
||||
<Text TextId="IDT_SS_P6" Value="X1 P5"/>
|
||||
<Text TextId="IDT_SS_P7" Value="X1 P6"/>
|
||||
<Text TextId="IDT_SS_P8" Value="X1 P7"/>
|
||||
<Text TextId="IDT_SS_P9" Value="X1 P8"/>
|
||||
<Text TextId="IDT_SS_P10" Value="X1 P9"/>
|
||||
<Text TextId="IDT_P1" Value="e0"/>
|
||||
<Text TextId="IDT_P2" Value="e1"/>
|
||||
<Text TextId="IDT_P3" Value="e2"/>
|
||||
<Text TextId="IDT_P4" Value="e3"/>
|
||||
<Text TextId="IDT_P5" Value="e4"/>
|
||||
<Text TextId="IDT_P6" Value="e5"/>
|
||||
<Text TextId="IDT_P7" Value="e6"/>
|
||||
<Text TextId="IDT_P8" Value="e7"/>
|
||||
<Text TextId="IDT_P9" Value="e8"/>
|
||||
<Text TextId="IDT_P10" Value="e9"/>
|
||||
</PrimaryLanguage>
|
||||
</ExternalTextList>
|
||||
</ApplicationProcess>
|
||||
</ProfileBody>
|
||||
</ISO15745Profile>
|
||||
@@ -1,3 +0,0 @@
|
||||
SUBDIRS = src
|
||||
DISTCLEANFILES = *~ *.d
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
@@ -1,7 +0,0 @@
|
||||
PROFΞTH
|
||||
=======
|
||||
|
||||
A PROFINET network device based on the p-net device example.
|
||||
|
||||
profeth is licensed under the GPL V3, like p-net itself.
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([profeth], [1.0.0],
|
||||
[https://github.com/kernelkit/infix/issues])
|
||||
AM_INIT_AUTOMAKE(1.11 foreign subdir-objects)
|
||||
AM_SILENT_RULES(yes)
|
||||
|
||||
LT_INIT
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/Makefile
|
||||
])
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
|
||||
AC_CHECK_LIB([profinet], [pnet_init],, AC_MSG_ERROR([Profinet not found]))
|
||||
|
||||
test "x$prefix" = xNONE && prefix=$ac_default_prefix
|
||||
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
|
||||
|
||||
DATAROOTDIR=`eval echo $datarootdir`
|
||||
DATAROOTDIR=`eval echo $DATAROOTDIR`
|
||||
AC_SUBST(DATAROOTDIR)
|
||||
|
||||
LIBDIR=`eval echo $libdir`
|
||||
LIBDIR=`eval echo $LIBDIR`
|
||||
AC_SUBST(LIBDIR)
|
||||
|
||||
LOCALSTATEDIR=`eval echo $localstatedir`
|
||||
LOCALSTATEDIR=`eval echo $LOCALSTATEDIR`
|
||||
AC_SUBST(LOCALSTATEDIR)
|
||||
|
||||
RUNSTATEDIR=`eval echo $runstatedir`
|
||||
RUNSTATEDIR=`eval echo $RUNSTATEDIR`
|
||||
AC_SUBST(RUNSTATEDIR)
|
||||
|
||||
SYSCONFDIR=`eval echo $sysconfdir`
|
||||
SYSCONFDIR=`eval echo $SYSCONFDIR`
|
||||
AC_SUBST(SYSCONFDIR)
|
||||
|
||||
AC_OUTPUT
|
||||
@@ -1,13 +0,0 @@
|
||||
sbin_PROGRAMS = profeth
|
||||
|
||||
profeth_SOURCES = profeth.c \
|
||||
app_data.c app_data.h \
|
||||
app_gsdml.c app_gsdml.h \
|
||||
app_log.c app_log.h \
|
||||
app_utils.c app_utils.h \
|
||||
pnal_filetools.c pnal_filetools.h \
|
||||
sampleapp_common.c sampleapp_common.h
|
||||
|
||||
profeth_CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter
|
||||
profeth_LDADD = -losal -lprofinet
|
||||
|
||||
@@ -1,315 +0,0 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2021 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#include "app_data.h"
|
||||
#include "app_utils.h"
|
||||
#include "app_gsdml.h"
|
||||
#include "app_log.h"
|
||||
#include "sampleapp_common.h"
|
||||
#include "osal.h"
|
||||
#include "pnal.h"
|
||||
#include <pnet_api.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define APP_DATA_DEFAULT_OUTPUT_DATA 0
|
||||
|
||||
/* Parameter data for digital submodules
|
||||
* The stored value is shared between all digital submodules in this example.
|
||||
*
|
||||
* Todo: Data is always in pnio data format. Add conversion to uint32_t.
|
||||
*/
|
||||
static uint32_t app_param_1 = 0; /* Network endianness */
|
||||
static uint32_t app_param_2 = 0; /* Network endianness */
|
||||
|
||||
/* Parameter data for echo submodules
|
||||
* The stored value is shared between all echo submodules in this example.
|
||||
*
|
||||
* Todo: Data is always in pnio data format. Add conversion to uint32_t.
|
||||
*/
|
||||
static uint32_t app_param_echo_gain = 1; /* Network endianness */
|
||||
|
||||
/* Digital submodule process data
|
||||
* The stored value is shared between all digital submodules in this example. */
|
||||
static uint8_t inputdata[APP_GSDML_INPUT_DATA_DIGITAL_SIZE] = {0};
|
||||
static uint8_t outputdata[APP_GSDML_OUTPUT_DATA_DIGITAL_SIZE] = {0};
|
||||
static uint8_t counter = 0;
|
||||
|
||||
/* Network endianness */
|
||||
static uint8_t echo_inputdata[APP_GSDML_INPUT_DATA_ECHO_SIZE] = {0};
|
||||
static uint8_t echo_outputdata[APP_GSDML_OUTPUT_DATA_ECHO_SIZE] = {0};
|
||||
|
||||
CC_PACKED_BEGIN
|
||||
typedef struct CC_PACKED app_echo_data
|
||||
{
|
||||
/* Network endianness.
|
||||
Used as a float, but we model it as a 4-byte integer to easily
|
||||
do endianness conversion */
|
||||
uint32_t echo_float_bytes;
|
||||
|
||||
/* Network endianness */
|
||||
uint32_t echo_int;
|
||||
} app_echo_data_t;
|
||||
CC_PACKED_END
|
||||
CC_STATIC_ASSERT (sizeof (app_echo_data_t) == APP_GSDML_INPUT_DATA_ECHO_SIZE);
|
||||
CC_STATIC_ASSERT (sizeof (app_echo_data_t) == APP_GSDML_OUTPUT_DATA_ECHO_SIZE);
|
||||
|
||||
/**
|
||||
* Set LED state.
|
||||
*
|
||||
* Compares new state with previous state, to minimize system calls.
|
||||
*
|
||||
* Uses the hardware specific app_set_led() function.
|
||||
*
|
||||
* @param led_state In: New LED state
|
||||
*/
|
||||
static void app_handle_data_led_state (bool led_state)
|
||||
{
|
||||
static bool previous_led_state = false;
|
||||
|
||||
if (led_state != previous_led_state)
|
||||
{
|
||||
app_set_led (APP_DATA_LED_ID, led_state);
|
||||
}
|
||||
previous_led_state = led_state;
|
||||
}
|
||||
|
||||
uint8_t * app_data_get_input_data (
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr,
|
||||
uint32_t submodule_id,
|
||||
bool button_pressed,
|
||||
uint16_t * size,
|
||||
uint8_t * iops)
|
||||
{
|
||||
float inputfloat;
|
||||
float outputfloat;
|
||||
uint32_t hostorder_inputfloat_bytes;
|
||||
uint32_t hostorder_outputfloat_bytes;
|
||||
app_echo_data_t * p_echo_inputdata = (app_echo_data_t *)&echo_inputdata;
|
||||
app_echo_data_t * p_echo_outputdata = (app_echo_data_t *)&echo_outputdata;
|
||||
|
||||
if (size == NULL || iops == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (
|
||||
submodule_id == APP_GSDML_SUBMOD_ID_DIGITAL_IN ||
|
||||
submodule_id == APP_GSDML_SUBMOD_ID_DIGITAL_IN_OUT)
|
||||
{
|
||||
/* Prepare digital input data
|
||||
* Lowest 7 bits: Counter Most significant bit: Button
|
||||
*/
|
||||
inputdata[0] = counter++;
|
||||
if (button_pressed)
|
||||
{
|
||||
inputdata[0] |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
inputdata[0] &= 0x7F;
|
||||
}
|
||||
|
||||
*size = APP_GSDML_INPUT_DATA_DIGITAL_SIZE;
|
||||
*iops = PNET_IOXS_GOOD;
|
||||
return inputdata;
|
||||
}
|
||||
|
||||
if (submodule_id == APP_GSDML_SUBMOD_ID_ECHO)
|
||||
{
|
||||
/* Calculate echodata input (to the PLC)
|
||||
* by multiplying the output (from the PLC) with a gain factor
|
||||
*/
|
||||
|
||||
/* Integer */
|
||||
p_echo_inputdata->echo_int = CC_TO_BE32 (
|
||||
CC_FROM_BE32 (p_echo_outputdata->echo_int) *
|
||||
CC_FROM_BE32 (app_param_echo_gain));
|
||||
|
||||
/* Float */
|
||||
/* Use memcopy to avoid strict-aliasing rule warnings */
|
||||
hostorder_outputfloat_bytes =
|
||||
CC_FROM_BE32 (p_echo_outputdata->echo_float_bytes);
|
||||
memcpy (&outputfloat, &hostorder_outputfloat_bytes, sizeof (outputfloat));
|
||||
inputfloat = outputfloat * CC_FROM_BE32 (app_param_echo_gain);
|
||||
memcpy (&hostorder_inputfloat_bytes, &inputfloat, sizeof (outputfloat));
|
||||
p_echo_inputdata->echo_float_bytes =
|
||||
CC_TO_BE32 (hostorder_inputfloat_bytes);
|
||||
|
||||
*size = APP_GSDML_INPUT_DATA_ECHO_SIZE;
|
||||
*iops = PNET_IOXS_GOOD;
|
||||
return echo_inputdata;
|
||||
}
|
||||
|
||||
/* Automated RT Tester scenario 2 - unsupported (sub)module */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int app_data_set_output_data (
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr,
|
||||
uint32_t submodule_id,
|
||||
uint8_t * data,
|
||||
uint16_t size)
|
||||
{
|
||||
bool led_state;
|
||||
|
||||
if (data == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (
|
||||
submodule_id == APP_GSDML_SUBMOD_ID_DIGITAL_OUT ||
|
||||
submodule_id == APP_GSDML_SUBMOD_ID_DIGITAL_IN_OUT)
|
||||
{
|
||||
if (size == APP_GSDML_OUTPUT_DATA_DIGITAL_SIZE)
|
||||
{
|
||||
memcpy (outputdata, data, size);
|
||||
|
||||
/* Most significant bit: LED */
|
||||
led_state = (outputdata[0] & 0x80) > 0;
|
||||
app_handle_data_led_state (led_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (submodule_id == APP_GSDML_SUBMOD_ID_ECHO)
|
||||
{
|
||||
if (size == APP_GSDML_OUTPUT_DATA_ECHO_SIZE)
|
||||
{
|
||||
memcpy (echo_outputdata, data, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int app_data_set_default_outputs (void)
|
||||
{
|
||||
outputdata[0] = APP_DATA_DEFAULT_OUTPUT_DATA;
|
||||
app_handle_data_led_state (false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_data_write_parameter (
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr,
|
||||
uint32_t submodule_id,
|
||||
uint32_t index,
|
||||
const uint8_t * data,
|
||||
uint16_t length)
|
||||
{
|
||||
const app_gsdml_param_t * par_cfg;
|
||||
|
||||
par_cfg = app_gsdml_get_parameter_cfg (submodule_id, index);
|
||||
if (par_cfg == NULL)
|
||||
{
|
||||
APP_LOG_WARNING (
|
||||
"PLC write request unsupported submodule/parameter. "
|
||||
"Submodule id: %u Index: %u\n",
|
||||
(unsigned)submodule_id,
|
||||
(unsigned)index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (length != par_cfg->length)
|
||||
{
|
||||
APP_LOG_WARNING (
|
||||
"PLC write request unsupported length. "
|
||||
"Index: %u Length: %u Expected length: %u\n",
|
||||
(unsigned)index,
|
||||
(unsigned)length,
|
||||
par_cfg->length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (index == APP_GSDML_PARAMETER_1_IDX)
|
||||
{
|
||||
memcpy (&app_param_1, data, length);
|
||||
}
|
||||
else if (index == APP_GSDML_PARAMETER_2_IDX)
|
||||
{
|
||||
memcpy (&app_param_2, data, length);
|
||||
}
|
||||
else if (index == APP_GSDML_PARAMETER_ECHO_IDX)
|
||||
{
|
||||
memcpy (&app_param_echo_gain, data, length);
|
||||
}
|
||||
|
||||
APP_LOG_DEBUG (" Writing parameter \"%s\"\n", par_cfg->name);
|
||||
app_log_print_bytes (APP_LOG_LEVEL_DEBUG, data, length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_data_read_parameter (
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr,
|
||||
uint32_t submodule_id,
|
||||
uint32_t index,
|
||||
uint8_t ** data,
|
||||
uint16_t * length)
|
||||
{
|
||||
const app_gsdml_param_t * par_cfg;
|
||||
|
||||
par_cfg = app_gsdml_get_parameter_cfg (submodule_id, index);
|
||||
if (par_cfg == NULL)
|
||||
{
|
||||
APP_LOG_WARNING (
|
||||
"PLC read request unsupported submodule/parameter. "
|
||||
"Submodule id: %u Index: %u\n",
|
||||
(unsigned)submodule_id,
|
||||
(unsigned)index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*length < par_cfg->length)
|
||||
{
|
||||
APP_LOG_WARNING (
|
||||
"PLC read request unsupported length. "
|
||||
"Index: %u Max length: %u Data length for our parameter: %u\n",
|
||||
(unsigned)index,
|
||||
(unsigned)*length,
|
||||
par_cfg->length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
APP_LOG_DEBUG (" Reading \"%s\"\n", par_cfg->name);
|
||||
if (index == APP_GSDML_PARAMETER_1_IDX)
|
||||
{
|
||||
*data = (uint8_t *)&app_param_1;
|
||||
*length = sizeof (app_param_1);
|
||||
}
|
||||
else if (index == APP_GSDML_PARAMETER_2_IDX)
|
||||
{
|
||||
*data = (uint8_t *)&app_param_2;
|
||||
*length = sizeof (app_param_2);
|
||||
}
|
||||
else if (index == APP_GSDML_PARAMETER_ECHO_IDX)
|
||||
{
|
||||
*data = (uint8_t *)&app_param_echo_gain;
|
||||
*length = sizeof (app_param_echo_gain);
|
||||
}
|
||||
|
||||
app_log_print_bytes (APP_LOG_LEVEL_DEBUG, *data, *length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2018 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef APP_DATA_H
|
||||
#define APP_DATA_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Sample application data interface
|
||||
*
|
||||
* Functions for:
|
||||
* - Getting input data (Button 1 and counter value)
|
||||
* - Setting output data (LED 1)
|
||||
* - Setting default output state. This should be
|
||||
* part of all device implementations for setting
|
||||
* defined state when device is not connected to PLC
|
||||
* - Reading and writing parameters
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* Get application specific PNIO input data (for sending to PLC)
|
||||
*
|
||||
* The main sample application keeps track
|
||||
* of button so it is a parameter to this function.
|
||||
*
|
||||
* This function is not called for the DAP submodules (slot_nbr==0).
|
||||
*
|
||||
* @param slot_nbr In: Slot number
|
||||
* @param subslot_nbr In: Subslot number
|
||||
* @param submodule_id In: Submodule id
|
||||
* @param button_state In: State of button 1
|
||||
* @param size Out: Size of pnio data.
|
||||
* Not modified on error.
|
||||
* @param iops Out: Provider status. If for example
|
||||
* a sensor is failing or a short
|
||||
* circuit is detected on digital
|
||||
* input this shall be set to BAD.
|
||||
* Not modified on error.
|
||||
* @return Reference to PNIO data, NULL on error
|
||||
*/
|
||||
uint8_t * app_data_get_input_data (
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr,
|
||||
uint32_t submodule_id,
|
||||
bool button_state,
|
||||
uint16_t * size,
|
||||
uint8_t * iops);
|
||||
|
||||
/**
|
||||
* Set application specific PNIO output data (received from PLC)
|
||||
*
|
||||
* This function is not called for the DAP submodules (slot_nbr==0).
|
||||
*
|
||||
* @param slot_nbr In: Slot number
|
||||
* @param subslot_nbr In: Subslot number
|
||||
* @param submodule_id In: Submodule id
|
||||
* @param data In: Reference to output data
|
||||
* @param size In: Length of output data
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int app_data_set_output_data (
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr,
|
||||
uint32_t submodule_id,
|
||||
uint8_t * data,
|
||||
uint16_t size);
|
||||
|
||||
/**
|
||||
* Set default outputs for all subslots.
|
||||
*
|
||||
* For the sample application this means that
|
||||
* LED 1 is turned off.
|
||||
*
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int app_data_set_default_outputs (void);
|
||||
|
||||
/**
|
||||
* Write parameter index for a subslot
|
||||
*
|
||||
* @param slot_nbr In: Slot number
|
||||
* @param subslot_nbr In: Subslot number
|
||||
* @param submodule_id In: Submodule id
|
||||
* @param index In: Parameter index
|
||||
* @param data In: New parameter value
|
||||
* @param write_length In: Length of parameter data
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int app_data_write_parameter (
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr,
|
||||
uint32_t submodule_id,
|
||||
uint32_t index,
|
||||
const uint8_t * data,
|
||||
uint16_t write_length);
|
||||
|
||||
/**
|
||||
* Read parameter index from a subslot
|
||||
*
|
||||
* @param slot_nbr In: Slot number
|
||||
* @param subslot_nbr In: Subslot number
|
||||
* @param submodule_id In: Submodule id
|
||||
* @param index In: Parameter index
|
||||
* @param data In: Reference to parameter data
|
||||
* @param length InOut: The maximum (in) and actual (out) length in
|
||||
* bytes of the data.
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int app_data_read_parameter (
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr,
|
||||
uint32_t submodule_id,
|
||||
uint32_t index,
|
||||
uint8_t ** data,
|
||||
uint16_t * length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* APP_DATA_H */
|
||||
@@ -1,260 +0,0 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2021 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#include "sampleapp_common.h"
|
||||
#include "app_utils.h"
|
||||
#include "app_gsdml.h"
|
||||
#include "app_log.h"
|
||||
#include "osal.h"
|
||||
#include "pnal.h"
|
||||
#include <pnet_api.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/******************* Supported modules ***************************/
|
||||
|
||||
static const app_gsdml_module_t dap_1 = {
|
||||
.id = PNET_MOD_DAP_IDENT,
|
||||
.name = "DAP 1",
|
||||
.submodules = {
|
||||
PNET_SUBMOD_DAP_IDENT,
|
||||
PNET_SUBMOD_DAP_INTERFACE_1_PORT_1_IDENT,
|
||||
PNET_SUBMOD_DAP_INTERFACE_1_PORT_2_IDENT,
|
||||
PNET_SUBMOD_DAP_INTERFACE_1_PORT_3_IDENT,
|
||||
PNET_SUBMOD_DAP_INTERFACE_1_PORT_4_IDENT,
|
||||
0}};
|
||||
|
||||
static const app_gsdml_module_t module_digital_in = {
|
||||
.id = APP_GSDML_MOD_ID_8_0_DIGITAL_IN,
|
||||
.name = "DI 8xLogicLevel",
|
||||
.submodules = {APP_GSDML_SUBMOD_ID_DIGITAL_IN, 0},
|
||||
};
|
||||
|
||||
static const app_gsdml_module_t module_digital_out = {
|
||||
.id = APP_GSDML_MOD_ID_0_8_DIGITAL_OUT,
|
||||
.name = "DO 8xLogicLevel",
|
||||
.submodules = {APP_GSDML_SUBMOD_ID_DIGITAL_OUT, 0}};
|
||||
|
||||
static const app_gsdml_module_t module_digital_in_out = {
|
||||
.id = APP_GSDML_MOD_ID_8_8_DIGITAL_IN_OUT,
|
||||
.name = "DIO 8xLogicLevel",
|
||||
.submodules = {APP_GSDML_SUBMOD_ID_DIGITAL_IN_OUT, 0}};
|
||||
|
||||
static const app_gsdml_module_t module_echo = {
|
||||
.id = APP_GSDML_MOD_ID_ECHO,
|
||||
.name = "Echo module",
|
||||
.submodules = {APP_GSDML_SUBMOD_ID_ECHO, 0}};
|
||||
|
||||
/******************* Supported submodules ************************/
|
||||
|
||||
static const app_gsdml_submodule_t dap_indentity_1 = {
|
||||
.name = "DAP Identity 1",
|
||||
.api = APP_GSDML_API,
|
||||
.id = PNET_SUBMOD_DAP_IDENT,
|
||||
.data_dir = PNET_DIR_NO_IO,
|
||||
.insize = 0,
|
||||
.outsize = 0,
|
||||
.parameters = {0}};
|
||||
|
||||
static const app_gsdml_submodule_t dap_interface_1 = {
|
||||
.name = "DAP Interface 1",
|
||||
.api = APP_GSDML_API,
|
||||
.id = PNET_SUBMOD_DAP_INTERFACE_1_IDENT,
|
||||
.data_dir = PNET_DIR_NO_IO,
|
||||
.insize = 0,
|
||||
.outsize = 0,
|
||||
.parameters = {0}};
|
||||
|
||||
static const app_gsdml_submodule_t dap_port_1 = {
|
||||
.name = "DAP Port 1",
|
||||
.api = APP_GSDML_API,
|
||||
.id = PNET_SUBMOD_DAP_INTERFACE_1_PORT_1_IDENT,
|
||||
.data_dir = PNET_DIR_NO_IO,
|
||||
.insize = 0,
|
||||
.outsize = 0,
|
||||
.parameters = {0}};
|
||||
|
||||
static const app_gsdml_submodule_t dap_port_2 = {
|
||||
.name = "DAP Port 2",
|
||||
.api = APP_GSDML_API,
|
||||
.id = PNET_SUBMOD_DAP_INTERFACE_1_PORT_2_IDENT,
|
||||
.data_dir = PNET_DIR_NO_IO,
|
||||
.insize = 0,
|
||||
.outsize = 0,
|
||||
.parameters = {0}};
|
||||
|
||||
static const app_gsdml_submodule_t dap_port_3 = {
|
||||
.name = "DAP Port 3",
|
||||
.api = APP_GSDML_API,
|
||||
.id = PNET_SUBMOD_DAP_INTERFACE_1_PORT_3_IDENT,
|
||||
.data_dir = PNET_DIR_NO_IO,
|
||||
.insize = 0,
|
||||
.outsize = 0,
|
||||
.parameters = {0}};
|
||||
|
||||
static const app_gsdml_submodule_t dap_port_4 = {
|
||||
.name = "DAP Port 4",
|
||||
.api = APP_GSDML_API,
|
||||
.id = PNET_SUBMOD_DAP_INTERFACE_1_PORT_4_IDENT,
|
||||
.data_dir = PNET_DIR_NO_IO,
|
||||
.insize = 0,
|
||||
.outsize = 0,
|
||||
.parameters = {0}};
|
||||
|
||||
static const app_gsdml_submodule_t submod_digital_in = {
|
||||
.id = APP_GSDML_SUBMOD_ID_DIGITAL_IN,
|
||||
.name = "Digital Input",
|
||||
.api = APP_GSDML_API,
|
||||
.data_dir = PNET_DIR_INPUT,
|
||||
.insize = APP_GSDML_INPUT_DATA_DIGITAL_SIZE,
|
||||
.outsize = 0,
|
||||
.parameters = {0}};
|
||||
|
||||
static const app_gsdml_submodule_t submod_digital_out = {
|
||||
.id = APP_GSDML_SUBMOD_ID_DIGITAL_OUT,
|
||||
.name = "Digital Output",
|
||||
.api = APP_GSDML_API,
|
||||
.data_dir = PNET_DIR_OUTPUT,
|
||||
.insize = 0,
|
||||
.outsize = APP_GSDML_OUTPUT_DATA_DIGITAL_SIZE,
|
||||
.parameters = {0}};
|
||||
|
||||
static const app_gsdml_submodule_t submod_digital_inout = {
|
||||
.id = APP_GSDML_SUBMOD_ID_DIGITAL_IN_OUT,
|
||||
.name = "Digital Input/Output",
|
||||
.api = APP_GSDML_API,
|
||||
.data_dir = PNET_DIR_IO,
|
||||
.insize = APP_GSDML_INPUT_DATA_DIGITAL_SIZE,
|
||||
.outsize = APP_GSDML_OUTPUT_DATA_DIGITAL_SIZE,
|
||||
.parameters = {APP_GSDML_PARAMETER_1_IDX, APP_GSDML_PARAMETER_2_IDX, 0}};
|
||||
|
||||
static const app_gsdml_submodule_t submod_echo = {
|
||||
.id = APP_GSDML_SUBMOD_ID_ECHO,
|
||||
.name = "Echo submodule",
|
||||
.api = APP_GSDML_API,
|
||||
.data_dir = PNET_DIR_IO,
|
||||
.insize = APP_GSDML_INPUT_DATA_ECHO_SIZE,
|
||||
.outsize = APP_GSDML_OUTPUT_DATA_ECHO_SIZE,
|
||||
.parameters = {APP_GSDML_PARAMETER_ECHO_IDX, 0}};
|
||||
|
||||
/** List of supported modules */
|
||||
static const app_gsdml_module_t * app_gsdml_modules[] = {
|
||||
&dap_1,
|
||||
&module_digital_in,
|
||||
&module_digital_out,
|
||||
&module_digital_in_out,
|
||||
&module_echo};
|
||||
|
||||
/** List of supported submodules */
|
||||
static const app_gsdml_submodule_t * app_gsdml_submodules[] = {
|
||||
&dap_indentity_1,
|
||||
&dap_interface_1,
|
||||
&dap_port_1,
|
||||
&dap_port_2,
|
||||
&dap_port_3,
|
||||
&dap_port_4,
|
||||
|
||||
&submod_digital_in,
|
||||
&submod_digital_out,
|
||||
&submod_digital_inout,
|
||||
|
||||
&submod_echo,
|
||||
};
|
||||
|
||||
/* List of supported parameters.
|
||||
* Note that parameters are submodule attributes.
|
||||
* This list contain all parameters while each
|
||||
* submodule list its supported parameters using
|
||||
* their indexes.
|
||||
*/
|
||||
static app_gsdml_param_t app_gsdml_parameters[] = {
|
||||
{
|
||||
.index = APP_GSDML_PARAMETER_1_IDX,
|
||||
.name = "Demo 1",
|
||||
.length = APP_GSDML_PARAMETER_LENGTH,
|
||||
},
|
||||
{
|
||||
.index = APP_GSDML_PARAMETER_2_IDX,
|
||||
.name = "Demo 2",
|
||||
.length = APP_GSDML_PARAMETER_LENGTH,
|
||||
},
|
||||
{
|
||||
.index = APP_GSDML_PARAMETER_ECHO_IDX,
|
||||
.name = "Echo gain setting",
|
||||
.length = APP_GSDML_PARAMETER_LENGTH,
|
||||
}};
|
||||
|
||||
const app_gsdml_module_t * app_gsdml_get_module_cfg (uint32_t id)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < NELEMENTS (app_gsdml_modules); i++)
|
||||
{
|
||||
if (app_gsdml_modules[i]->id == id)
|
||||
{
|
||||
return app_gsdml_modules[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const app_gsdml_submodule_t * app_gsdml_get_submodule_cfg (uint32_t id)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < NELEMENTS (app_gsdml_submodules); i++)
|
||||
{
|
||||
if (app_gsdml_submodules[i]->id == id)
|
||||
{
|
||||
return app_gsdml_submodules[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const app_gsdml_param_t * app_gsdml_get_parameter_cfg (
|
||||
uint32_t submodule_id,
|
||||
uint32_t index)
|
||||
{
|
||||
uint16_t i;
|
||||
uint16_t j;
|
||||
|
||||
const app_gsdml_submodule_t * submodule_cfg =
|
||||
app_gsdml_get_submodule_cfg (submodule_id);
|
||||
|
||||
if (submodule_cfg == NULL)
|
||||
{
|
||||
/* Unsupported submodule id */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Search for parameter index in submodule configuration */
|
||||
for (i = 0; submodule_cfg->parameters[i] != 0; i++)
|
||||
{
|
||||
if (submodule_cfg->parameters[i] == index)
|
||||
{
|
||||
/* Find parameter configuration */
|
||||
for (j = 0; j < NELEMENTS (app_gsdml_parameters); j++)
|
||||
{
|
||||
if (app_gsdml_parameters[j].index == index)
|
||||
{
|
||||
return &app_gsdml_parameters[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2018 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef APP_GSDML_H
|
||||
#define APP_GSDML_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Device properties defined by the GSDML device definition
|
||||
*
|
||||
* Functions for getting module, submodule and parameter
|
||||
* configurations using their ids.
|
||||
*
|
||||
* Important:
|
||||
* Any change in this file may require an update of the GSDML file.
|
||||
* Note that when the GSDML file is updated it has to be reloaded
|
||||
* in your Profinet engineering tool. PLC applications may be affected.
|
||||
*
|
||||
* Design requires unique submodule IDs and unique parameter indexes.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <pnet_api.h>
|
||||
|
||||
#define APP_GSDML_API 0
|
||||
|
||||
#define APP_GSDML_DEFAULT_STATION_NAME "infix"
|
||||
|
||||
/* GSDML tag: VendorID */
|
||||
#define APP_GSDML_VENDOR_ID 0x0493
|
||||
|
||||
/* GSDML tag: DeviceID */
|
||||
#define APP_GSDML_DEVICE_ID 0x0002
|
||||
|
||||
/* Used in DCP communication */
|
||||
#define APP_GSDML_OEM_VENDOR_ID 0xcafe
|
||||
#define APP_GSDML_OEM_DEVICE_ID 0xee02
|
||||
|
||||
/* Used in I&M0 */
|
||||
#define APP_GSDML_IM_HARDWARE_REVISION 3
|
||||
#define APP_GSDML_IM_VERSION_MAJOR 1
|
||||
#define APP_GSDML_IM_VERSION_MINOR 2
|
||||
|
||||
/* Allowed: 'V', 'R', 'P', 'U', 'T' */
|
||||
#define APP_GSDML_SW_REV_PREFIX 'V'
|
||||
#define APP_GSDML_PROFILE_ID 0x1234
|
||||
#define APP_GSDML_PROFILE_SPEC_TYPE 0x5678
|
||||
#define APP_GSDML_IM_REVISION_COUNTER 0 /* Typically 0 */
|
||||
|
||||
/* Note: You need to read out the actual hardware serial number instead */
|
||||
#define APP_GSDML_EXAMPLE_SERIAL_NUMBER "007"
|
||||
|
||||
/* Initial values. Can be overwritten by PLC */
|
||||
#define APP_GSDML_TAG_FUNCTION "my function"
|
||||
#define APP_GSDML_TAG_LOCATION "my location"
|
||||
#define APP_GSDML_IM_DATE "2022-03-01 10:03"
|
||||
#define APP_GSDML_DESCRIPTOR "my descriptor"
|
||||
#define APP_GSDML_SIGNATURE ""
|
||||
|
||||
/* GSDML tag: Writeable_IM_Records */
|
||||
#define APP_GSDML_IM_SUPPORTED \
|
||||
(PNET_SUPPORTED_IM1 | PNET_SUPPORTED_IM2 | PNET_SUPPORTED_IM3)
|
||||
|
||||
/* GSDML tag: OrderNumber */
|
||||
#define APP_GSDML_ORDER_ID "12345 Abcdefghijk"
|
||||
|
||||
/* GSDML tag: ModuleInfo / Name */
|
||||
#define APP_GSDML_PRODUCT_NAME "Infix Switch 10p"
|
||||
|
||||
/* GSDML tag: MinDeviceInterval */
|
||||
#define APP_GSDML_MIN_DEVICE_INTERVAL 32 /* 1 ms */
|
||||
|
||||
#define APP_GSDML_DIAG_CUSTOM_USI 0x1234
|
||||
|
||||
/* See "Specification for GSDML" 8.26 LogBookEntryItem for allowed values */
|
||||
#define APP_GSDML_LOGBOOK_ERROR_CODE 0x20 /* Manufacturer specific */
|
||||
#define APP_GSDML_LOGBOOK_ERROR_DECODE 0x82 /* Manufacturer specific */
|
||||
#define APP_GSDML_LOGBOOK_ERROR_CODE_1 PNET_ERROR_CODE_1_FSPM
|
||||
#define APP_GSDML_LOGBOOK_ERROR_CODE_2 0x00 /* Manufacturer specific */
|
||||
#define APP_GSDML_LOGBOOK_ENTRY_DETAIL 0xFEE1DEAD /* Manufacturer specific */
|
||||
|
||||
#define APP_GSDML_PARAMETER_1_IDX 123
|
||||
#define APP_GSDML_PARAMETER_2_IDX 124
|
||||
#define APP_GSDML_PARAMETER_ECHO_IDX 125
|
||||
|
||||
/* Use same size for all parameters in example */
|
||||
#define APP_GSDML_PARAMETER_LENGTH 4
|
||||
|
||||
#define APP_GSDML_DEFAULT_MAUTYPE 0x10 /* Copper 100 Mbit/s Full duplex */
|
||||
|
||||
typedef struct app_gsdml_module
|
||||
{
|
||||
uint32_t id;
|
||||
|
||||
/** Module name */
|
||||
const char * name;
|
||||
|
||||
/** Submodule IDs. Variable length, ends with 0. */
|
||||
uint32_t submodules[];
|
||||
} app_gsdml_module_t;
|
||||
|
||||
typedef struct app_gsdml_submodule
|
||||
{
|
||||
uint32_t id;
|
||||
|
||||
/** Submodule name */
|
||||
const char * name;
|
||||
|
||||
uint32_t api;
|
||||
pnet_submodule_dir_t data_dir;
|
||||
uint16_t insize;
|
||||
uint16_t outsize;
|
||||
|
||||
/** Parameter indexes. See app_gsdml_parameters.
|
||||
* Variable length, ends with 0. */
|
||||
uint16_t parameters[];
|
||||
} app_gsdml_submodule_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t index;
|
||||
const char * name;
|
||||
uint16_t length;
|
||||
} app_gsdml_param_t;
|
||||
|
||||
#define APP_GSDML_MOD_ID_8_0_DIGITAL_IN 0x00000030
|
||||
#define APP_GSDML_MOD_ID_0_8_DIGITAL_OUT 0x00000031
|
||||
#define APP_GSDML_MOD_ID_8_8_DIGITAL_IN_OUT 0x00000032
|
||||
#define APP_GSDML_MOD_ID_ECHO 0x00000040
|
||||
#define APP_GSDML_SUBMOD_ID_DIGITAL_IN 0x00000130
|
||||
#define APP_GSDML_SUBMOD_ID_DIGITAL_OUT 0x00000131
|
||||
#define APP_GSDML_SUBMOD_ID_DIGITAL_IN_OUT 0x00000132
|
||||
#define APP_GSDML_SUBMOD_ID_ECHO 0x00000140
|
||||
#define APP_GSDML_INPUT_DATA_DIGITAL_SIZE 1 /* bytes */
|
||||
#define APP_GSDML_OUTPUT_DATA_DIGITAL_SIZE 1 /* bytes */
|
||||
#define APP_GSDML_INPUT_DATA_ECHO_SIZE 8 /* bytes */
|
||||
#define APP_GSDML_OUTPUT_DATA_ECHO_SIZE APP_GSDML_INPUT_DATA_ECHO_SIZE
|
||||
#define APP_GSDML_ALARM_PAYLOAD_SIZE 1 /* bytes */
|
||||
|
||||
/**
|
||||
* Get module configuration from module ID
|
||||
* @param module_id In: Module ID
|
||||
* @return Module configuration, NULL if not found
|
||||
*/
|
||||
const app_gsdml_module_t * app_gsdml_get_module_cfg (uint32_t module_id);
|
||||
|
||||
/**
|
||||
* Get submodule module configuration from submodule ID
|
||||
* @param submodule_id In: Submodule ID
|
||||
* @return Submodule configuration, NULL if not found
|
||||
*/
|
||||
const app_gsdml_submodule_t * app_gsdml_get_submodule_cfg (
|
||||
uint32_t submodule_id);
|
||||
|
||||
/**
|
||||
* Get parameter configuration from parameter index
|
||||
* @param submodule_id In: Submodule ID
|
||||
* @param index In: Parameters index
|
||||
* @return Parameter configuration, NULL if not found
|
||||
*/
|
||||
const app_gsdml_param_t * app_gsdml_get_parameter_cfg (
|
||||
uint32_t submodule_id,
|
||||
uint32_t index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* APP_GSDML_H */
|
||||
@@ -1,52 +0,0 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2021 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#include "app_log.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static int32_t log_level = APP_DEFAULT_LOG_LEVEL;
|
||||
|
||||
void app_log_set_log_level (int32_t level)
|
||||
{
|
||||
log_level = level;
|
||||
}
|
||||
|
||||
void app_log (int32_t level, const char * fmt, ...)
|
||||
{
|
||||
va_list list;
|
||||
|
||||
if (level >= log_level)
|
||||
{
|
||||
va_start (list, fmt);
|
||||
vprintf (fmt, list);
|
||||
va_end (list);
|
||||
fflush (stdout);
|
||||
}
|
||||
}
|
||||
|
||||
void app_log_print_bytes (int32_t level, const uint8_t * bytes, uint32_t len)
|
||||
{
|
||||
if (level >= log_level)
|
||||
{
|
||||
printf (" Bytes: ");
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
{
|
||||
printf ("%02X ", bytes[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2018 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef APP_LOG_H
|
||||
#define APP_LOG_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Application debug log utility
|
||||
*
|
||||
* Runtime configurable debug log using printf()
|
||||
* Levels matches levels used in P-Net.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define APP_LOG_LEVEL_DEBUG 0x00
|
||||
#define APP_LOG_LEVEL_INFO 0x01
|
||||
#define APP_LOG_LEVEL_WARNING 0x02
|
||||
#define APP_LOG_LEVEL_ERROR 0x03
|
||||
#define APP_LOG_LEVEL_FATAL 0x04
|
||||
|
||||
#define APP_DEFAULT_LOG_LEVEL APP_LOG_LEVEL_FATAL
|
||||
|
||||
#define APP_LOG(level, ...) app_log (level, __VA_ARGS__)
|
||||
|
||||
#define APP_LOG_DEBUG(...) APP_LOG (APP_LOG_LEVEL_DEBUG, __VA_ARGS__)
|
||||
#define APP_LOG_INFO(...) APP_LOG (APP_LOG_LEVEL_INFO, __VA_ARGS__)
|
||||
#define APP_LOG_WARNING(...) APP_LOG (APP_LOG_LEVEL_WARNING, __VA_ARGS__)
|
||||
#define APP_LOG_ERROR(...) APP_LOG (APP_LOG_LEVEL_ERROR, __VA_ARGS__)
|
||||
#define APP_LOG_FATAL(...) APP_LOG (APP_LOG_LEVEL_FATAL, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Print log message depending on level
|
||||
* Use the APP_LOG_xxxxx macros instead of this function.
|
||||
* @param level In: Message log level
|
||||
* @param fmt In: Log message format string
|
||||
*/
|
||||
void app_log (int32_t level, const char * fmt, ...);
|
||||
|
||||
/**
|
||||
* Log an array of bytes
|
||||
* @param level In: Log level
|
||||
* @param bytes In: Array of bytes
|
||||
* @param length In: Length of array
|
||||
*/
|
||||
void app_log_print_bytes (int32_t level, const uint8_t * bytes, uint32_t length);
|
||||
|
||||
/**
|
||||
* Set log level
|
||||
* @param level In: Log level
|
||||
*/
|
||||
void app_log_set_log_level (int32_t level);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* APP_LOG_H */
|
||||
@@ -1,878 +0,0 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2021 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#define _GNU_SOURCE /* For asprintf() */
|
||||
|
||||
#include "app_utils.h"
|
||||
#include "app_log.h"
|
||||
#include "app_gsdml.h"
|
||||
#include "sampleapp_common.h"
|
||||
#include "osal.h"
|
||||
#include "osal_log.h" /* For LOG_LEVEL */
|
||||
#include "pnal.h"
|
||||
#include <pnet_api.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define GET_HIGH_BYTE(id) ((id >> 8) & 0xFF)
|
||||
#define GET_LOW_BYTE(id) (id & 0xFF)
|
||||
|
||||
int app_ar_add_arep (app_api_t * api, uint32_t arep, app_ar_t ** ar)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
CC_ASSERT (api != NULL);
|
||||
CC_ASSERT (ar != NULL);
|
||||
for (i = 0; i < PNET_MAX_AR; ++i)
|
||||
{
|
||||
if (api->ar[i].arep == UINT32_MAX)
|
||||
{
|
||||
api->ar[i].arep = arep;
|
||||
api->ar[i].events = 0;
|
||||
*ar = api->ar + i;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t app_ar_arep (app_ar_t * ar)
|
||||
{
|
||||
CC_ASSERT (ar != NULL);
|
||||
return ar->arep;
|
||||
}
|
||||
|
||||
void app_ar_event_set (app_ar_t * ar, uint32_t event)
|
||||
{
|
||||
CC_ASSERT (ar != NULL);
|
||||
ar->events |= event;
|
||||
}
|
||||
|
||||
int app_ar_event_clr (app_ar_t * ar, uint32_t event)
|
||||
{
|
||||
CC_ASSERT (ar != NULL);
|
||||
if (ar->events & event)
|
||||
{
|
||||
ar->events &= ~event;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void app_ar_iterator_init (
|
||||
app_ar_iterator_t * iterator,
|
||||
app_api_t * api)
|
||||
{
|
||||
CC_ASSERT (iterator != NULL);
|
||||
CC_ASSERT (api != NULL);
|
||||
iterator->ar = api->ar;
|
||||
iterator->index = -1;
|
||||
iterator->modified = false;
|
||||
}
|
||||
|
||||
int app_ar_iterator_next (app_ar_iterator_t * iterator, app_ar_t ** ar)
|
||||
{
|
||||
#if PNET_MAX_AR > 1
|
||||
uint16_t i;
|
||||
uint16_t j;
|
||||
#endif
|
||||
|
||||
CC_ASSERT (iterator != NULL);
|
||||
CC_ASSERT (ar != NULL);
|
||||
++iterator->index;
|
||||
if (
|
||||
(iterator->index < PNET_MAX_AR) &&
|
||||
(iterator->ar[iterator->index].arep != UINT32_MAX))
|
||||
{
|
||||
*ar = iterator->ar + iterator->index;
|
||||
return 1;
|
||||
}
|
||||
#if PNET_MAX_AR > 1
|
||||
else if (iterator->modified)
|
||||
{
|
||||
for (i = 0; i < PNET_MAX_AR; ++i)
|
||||
{
|
||||
if (iterator->ar[i].arep == UINT32_MAX)
|
||||
{
|
||||
for (j = i + 1; j < PNET_MAX_AR; ++j)
|
||||
{
|
||||
if (iterator->ar[j].arep != UINT32_MAX)
|
||||
{
|
||||
iterator->ar[i] = iterator->ar[j];
|
||||
iterator->ar[j].arep = UINT32_MAX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j >= PNET_MAX_AR - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_ar_iterator_done (app_ar_iterator_t * iterator)
|
||||
{
|
||||
CC_ASSERT (iterator != NULL);
|
||||
if (
|
||||
(iterator->index < 0) ||
|
||||
((iterator->index < PNET_MAX_AR) &&
|
||||
(iterator->ar[iterator->index].arep != UINT32_MAX)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void app_ar_iterator_delete_current (app_ar_iterator_t * iterator)
|
||||
{
|
||||
CC_ASSERT (iterator != NULL);
|
||||
CC_ASSERT (iterator->index >= 0);
|
||||
if (iterator->index < PNET_MAX_AR)
|
||||
{
|
||||
iterator->ar[iterator->index].arep = UINT32_MAX;
|
||||
iterator->modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
void app_utils_ip_to_string (pnal_ipaddr_t ip, char * outputstring)
|
||||
{
|
||||
snprintf (
|
||||
outputstring,
|
||||
PNAL_INET_ADDRSTR_SIZE,
|
||||
"%u.%u.%u.%u",
|
||||
(uint8_t)((ip >> 24) & 0xFF),
|
||||
(uint8_t)((ip >> 16) & 0xFF),
|
||||
(uint8_t)((ip >> 8) & 0xFF),
|
||||
(uint8_t)(ip & 0xFF));
|
||||
}
|
||||
|
||||
void app_utils_mac_to_string (pnet_ethaddr_t mac, char * outputstring)
|
||||
{
|
||||
snprintf (
|
||||
outputstring,
|
||||
PNAL_ETH_ADDRSTR_SIZE,
|
||||
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
mac.addr[0],
|
||||
mac.addr[1],
|
||||
mac.addr[2],
|
||||
mac.addr[3],
|
||||
mac.addr[4],
|
||||
mac.addr[5]);
|
||||
}
|
||||
|
||||
const char * app_utils_submod_dir_to_string (pnet_submodule_dir_t direction)
|
||||
{
|
||||
const char * s = "<error>";
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case PNET_DIR_NO_IO:
|
||||
s = "NO_IO";
|
||||
break;
|
||||
case PNET_DIR_INPUT:
|
||||
s = "INPUT";
|
||||
break;
|
||||
case PNET_DIR_OUTPUT:
|
||||
s = "OUTPUT";
|
||||
break;
|
||||
case PNET_DIR_IO:
|
||||
s = "INPUT_OUTPUT";
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
const char * app_utils_ioxs_to_string (pnet_ioxs_values_t ioxs)
|
||||
{
|
||||
const char * s = "<error>";
|
||||
switch (ioxs)
|
||||
{
|
||||
case PNET_IOXS_BAD:
|
||||
s = "IOXS_BAD";
|
||||
break;
|
||||
case PNET_IOXS_GOOD:
|
||||
s = "IOXS_GOOD";
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void app_utils_get_error_code_strings (
|
||||
uint16_t err_cls,
|
||||
uint16_t err_code,
|
||||
const char ** err_cls_str,
|
||||
const char ** err_code_str)
|
||||
{
|
||||
if (err_cls_str == NULL || err_cls_str == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
*err_cls_str = "Not decoded";
|
||||
*err_code_str = "Not decoded";
|
||||
|
||||
switch (err_cls)
|
||||
{
|
||||
case PNET_ERROR_CODE_1_RTA_ERR_CLS_PROTOCOL:
|
||||
*err_cls_str = "Real-Time Acyclic Protocol";
|
||||
switch (err_code)
|
||||
{
|
||||
case PNET_ERROR_CODE_2_ABORT_AR_CONSUMER_DHT_EXPIRED:
|
||||
*err_code_str = "Device missed cyclic data "
|
||||
"deadline, device terminated AR";
|
||||
break;
|
||||
case PNET_ERROR_CODE_2_ABORT_AR_CMI_TIMEOUT:
|
||||
*err_code_str = "Communication initialization "
|
||||
"timeout, device terminated AR";
|
||||
break;
|
||||
case PNET_ERROR_CODE_2_ABORT_AR_RELEASE_IND_RECEIVED:
|
||||
*err_code_str = "AR release indication received";
|
||||
break;
|
||||
case PNET_ERROR_CODE_2_ABORT_AR_RPC_READ_ERROR:
|
||||
*err_code_str = "AR RPC-Read error";
|
||||
break;
|
||||
case PNET_ERROR_CODE_2_ABORT_DCP_STATION_NAME_CHANGED:
|
||||
*err_code_str = "DCP station name changed, "
|
||||
"device terminated AR";
|
||||
break;
|
||||
case PNET_ERROR_CODE_2_ABORT_DCP_RESET_TO_FACTORY:
|
||||
*err_code_str = "DCP reset to factory or factory "
|
||||
"reset, device terminated AR";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PNET_ERROR_CODE_1_CTLDINA:
|
||||
*err_cls_str = "CTLDINA = Name and IP assignment from controller";
|
||||
switch (err_code)
|
||||
{
|
||||
case PNET_ERROR_CODE_2_CTLDINA_ARP_MULTIPLE_IP_ADDRESSES:
|
||||
*err_code_str = "Multiple users of same IP address";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void app_utils_copy_ip_to_struct (
|
||||
pnet_cfg_ip_addr_t * destination_struct,
|
||||
pnal_ipaddr_t ip)
|
||||
{
|
||||
destination_struct->a = ((ip >> 24) & 0xFF);
|
||||
destination_struct->b = ((ip >> 16) & 0xFF);
|
||||
destination_struct->c = ((ip >> 8) & 0xFF);
|
||||
destination_struct->d = (ip & 0xFF);
|
||||
}
|
||||
|
||||
const char * app_utils_dcontrol_cmd_to_string (
|
||||
pnet_control_command_t control_command)
|
||||
{
|
||||
const char * s = NULL;
|
||||
|
||||
switch (control_command)
|
||||
{
|
||||
case PNET_CONTROL_COMMAND_PRM_BEGIN:
|
||||
s = "PRM_BEGIN";
|
||||
break;
|
||||
case PNET_CONTROL_COMMAND_PRM_END:
|
||||
s = "PRM_END";
|
||||
break;
|
||||
case PNET_CONTROL_COMMAND_APP_RDY:
|
||||
s = "APP_RDY";
|
||||
break;
|
||||
case PNET_CONTROL_COMMAND_RELEASE:
|
||||
s = "RELEASE";
|
||||
break;
|
||||
default:
|
||||
s = "<error>";
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
const char * app_utils_event_to_string (pnet_event_values_t event)
|
||||
{
|
||||
const char * s = "<error>";
|
||||
|
||||
switch (event)
|
||||
{
|
||||
case PNET_EVENT_ABORT:
|
||||
s = "PNET_EVENT_ABORT";
|
||||
break;
|
||||
case PNET_EVENT_STARTUP:
|
||||
s = "PNET_EVENT_STARTUP";
|
||||
break;
|
||||
case PNET_EVENT_PRMEND:
|
||||
s = "PNET_EVENT_PRMEND";
|
||||
break;
|
||||
case PNET_EVENT_APPLRDY:
|
||||
s = "PNET_EVENT_APPLRDY";
|
||||
break;
|
||||
case PNET_EVENT_DATA:
|
||||
s = "PNET_EVENT_DATA";
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int app_utils_pnet_cfg_init_default (pnet_cfg_t * cfg)
|
||||
{
|
||||
memset (cfg, 0, sizeof (pnet_cfg_t));
|
||||
|
||||
cfg->tick_us = APP_TICK_INTERVAL_US;
|
||||
|
||||
/* Identification & Maintenance */
|
||||
|
||||
cfg->im_0_data.im_vendor_id_hi = GET_HIGH_BYTE (APP_GSDML_VENDOR_ID);
|
||||
cfg->im_0_data.im_vendor_id_lo = GET_LOW_BYTE (APP_GSDML_VENDOR_ID);
|
||||
|
||||
cfg->im_0_data.im_hardware_revision = APP_GSDML_IM_HARDWARE_REVISION;
|
||||
cfg->im_0_data.im_sw_revision_prefix = APP_GSDML_SW_REV_PREFIX;
|
||||
cfg->im_0_data.im_sw_revision_functional_enhancement = PNET_VERSION_MAJOR;
|
||||
cfg->im_0_data.im_sw_revision_bug_fix = PNET_VERSION_MINOR;
|
||||
cfg->im_0_data.im_sw_revision_internal_change = PNET_VERSION_PATCH;
|
||||
cfg->im_0_data.im_revision_counter = APP_GSDML_IM_REVISION_COUNTER;
|
||||
cfg->im_0_data.im_profile_id = APP_GSDML_PROFILE_ID;
|
||||
cfg->im_0_data.im_profile_specific_type = APP_GSDML_PROFILE_SPEC_TYPE;
|
||||
cfg->im_0_data.im_version_major = 1; /** Always 1 */
|
||||
cfg->im_0_data.im_version_minor = 1; /** Always 1 */
|
||||
cfg->im_0_data.im_supported = APP_GSDML_IM_SUPPORTED;
|
||||
|
||||
snprintf (
|
||||
cfg->im_0_data.im_order_id,
|
||||
sizeof (cfg->im_0_data.im_order_id),
|
||||
"%s",
|
||||
APP_GSDML_ORDER_ID);
|
||||
snprintf (
|
||||
cfg->im_0_data.im_serial_number,
|
||||
sizeof (cfg->im_0_data.im_serial_number),
|
||||
"%s",
|
||||
APP_GSDML_EXAMPLE_SERIAL_NUMBER);
|
||||
snprintf (
|
||||
cfg->im_1_data.im_tag_function,
|
||||
sizeof (cfg->im_1_data.im_tag_function),
|
||||
"%s",
|
||||
APP_GSDML_TAG_FUNCTION);
|
||||
snprintf (
|
||||
cfg->im_1_data.im_tag_location,
|
||||
sizeof (cfg->im_1_data.im_tag_location),
|
||||
"%s",
|
||||
APP_GSDML_TAG_LOCATION);
|
||||
snprintf (
|
||||
cfg->im_2_data.im_date,
|
||||
sizeof (cfg->im_2_data.im_date),
|
||||
"%s",
|
||||
APP_GSDML_IM_DATE);
|
||||
snprintf (
|
||||
cfg->im_3_data.im_descriptor,
|
||||
sizeof (cfg->im_3_data.im_descriptor),
|
||||
"%s",
|
||||
APP_GSDML_DESCRIPTOR);
|
||||
snprintf (
|
||||
cfg->im_4_data.im_signature,
|
||||
sizeof (cfg->im_4_data.im_signature),
|
||||
"%s",
|
||||
APP_GSDML_SIGNATURE);
|
||||
|
||||
/* Device configuration */
|
||||
cfg->device_id.vendor_id_hi = GET_HIGH_BYTE (APP_GSDML_VENDOR_ID);
|
||||
cfg->device_id.vendor_id_lo = GET_LOW_BYTE (APP_GSDML_VENDOR_ID);
|
||||
cfg->device_id.device_id_hi = GET_HIGH_BYTE (APP_GSDML_DEVICE_ID);
|
||||
cfg->device_id.device_id_lo = GET_LOW_BYTE (APP_GSDML_DEVICE_ID);
|
||||
cfg->oem_device_id.vendor_id_hi = GET_HIGH_BYTE (APP_GSDML_OEM_VENDOR_ID);
|
||||
cfg->oem_device_id.vendor_id_lo = GET_LOW_BYTE (APP_GSDML_OEM_VENDOR_ID);
|
||||
cfg->oem_device_id.device_id_hi = GET_HIGH_BYTE (APP_GSDML_OEM_DEVICE_ID);
|
||||
cfg->oem_device_id.device_id_lo = GET_LOW_BYTE (APP_GSDML_OEM_DEVICE_ID);
|
||||
|
||||
snprintf (
|
||||
cfg->product_name,
|
||||
sizeof (cfg->product_name),
|
||||
"%s",
|
||||
APP_GSDML_PRODUCT_NAME);
|
||||
|
||||
cfg->send_hello = true;
|
||||
|
||||
/* Timing */
|
||||
cfg->min_device_interval = APP_GSDML_MIN_DEVICE_INTERVAL;
|
||||
|
||||
/* Should be set by application as part of network configuration. */
|
||||
cfg->num_physical_ports = 1;
|
||||
|
||||
snprintf (
|
||||
cfg->station_name,
|
||||
sizeof (cfg->station_name),
|
||||
"%s",
|
||||
APP_GSDML_DEFAULT_STATION_NAME);
|
||||
|
||||
/* Diagnosis mechanism */
|
||||
/* We prefer using "Extended channel diagnosis" instead of
|
||||
* "Qualified channel diagnosis" format on the wire,
|
||||
* as this is better supported by Wireshark.
|
||||
*/
|
||||
cfg->use_qualified_diagnosis = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_utils_get_netif_namelist (
|
||||
const char * arg_str,
|
||||
uint16_t max_port,
|
||||
app_utils_netif_namelist_t * p_if_list,
|
||||
uint16_t * p_num_ports)
|
||||
{
|
||||
int ret = 0;
|
||||
uint16_t i = 0;
|
||||
uint16_t j = 0;
|
||||
uint16_t if_index = 0;
|
||||
uint16_t number_of_given_names = 1;
|
||||
uint16_t if_list_size = max_port + 1;
|
||||
char c;
|
||||
|
||||
if (max_port == 0)
|
||||
{
|
||||
printf ("Error: max_port is 0.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset (p_if_list, 0, sizeof (*p_if_list));
|
||||
c = arg_str[i++];
|
||||
while (c != '\0')
|
||||
{
|
||||
if (c != ',')
|
||||
{
|
||||
if (if_index < if_list_size)
|
||||
{
|
||||
p_if_list->netif[if_index].name[j++] = c;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (if_index < if_list_size)
|
||||
{
|
||||
p_if_list->netif[if_index].name[j++] = '\0';
|
||||
j = 0;
|
||||
if_index++;
|
||||
}
|
||||
number_of_given_names++;
|
||||
}
|
||||
|
||||
c = arg_str[i++];
|
||||
}
|
||||
|
||||
if (max_port == 1 && number_of_given_names > 1)
|
||||
{
|
||||
printf ("Error: Only 1 network interface expected as max_port is 1.\n");
|
||||
return -1;
|
||||
}
|
||||
if (number_of_given_names == 2)
|
||||
{
|
||||
printf ("Error: It is illegal to give 2 interface names. Use 1, or one "
|
||||
"more than the number of physical interfaces.\n");
|
||||
return -1;
|
||||
}
|
||||
if (number_of_given_names > max_port + 1)
|
||||
{
|
||||
printf (
|
||||
"Error: You have given %u interface names, but max is %u as "
|
||||
"PNET_MAX_PHYSICAL_PORTS is %u.\n",
|
||||
number_of_given_names,
|
||||
max_port + 1,
|
||||
max_port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (number_of_given_names == 1)
|
||||
{
|
||||
if (strlen (p_if_list->netif[0].name) == 0)
|
||||
{
|
||||
printf ("Error: Zero length network interface name.\n");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_if_list->netif[1] = p_if_list->netif[0];
|
||||
*p_num_ports = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < number_of_given_names; i++)
|
||||
{
|
||||
if (strlen (p_if_list->netif[i].name) == 0)
|
||||
{
|
||||
printf ("Error: Zero length network interface name (%d).\n", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
*p_num_ports = number_of_given_names - 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int app_utils_pnet_cfg_init_netifs (
|
||||
const char * netif_list_str,
|
||||
app_utils_netif_namelist_t * if_list,
|
||||
uint16_t * number_of_ports,
|
||||
pnet_if_cfg_t * if_cfg)
|
||||
{
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
pnal_ipaddr_t ip;
|
||||
pnal_ipaddr_t netmask;
|
||||
pnal_ipaddr_t gateway;
|
||||
|
||||
ret = app_utils_get_netif_namelist (
|
||||
netif_list_str,
|
||||
PNET_MAX_PHYSICAL_PORTS,
|
||||
if_list,
|
||||
number_of_ports);
|
||||
if (ret != 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
if_cfg->main_netif_name = if_list->netif[0].name;
|
||||
|
||||
for (i = 1; i <= *number_of_ports; i++)
|
||||
{
|
||||
if_cfg->physical_ports[i - 1].netif_name = if_list->netif[i].name;
|
||||
if_cfg->physical_ports[i - 1].default_mau_type =
|
||||
APP_GSDML_DEFAULT_MAUTYPE;
|
||||
}
|
||||
|
||||
/* Read IP, netmask, gateway from operating system */
|
||||
if (pnal_get_ipmask(if_cfg->main_netif_name, &ip, &netmask))
|
||||
{
|
||||
APP_LOG_INFO ("No valid interface address on %s yet.", if_cfg->main_netif_name);
|
||||
}
|
||||
gateway = pnal_get_gateway(if_cfg->main_netif_name);
|
||||
if (gateway == PNAL_IPADDR_INVALID)
|
||||
{
|
||||
APP_LOG_INFO ("System has no default gateway set.\n");
|
||||
}
|
||||
|
||||
app_utils_copy_ip_to_struct (&if_cfg->ip_cfg.ip_addr, ip);
|
||||
app_utils_copy_ip_to_struct (&if_cfg->ip_cfg.ip_gateway, gateway);
|
||||
app_utils_copy_ip_to_struct (&if_cfg->ip_cfg.ip_mask, netmask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void app_utils_print_mac_address (const char * netif_name)
|
||||
{
|
||||
pnal_ethaddr_t pnal_mac_addr;
|
||||
if (pnal_get_macaddress (netif_name, &pnal_mac_addr) == 0)
|
||||
{
|
||||
APP_LOG_INFO (
|
||||
"%02X:%02X:%02X:%02X:%02X:%02X\n",
|
||||
pnal_mac_addr.addr[0],
|
||||
pnal_mac_addr.addr[1],
|
||||
pnal_mac_addr.addr[2],
|
||||
pnal_mac_addr.addr[3],
|
||||
pnal_mac_addr.addr[4],
|
||||
pnal_mac_addr.addr[5]);
|
||||
}
|
||||
else
|
||||
{
|
||||
APP_LOG_ERROR ("Failed read mac address\n");
|
||||
}
|
||||
}
|
||||
|
||||
void app_utils_print_network_config (
|
||||
pnet_if_cfg_t * if_cfg,
|
||||
uint16_t number_of_ports)
|
||||
{
|
||||
uint16_t i;
|
||||
char hostname_string[PNAL_HOSTNAME_MAX_SIZE]; /* Terminated string */
|
||||
|
||||
APP_LOG_INFO ("Management port: %s ", if_cfg->main_netif_name);
|
||||
app_utils_print_mac_address (if_cfg->main_netif_name);
|
||||
for (i = 1; i <= number_of_ports; i++)
|
||||
{
|
||||
APP_LOG_INFO (
|
||||
"Physical port [%u]: %s ",
|
||||
i,
|
||||
if_cfg->physical_ports[i - 1].netif_name);
|
||||
|
||||
app_utils_print_mac_address (if_cfg->physical_ports[i - 1].netif_name);
|
||||
}
|
||||
|
||||
if (pnal_get_hostname (hostname_string) != 0)
|
||||
{
|
||||
hostname_string[0] = '\0';
|
||||
}
|
||||
|
||||
APP_LOG_INFO ("Hostname: %s\n", hostname_string);
|
||||
APP_LOG_INFO (
|
||||
"IP address: %u.%u.%u.%u\n",
|
||||
if_cfg->ip_cfg.ip_addr.a,
|
||||
if_cfg->ip_cfg.ip_addr.b,
|
||||
if_cfg->ip_cfg.ip_addr.c,
|
||||
if_cfg->ip_cfg.ip_addr.d);
|
||||
APP_LOG_INFO (
|
||||
"Netmask: %u.%u.%u.%u\n",
|
||||
if_cfg->ip_cfg.ip_mask.a,
|
||||
if_cfg->ip_cfg.ip_mask.b,
|
||||
if_cfg->ip_cfg.ip_mask.c,
|
||||
if_cfg->ip_cfg.ip_mask.d);
|
||||
APP_LOG_INFO (
|
||||
"Gateway: %u.%u.%u.%u\n",
|
||||
if_cfg->ip_cfg.ip_gateway.a,
|
||||
if_cfg->ip_cfg.ip_gateway.b,
|
||||
if_cfg->ip_cfg.ip_gateway.c,
|
||||
if_cfg->ip_cfg.ip_gateway.d);
|
||||
}
|
||||
|
||||
void app_utils_print_ioxs_change (
|
||||
const app_subslot_t * subslot,
|
||||
const char * ioxs_str,
|
||||
uint8_t ioxs_current,
|
||||
uint8_t ioxs_new)
|
||||
{
|
||||
if (ioxs_current != ioxs_new)
|
||||
{
|
||||
if (ioxs_new == PNET_IOXS_BAD)
|
||||
{
|
||||
APP_LOG_DEBUG (
|
||||
"PLC reports %s BAD for slot %u subslot %u \"%s\"\n",
|
||||
ioxs_str,
|
||||
subslot->slot_nbr,
|
||||
subslot->subslot_nbr,
|
||||
subslot->submodule_name);
|
||||
}
|
||||
else if (ioxs_new == PNET_IOXS_GOOD)
|
||||
{
|
||||
APP_LOG_DEBUG (
|
||||
"PLC reports %s GOOD for slot %u subslot %u \"%s\".\n",
|
||||
ioxs_str,
|
||||
subslot->slot_nbr,
|
||||
subslot->subslot_nbr,
|
||||
subslot->submodule_name);
|
||||
}
|
||||
else if (ioxs_new != PNET_IOXS_GOOD)
|
||||
{
|
||||
APP_LOG_DEBUG (
|
||||
"PLC reports %s %u for slot %u subslot %u \"%s\".\n"
|
||||
" Is the PLC in STOP mode?\n",
|
||||
ioxs_str,
|
||||
ioxs_new,
|
||||
subslot->slot_nbr,
|
||||
subslot->subslot_nbr,
|
||||
subslot->submodule_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int app_utils_plug_module (
|
||||
app_api_t * p_api,
|
||||
uint16_t slot_nbr,
|
||||
uint32_t id,
|
||||
const char * name)
|
||||
{
|
||||
if (slot_nbr >= PNET_MAX_SLOTS)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
p_api->slots[slot_nbr].module_id = id;
|
||||
p_api->slots[slot_nbr].plugged = true;
|
||||
p_api->slots[slot_nbr].name = name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_utils_pull_module (app_api_t * p_api, uint16_t slot_nbr)
|
||||
{
|
||||
if (slot_nbr >= PNET_MAX_SLOTS)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
p_api->slots[slot_nbr].plugged = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
app_subslot_t * app_utils_plug_submodule (
|
||||
app_api_t * p_api,
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr,
|
||||
uint32_t submodule_ident,
|
||||
const pnet_data_cfg_t * p_data_cfg,
|
||||
const char * submodule_name,
|
||||
app_utils_cyclic_callback cyclic_callback,
|
||||
void * tag)
|
||||
{
|
||||
uint16_t subslot_ix;
|
||||
|
||||
if (slot_nbr >= PNET_MAX_SLOTS || p_api == NULL || p_data_cfg == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Find a free subslot */
|
||||
for (subslot_ix = 0; subslot_ix < PNET_MAX_SUBSLOTS; subslot_ix++)
|
||||
{
|
||||
if (p_api->slots[slot_nbr].subslots[subslot_ix].used == false)
|
||||
{
|
||||
app_subslot_t * p_subslot =
|
||||
&p_api->slots[slot_nbr].subslots[subslot_ix];
|
||||
|
||||
p_subslot->used = true;
|
||||
p_subslot->plugged = true;
|
||||
p_subslot->slot_nbr = slot_nbr;
|
||||
p_subslot->subslot_nbr = subslot_nbr;
|
||||
p_subslot->submodule_name = submodule_name;
|
||||
p_subslot->submodule_id = submodule_ident;
|
||||
p_subslot->data_cfg = *p_data_cfg;
|
||||
p_subslot->cyclic_callback = cyclic_callback;
|
||||
p_subslot->tag = tag;
|
||||
p_subslot->indata_iocs = PNET_IOXS_BAD;
|
||||
p_subslot->outdata_iops = PNET_IOXS_BAD;
|
||||
return p_subslot;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int app_utils_pull_submodule (
|
||||
app_api_t * p_api,
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr)
|
||||
{
|
||||
app_subslot_t * p_subslot = NULL;
|
||||
|
||||
if (slot_nbr >= PNET_MAX_SUBSLOTS || p_api == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
p_subslot = app_utils_subslot_get (p_api, slot_nbr, subslot_nbr);
|
||||
if (p_subslot == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset (p_subslot, 0, sizeof (app_subslot_t));
|
||||
p_subslot->used = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
app_subslot_t * app_utils_subslot_get (
|
||||
app_api_t * p_api,
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr)
|
||||
{
|
||||
uint16_t subslot_ix;
|
||||
|
||||
if (slot_nbr >= PNET_MAX_SLOTS || p_api == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (subslot_ix = 0; subslot_ix < PNET_MAX_SUBSLOTS; subslot_ix++)
|
||||
{
|
||||
if (p_api->slots[slot_nbr].subslots[subslot_ix].subslot_nbr == subslot_nbr)
|
||||
{
|
||||
return &p_api->slots[slot_nbr].subslots[subslot_ix];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool app_utils_subslot_is_input (const app_subslot_t * p_subslot)
|
||||
{
|
||||
if (p_subslot == NULL || p_subslot->used == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
p_subslot->data_cfg.data_dir == PNET_DIR_INPUT ||
|
||||
p_subslot->data_cfg.data_dir == PNET_DIR_IO)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool app_utils_subslot_is_no_io (const app_subslot_t * p_subslot)
|
||||
{
|
||||
if (p_subslot == NULL || p_subslot->used == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return p_subslot->data_cfg.data_dir == PNET_DIR_NO_IO;
|
||||
}
|
||||
|
||||
bool app_utils_subslot_is_output (const app_subslot_t * p_subslot)
|
||||
{
|
||||
if (p_subslot == NULL || p_subslot->used == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
p_subslot->data_cfg.data_dir == PNET_DIR_OUTPUT ||
|
||||
p_subslot->data_cfg.data_dir == PNET_DIR_IO)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void app_utils_cyclic_data_poll (app_api_t * p_api)
|
||||
{
|
||||
uint16_t slot_nbr;
|
||||
uint16_t subslot_index;
|
||||
app_subslot_t * p_subslot;
|
||||
|
||||
for (slot_nbr = 0; slot_nbr < PNET_MAX_SLOTS; slot_nbr++)
|
||||
{
|
||||
for (subslot_index = 0; subslot_index < PNET_MAX_SUBSLOTS;
|
||||
subslot_index++)
|
||||
{
|
||||
p_subslot = &p_api->slots[slot_nbr].subslots[subslot_index];
|
||||
if (p_subslot->plugged && p_subslot->cyclic_callback != NULL)
|
||||
{
|
||||
p_subslot->cyclic_callback (p_subslot, p_subslot->tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: nil
|
||||
* c-file-style: "ellemtel"
|
||||
* End:
|
||||
*/
|
||||
@@ -1,519 +0,0 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2018 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef APP_UTILS_H
|
||||
#define APP_UTILS_H
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Application utilities and helper functions
|
||||
*
|
||||
* Functions for getting string representation of
|
||||
* P-Net events, error codes and more.
|
||||
*
|
||||
* API, slot and subslot administration.
|
||||
*
|
||||
* Initialization of P-Net configuration from app_gsdml.h.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "osal.h"
|
||||
#include "pnal.h"
|
||||
#include <pnet_api.h>
|
||||
|
||||
typedef struct app_utils_netif_name
|
||||
{
|
||||
char name[PNET_INTERFACE_NAME_MAX_SIZE];
|
||||
} app_utils_netif_name_t;
|
||||
|
||||
typedef struct app_utils_netif_namelist
|
||||
{
|
||||
app_utils_netif_name_t netif[PNET_MAX_PHYSICAL_PORTS + 1];
|
||||
} app_utils_netif_namelist_t;
|
||||
|
||||
/* Forward declaration */
|
||||
typedef struct app_subslot app_subslot_t;
|
||||
|
||||
/**
|
||||
* Callback for updated cyclic data
|
||||
*
|
||||
* @param subslot InOut: Subslot structure
|
||||
* @param tag InOut: Typically a handle to a submodule
|
||||
*/
|
||||
typedef void (*app_utils_cyclic_callback) (app_subslot_t * subslot, void * tag);
|
||||
|
||||
/**
|
||||
* Information of submodule plugged into a subslot.
|
||||
*
|
||||
* Note that submodule data is not stored here but must
|
||||
* be handled by the submodule implementation.
|
||||
*
|
||||
* All parameters are initialized by the app_utils_plug_submodule()
|
||||
* function.
|
||||
*
|
||||
* The cyclic_callback is used when app_utils_cyclic_data_poll()
|
||||
* is called. Typically on the tick event in the main task.
|
||||
* The \a tag parameter is passed with the cyclic_callback and
|
||||
* is typically a handle to a submodule on application.
|
||||
*/
|
||||
typedef struct app_subslot
|
||||
{
|
||||
/** True when the position in the subslot array is occupied */
|
||||
bool used;
|
||||
|
||||
/** True when the subslot is plugged */
|
||||
bool plugged;
|
||||
|
||||
uint16_t slot_nbr;
|
||||
uint16_t subslot_nbr;
|
||||
uint32_t submodule_id;
|
||||
const char * submodule_name;
|
||||
pnet_data_cfg_t data_cfg;
|
||||
|
||||
/** Status indicator from PLC */
|
||||
uint8_t indata_iocs;
|
||||
|
||||
/** Status indicator from PLC */
|
||||
uint8_t outdata_iops;
|
||||
|
||||
/** Callback for cyclic input- or output data, or NULL if not implemented */
|
||||
app_utils_cyclic_callback cyclic_callback;
|
||||
void * tag;
|
||||
} app_subslot_t;
|
||||
|
||||
/**
|
||||
* Information of module plugged into a slot,
|
||||
* and array of subslots for admin of submodules.
|
||||
*/
|
||||
typedef struct app_slot
|
||||
{
|
||||
bool plugged;
|
||||
uint32_t module_id;
|
||||
const char * name; /** Module name */
|
||||
|
||||
/** Subslots. Use a separate index, as the subslot number might be large.
|
||||
* For example the subslot for DAP port 1 has number 0x8001 */
|
||||
app_subslot_t subslots[PNET_MAX_SUBSLOTS];
|
||||
} app_slot_t;
|
||||
|
||||
/**
|
||||
* Information relating to an application relation.
|
||||
*/
|
||||
typedef struct app_ar
|
||||
{
|
||||
uint32_t arep;
|
||||
uint32_t events;
|
||||
} app_ar_t;
|
||||
|
||||
/**
|
||||
* AR list iterator state.
|
||||
*/
|
||||
typedef struct app_ar_iterator
|
||||
{
|
||||
app_ar_t *ar;
|
||||
int16_t index;
|
||||
bool modified;
|
||||
} app_ar_iterator_t;
|
||||
|
||||
/**
|
||||
* Profinet API state for application
|
||||
*
|
||||
* Used to manage plugged modules into slots (and submodules into subslots).
|
||||
*/
|
||||
typedef struct app_api_t
|
||||
{
|
||||
uint32_t api_id;
|
||||
|
||||
/**
|
||||
* Active AR:s.
|
||||
* A list which is terminated by an entry with arep == UINT32_MAX.
|
||||
*/
|
||||
app_ar_t ar[PNET_MAX_AR];
|
||||
|
||||
/** Slots. Use slot number as index */
|
||||
app_slot_t slots[PNET_MAX_SLOTS];
|
||||
} app_api_t;
|
||||
|
||||
/**
|
||||
* Add an arep to the AR list of an API.
|
||||
* @param api InOut: The \a app_api_t instance.
|
||||
* @param arep In: The arep to add.
|
||||
* @param ar Out: The AR entry, if successful.
|
||||
*
|
||||
* @return 0 if the arep could not be added.
|
||||
* 1 if the arep was added.
|
||||
*/
|
||||
int app_ar_add_arep (app_api_t * api, uint32_t arep, app_ar_t ** ar);
|
||||
|
||||
/**
|
||||
* Get the arep of an AR.
|
||||
* @param ar In: The AR.
|
||||
* @return the arep of the AR.
|
||||
*/
|
||||
uint32_t app_ar_arep (app_ar_t * ar);
|
||||
|
||||
/**
|
||||
* Clear an event from the events value of the AR.
|
||||
* @param ar InOut: The AR to modify.
|
||||
* @param event In: The event(s) (bitmask) that should be cleared.
|
||||
* @return 0 if none of the set bits in \a event were set for the AR.
|
||||
* 1 if at least one of the set bits in \a event were set for the AR.
|
||||
*/
|
||||
int app_ar_event_clr (app_ar_t * ar, uint32_t event);
|
||||
|
||||
/**
|
||||
* Set an event from the events value of the AR.
|
||||
* @param ar InOut: The AR to modify.
|
||||
* @param event In: The event(s) (bitmask) that should be set.
|
||||
*/
|
||||
void app_ar_event_set (app_ar_t * ar, uint32_t event);
|
||||
|
||||
/**
|
||||
* Initialize a list iterator for the AR list of an API.
|
||||
* @param iterator InOut: The iterator to be initialized.
|
||||
* @param api In: The \a app_api_t instance.
|
||||
*/
|
||||
void app_ar_iterator_init (
|
||||
app_ar_iterator_t * iterator,
|
||||
app_api_t * api);
|
||||
|
||||
/**
|
||||
* Get the next AR from a list iterator.
|
||||
* @param iterator InOut: The iterator to use.
|
||||
* @param ar Out: If the return value is 1, the next AR from
|
||||
* the list.
|
||||
* @return 0 if there were no more items in the list.
|
||||
* 1 if there was another item in the list.
|
||||
*/
|
||||
int app_ar_iterator_next (app_ar_iterator_t * iterator, app_ar_t ** ar);
|
||||
|
||||
/**
|
||||
* Check whether the iterator has run to the end of entries.
|
||||
* @param iterator InOut: The iterator.
|
||||
* @return 0 if the iterator is finished.
|
||||
* 1 if the iterator is finished.
|
||||
*/
|
||||
int app_ar_iterator_done (app_ar_iterator_t * iterator);
|
||||
|
||||
/**
|
||||
* Delete the current AR entry of the list iterator.
|
||||
* @param ar InOut: The AR.
|
||||
*/
|
||||
void app_ar_iterator_delete_current (app_ar_iterator_t * iterator);
|
||||
|
||||
/**
|
||||
* Convert IP address to string
|
||||
* @param ip In: IP address
|
||||
* @param outputstring Out: Resulting string buffer. Should have size
|
||||
* PNAL_INET_ADDRSTR_SIZE.
|
||||
*/
|
||||
void app_utils_ip_to_string (pnal_ipaddr_t ip, char * outputstring);
|
||||
|
||||
/**
|
||||
* Get string description of data direction
|
||||
* @param direction In: Submodule data direction
|
||||
* @return String representation of data direction
|
||||
*/
|
||||
const char * app_utils_submod_dir_to_string (pnet_submodule_dir_t direction);
|
||||
|
||||
/**
|
||||
* Get string description of PNIO producer or consumer status
|
||||
* @param ioxs In: Producer or consumer status (IOPS/IOCS)
|
||||
* @return String representation of ioxs (IOPS/IOCS)
|
||||
*/
|
||||
const char * app_utils_ioxs_to_string (pnet_ioxs_values_t ioxs);
|
||||
|
||||
/**
|
||||
* Convert MAC address to string
|
||||
* @param mac In: MAC address
|
||||
* @param outputstring Out: Resulting string buffer. Should have size
|
||||
* PNAL_ETH_ADDRSTR_SIZE.
|
||||
*/
|
||||
void app_utils_mac_to_string (pnet_ethaddr_t mac, char * outputstring);
|
||||
|
||||
/**
|
||||
* Convert error code to string format
|
||||
* Only common error codes supported.
|
||||
* Todo: Add rest of error codes.
|
||||
*
|
||||
* @param err_cls In: The error class. See PNET_ERROR_CODE_1_*
|
||||
* @param err_code In: The error code. See PNET_ERROR_CODE_2_*
|
||||
* @param err_cls_str Out: The error class string
|
||||
* @param err_code_str Out: The error code string
|
||||
*/
|
||||
void app_utils_get_error_code_strings (
|
||||
uint16_t err_cls,
|
||||
uint16_t err_code,
|
||||
const char ** err_cls_str,
|
||||
const char ** err_code_str);
|
||||
|
||||
/**
|
||||
* Copy an IP address (as an integer) to a struct
|
||||
* @param destination_struct Out: Destination
|
||||
* @param ip In: IP address
|
||||
*/
|
||||
void app_utils_copy_ip_to_struct (
|
||||
pnet_cfg_ip_addr_t * destination_struct,
|
||||
pnal_ipaddr_t ip);
|
||||
|
||||
/**
|
||||
* Return a string representation of
|
||||
* the given dcontrol command.
|
||||
* @param event In: control_command
|
||||
* @return A string representing the command
|
||||
*/
|
||||
const char * app_utils_dcontrol_cmd_to_string (
|
||||
pnet_control_command_t control_command);
|
||||
|
||||
/**
|
||||
* Return a string representation of the given event.
|
||||
* @param event In: event
|
||||
* @return A string representing the event
|
||||
*/
|
||||
const char * app_utils_event_to_string (pnet_event_values_t event);
|
||||
|
||||
/**
|
||||
* Update network configuration from a string
|
||||
* defining a list of network interfaces examples:
|
||||
* "eth0" or "br0,eth0,eth1"
|
||||
*
|
||||
* Read IP, netmask etc from operating system.
|
||||
*
|
||||
* @param netif_list_str In: Comma separated string of network ifs
|
||||
* @param if_list Out: Array of network ifs
|
||||
* @param number_of_ports Out: Number of ports
|
||||
* @param if_cfg Out: P-Net network configuration to be updated
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int app_utils_pnet_cfg_init_netifs (
|
||||
const char * netif_list_str,
|
||||
app_utils_netif_namelist_t * if_list,
|
||||
uint16_t * number_of_ports,
|
||||
pnet_if_cfg_t * if_cfg);
|
||||
|
||||
/**
|
||||
* Parse a comma separated list of network interfaces and check
|
||||
* that the number of interfaces match the PNET_MAX_PHYSICAL_PORTS
|
||||
* configuration.
|
||||
*
|
||||
* For a single Ethernet interface, the \a arg_str should consist of
|
||||
* one name. For two Ethernet interfaces, the \a arg_str should consist of
|
||||
* three names, as we also need a bridge interface.
|
||||
*
|
||||
* Does only consider the number of comma separated names. No check of the
|
||||
* names themselves are done.
|
||||
*
|
||||
* Examples:
|
||||
* arg_str num_ports
|
||||
* "eth0" 1
|
||||
* "eth0,eth1" error (We need a bridge as well)
|
||||
* "br0,eth0,eth1" 2
|
||||
*
|
||||
* @param arg_str In: Network interface list as comma separated,
|
||||
* terminated string. For example "eth0" or
|
||||
* "br0,eth0,eth1".
|
||||
* @param max_port In: PNET_MAX_PHYSICAL_PORTS, passed as argument to
|
||||
* allow test.
|
||||
* @param p_if_list Out: List of network interfaces
|
||||
* @param p_num_ports Out: Resulting number of physical ports
|
||||
* @return 0 on success
|
||||
* -1 on error
|
||||
*/
|
||||
int app_utils_get_netif_namelist (
|
||||
const char * arg_str,
|
||||
uint16_t max_port,
|
||||
app_utils_netif_namelist_t * p_if_list,
|
||||
uint16_t * p_num_ports);
|
||||
|
||||
/**
|
||||
* Print network configuration using APP_LOG_INFO().
|
||||
*
|
||||
* @param if_cfg In: Network configuration
|
||||
* @param number_of_ports In: Number of used ports
|
||||
*/
|
||||
void app_utils_print_network_config (
|
||||
pnet_if_cfg_t * if_cfg,
|
||||
uint16_t number_of_ports);
|
||||
|
||||
/**
|
||||
* Print message if IOXS has changed.
|
||||
*
|
||||
* Uses APP_LOG_INFO()
|
||||
*
|
||||
* @param subslot In: Subslot
|
||||
* @param ioxs_str In: String description Producer or Consumer
|
||||
* @param ioxs_current In: Current status
|
||||
* @param ioxs_new In: New status
|
||||
*/
|
||||
void app_utils_print_ioxs_change (
|
||||
const app_subslot_t * subslot,
|
||||
const char * ioxs_str,
|
||||
uint8_t ioxs_current,
|
||||
uint8_t ioxs_new);
|
||||
|
||||
/**
|
||||
* Init the p-net configuration to default values.
|
||||
*
|
||||
* Most values are picked from app_gsdml.h
|
||||
*
|
||||
* Network configuration not initialized.
|
||||
* This means that \a '.if_cfg' must be set by application.
|
||||
*
|
||||
* Use this function to init P-Net configuration before
|
||||
* before passing config to app_init().
|
||||
*
|
||||
* @param pnet_cfg Out: Configuration for use by p-net
|
||||
* @return 0 if the operation succeeded.
|
||||
* -1 if an error occurred.
|
||||
*/
|
||||
int app_utils_pnet_cfg_init_default (pnet_cfg_t * pnet_cfg);
|
||||
|
||||
/**
|
||||
* Plug application module
|
||||
*
|
||||
* This is for the application to remember which slots are
|
||||
* populated in the p-net stack.
|
||||
*
|
||||
* @param p_api InOut: API
|
||||
* @param slot_nbr In: Slot number
|
||||
* @param id In: Module identity
|
||||
* @param name In: Module name
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int app_utils_plug_module (
|
||||
app_api_t * p_api,
|
||||
uint16_t slot_nbr,
|
||||
uint32_t id,
|
||||
const char * name);
|
||||
|
||||
/**
|
||||
* Pull any application module in given slot.
|
||||
*
|
||||
* This is for the application to remember which slots are
|
||||
* populated in the p-net stack.
|
||||
*
|
||||
* @param p_api InOut: API
|
||||
* @param slot_nbr In: Slot number
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int app_utils_pull_module (app_api_t * p_api, uint16_t slot_nbr);
|
||||
|
||||
/**
|
||||
* Plug application submodule.
|
||||
*
|
||||
* This is for the application to remember which subslots are
|
||||
* populated in the p-net stack.
|
||||
*
|
||||
* @param p_api InOut: API
|
||||
* @param slot_nbr In: Slot number
|
||||
* @param subslot_nbr In: Subslot number
|
||||
* @param submodule_id In: Submodule identity
|
||||
* @param p_data_cfg In: Data configuration,
|
||||
* direction, in and out sizes
|
||||
* @param submodule_name In: Submodule name
|
||||
* @param cyclic_callback In: Submodule data callback
|
||||
* @param tag In: Tag passed in cyclic callback
|
||||
* Typically application or
|
||||
* submodule handle
|
||||
* @return Reference to allocated subslot,
|
||||
* NULL if no free subslot is available. This should
|
||||
* never happen if application is aligned with p-net state.
|
||||
*/
|
||||
app_subslot_t * app_utils_plug_submodule (
|
||||
app_api_t * p_api,
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr,
|
||||
uint32_t submodule_id,
|
||||
const pnet_data_cfg_t * p_data_cfg,
|
||||
const char * submodule_name,
|
||||
app_utils_cyclic_callback cyclic_callback,
|
||||
void * tag);
|
||||
|
||||
/**
|
||||
* Unplug any application submodule from given subslot.
|
||||
*
|
||||
* This is for the application to remember which subslots are
|
||||
* populated in the p-net stack.
|
||||
*
|
||||
* @param p_api InOut: API
|
||||
* @param slot_nbr In: Slot number
|
||||
* @param subslot_nbr In: Subslot number
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
int app_utils_pull_submodule (
|
||||
app_api_t * p_api,
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr);
|
||||
|
||||
/**
|
||||
* Trigger data callback for all plugged submodules in all slots.
|
||||
*
|
||||
* The callbacks given in \a app_utils_plug_submodule() are used.
|
||||
*
|
||||
* @param p_api In: API
|
||||
*/
|
||||
void app_utils_cyclic_data_poll (app_api_t * p_api);
|
||||
|
||||
/**
|
||||
* Get subslot application information.
|
||||
*
|
||||
* @param p_appdata InOut: Application state.
|
||||
* @param slot_nbr In: Slot number.
|
||||
* @param subslot_nbr In: Subslot number. Range 0 - 0x9FFF.
|
||||
* @return Reference to application subslot,
|
||||
* NULL if subslot is not found/plugged.
|
||||
*/
|
||||
app_subslot_t * app_utils_subslot_get (
|
||||
app_api_t * p_api,
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr);
|
||||
|
||||
/**
|
||||
* Return true if subslot is input.
|
||||
*
|
||||
* @param p_subslot In: Reference to subslot.
|
||||
* @return true if subslot is input or input/output.
|
||||
* false if not.
|
||||
*/
|
||||
bool app_utils_subslot_is_input (const app_subslot_t * p_subslot);
|
||||
|
||||
/**
|
||||
* Return true if subslot is neither input or output.
|
||||
*
|
||||
* This is applies for DAP submodules/slots
|
||||
*
|
||||
* @param p_subslot In: Reference to subslot.
|
||||
* @return true if subslot is input or input/output.
|
||||
* false if not.
|
||||
*/
|
||||
bool app_utils_subslot_is_no_io (const app_subslot_t * p_subslot);
|
||||
|
||||
/**
|
||||
* Return true if subslot is output.
|
||||
*
|
||||
* @param p_subslot In: Reference to subslot.
|
||||
* @return true if subslot is output or input/output,
|
||||
* false if not.
|
||||
*/
|
||||
bool app_utils_subslot_is_output (const app_subslot_t * p_subslot);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* APP_UTILS_H */
|
||||
@@ -1,225 +0,0 @@
|
||||
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2020 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#define _GNU_SOURCE /* Enable execvpe () */
|
||||
|
||||
#include "pnal_filetools.h"
|
||||
|
||||
#include "pnet_options.h"
|
||||
#include "options.h"
|
||||
#include "osal_log.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
bool pnal_does_file_exist (const char * filepath)
|
||||
{
|
||||
struct stat statbuffer;
|
||||
|
||||
return (stat (filepath, &statbuffer) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Get the path to the directory where the main binary is located.
|
||||
*
|
||||
* @param tempstring Temp: Temporary buffer.
|
||||
* @param dirpath Out: Path to directory. Terminated string.
|
||||
* @param size In: Size of the stringbuffers. Should be large
|
||||
* enough for the full path to the binary.
|
||||
*
|
||||
* @return 0 on success.
|
||||
* -1 if an error occurred.
|
||||
*/
|
||||
static int pnal_get_directory_of_binary (
|
||||
char * tempstring,
|
||||
char * dirpath,
|
||||
size_t size)
|
||||
{
|
||||
ssize_t num_bytes = 0;
|
||||
memset (tempstring, 0, size); /* Path to executable */
|
||||
memset (dirpath, 0, size);
|
||||
char * resulting_directory = NULL;
|
||||
|
||||
num_bytes = readlink ("/proc/self/exe", tempstring, size);
|
||||
if (num_bytes == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Verify that we have the full path (size is big enough) */
|
||||
if (!pnal_does_file_exist (tempstring))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
resulting_directory = dirname (tempstring);
|
||||
snprintf (dirpath, size, "%s", resulting_directory);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Create a PATH string used when searching for scripts
|
||||
*
|
||||
* The PATH string is colon separated, and includes the directory where
|
||||
* the main binary is located.
|
||||
*
|
||||
* @param path Out: Resulting path. Terminated string.
|
||||
* Might be modified also on failure.
|
||||
* @param size In: Size of the outputbuffer. Should be
|
||||
* sizeof(PNAL_DEFAULT_SEARCHPATH) +
|
||||
* PNET_MAX_DIRECTORYPATH_SIZE
|
||||
* @return 0 on success.
|
||||
* -1 if an error occurred.
|
||||
*/
|
||||
int pnal_create_searchpath (char * path, size_t size)
|
||||
{
|
||||
int written = 0;
|
||||
|
||||
/** Should temporarily hold full path. Resulting size is
|
||||
* PNET_MAX_DIRECTORYPATH_SIZE */
|
||||
char
|
||||
directory_of_binary[PNET_MAX_DIRECTORYPATH_SIZE + PNET_MAX_FILENAME_SIZE] =
|
||||
{0};
|
||||
char tempstring[PNET_MAX_DIRECTORYPATH_SIZE + PNET_MAX_FILENAME_SIZE] = {0};
|
||||
|
||||
if (
|
||||
pnal_get_directory_of_binary (
|
||||
tempstring,
|
||||
directory_of_binary,
|
||||
sizeof (directory_of_binary)) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
written = snprintf (
|
||||
path,
|
||||
size,
|
||||
"%s:%s",
|
||||
PNAL_DEFAULT_SEARCHPATH,
|
||||
directory_of_binary);
|
||||
if (written < 0 || (unsigned)written >= size)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pnal_execute_script (const char * argv[])
|
||||
{
|
||||
/** Terminated string, see pnal_create_searchpath() */
|
||||
char child_searchpath
|
||||
[sizeof (PNAL_DEFAULT_SEARCHPATH) + PNET_MAX_DIRECTORYPATH_SIZE] = {0};
|
||||
int childstatus = 0;
|
||||
pid_t childpid;
|
||||
char * scriptenviron[] = {NULL};
|
||||
int script_returnvalue = 0;
|
||||
#if LOG_DEBUG_ENABLED(PF_PNAL_LOG)
|
||||
uint16_t ix;
|
||||
#endif
|
||||
|
||||
if (argv == NULL)
|
||||
{
|
||||
LOG_ERROR (
|
||||
PF_PNAL_LOG,
|
||||
"PNAL(%d): No argument vector given for running script.\n",
|
||||
__LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argv[0] == NULL)
|
||||
{
|
||||
LOG_ERROR (PF_PNAL_LOG, "PNAL(%d): No script name given.\n", __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pnal_create_searchpath (child_searchpath, sizeof (child_searchpath)) != 0)
|
||||
{
|
||||
LOG_ERROR (
|
||||
PF_PNAL_LOG,
|
||||
"PNAL(%d): Could not build PATH to run script.\n",
|
||||
__LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if LOG_DEBUG_ENABLED(PF_PNAL_LOG)
|
||||
printf ("PNAL(%d): Command for script:", __LINE__);
|
||||
for (ix = 0; argv[ix] != NULL; ix++)
|
||||
{
|
||||
if (strlen (argv[ix]) > 0)
|
||||
{
|
||||
printf (" %s", argv[ix]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf (" ''");
|
||||
}
|
||||
}
|
||||
printf ("\n");
|
||||
#endif
|
||||
|
||||
/* Fork and exec */
|
||||
childpid = fork();
|
||||
if (childpid < 0)
|
||||
{
|
||||
LOG_ERROR (
|
||||
PF_PNAL_LOG,
|
||||
"PNAL(%d): Failed to fork the process to run script.\n",
|
||||
__LINE__);
|
||||
return -1;
|
||||
}
|
||||
else if (childpid == 0)
|
||||
{
|
||||
/* We are in the child process */
|
||||
|
||||
/* setenv() will malloc memory. We will not free() it, but it does not
|
||||
matter since we do it in the short-lived child process */
|
||||
if (setenv ("PATH", child_searchpath, 1) != 0)
|
||||
{
|
||||
printf (
|
||||
"PNAL(%d): Failed to set PATH in child process to run script.\n",
|
||||
__LINE__);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
execvpe (argv[0], (char * const *)argv, scriptenviron);
|
||||
|
||||
printf (
|
||||
"PNAL(%d): Failed to execute in child process. Is the script file "
|
||||
"missing or lacks execution permission? %s Search path %s\n",
|
||||
__LINE__,
|
||||
argv[0],
|
||||
child_searchpath);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We are in the parent (original) process */
|
||||
wait (&childstatus);
|
||||
script_returnvalue = WEXITSTATUS (childstatus);
|
||||
}
|
||||
|
||||
return (script_returnvalue == 0) ? 0 : -1;
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2020 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef PNAL_FILETOOLS_H
|
||||
#define PNAL_FILETOOLS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Colon separated paths to search for scripts. No colon at end. */
|
||||
#define PNAL_DEFAULT_SEARCHPATH "/bin:/usr/bin"
|
||||
|
||||
/**
|
||||
* Check if a file or directory exists
|
||||
*
|
||||
* @param filepath In: Path to file or directory. Null terminated.
|
||||
* Trailing slash is optional for directories.
|
||||
* @return true if file exists
|
||||
*/
|
||||
bool pnal_does_file_exist (const char * filepath);
|
||||
|
||||
/**
|
||||
* Execute a script.
|
||||
*
|
||||
* The script will be searched for in:
|
||||
* - Directories given in PNAL_DEFAULT_SEARCHPATH
|
||||
* - Same directory as the main binary is located in.
|
||||
*
|
||||
* @param argv In: Arguments (null terminated strings).
|
||||
* The first argument should be the name of
|
||||
* the script.
|
||||
* The last element should be NULL.
|
||||
* @return 0 on success
|
||||
* -1 if an error occurred
|
||||
*/
|
||||
int pnal_execute_script (const char * argv[]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PNAL_FILETOOLS_H */
|
||||
@@ -1,517 +0,0 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2018 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#define _GNU_SOURCE /* For asprintf() */
|
||||
|
||||
#include "sampleapp_common.h"
|
||||
#include "app_gsdml.h"
|
||||
#include "app_log.h"
|
||||
#include "app_utils.h"
|
||||
|
||||
#include "osal.h"
|
||||
#include "osal_log.h" /* For LOG_LEVEL */
|
||||
#include "pnal.h"
|
||||
#include "pnal_filetools.h"
|
||||
#include <pnet_api.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if PNET_MAX_PHYSICAL_PORTS == 1
|
||||
#define APP_DEFAULT_ETHERNET_INTERFACE "eth0"
|
||||
#else
|
||||
#define APP_DEFAULT_ETHERNET_INTERFACE "br0,eth0,eth1"
|
||||
#endif
|
||||
|
||||
#define APP_MAIN_SLEEPTIME_US 5000 * 1000
|
||||
#define APP_SNMP_THREAD_PRIORITY 1
|
||||
#define APP_SNMP_THREAD_STACKSIZE 256 * 1024 /* bytes */
|
||||
#define APP_ETH_THREAD_PRIORITY 10
|
||||
#define APP_ETH_THREAD_STACKSIZE 4096 /* bytes */
|
||||
#define APP_BG_WORKER_THREAD_PRIORITY 5
|
||||
#define APP_BG_WORKER_THREAD_STACKSIZE 4096 /* bytes */
|
||||
|
||||
/* Note that this sample application uses os_timer_create() for the timer
|
||||
that controls the ticks. It is implemented in OSAL, and the Linux
|
||||
implementation uses a thread internally. To modify the timer thread priority,
|
||||
modify OSAL or use some other timer */
|
||||
|
||||
app_args_t app_args = {0};
|
||||
|
||||
/************************* Utilities ******************************************/
|
||||
|
||||
void show_usage()
|
||||
{
|
||||
printf ("\nSample application for p-net Profinet device stack.\n");
|
||||
printf ("\n");
|
||||
printf ("Wait for connection from IO-controller.\n");
|
||||
printf ("Then read buttons (input) and send to controller.\n");
|
||||
printf ("Listen for application LED output (from controller) and set "
|
||||
"application LED state.\n");
|
||||
printf ("It will also send a counter value (useful also without buttons and "
|
||||
"LED).\n");
|
||||
printf ("Button1 value is sent in the periodic data.\n");
|
||||
printf ("Button2 cycles through triggering an alarm, setting diagnosis and "
|
||||
"creating logbook entries.\n");
|
||||
printf ("\n");
|
||||
printf ("Also the mandatory Profinet signal LED is controlled by this "
|
||||
"application.\n");
|
||||
printf ("\n");
|
||||
printf ("The LEDs are controlled by the script set_profinet_leds\n");
|
||||
printf ("located in the same directory as the application binary.\n");
|
||||
printf ("A version for Raspberry Pi is available, and also a version "
|
||||
"writing\n");
|
||||
printf ("to plain text files (useful for demo if no LEDs are available).\n");
|
||||
printf ("\n");
|
||||
printf ("Assumes the default gateway is found on .1 on same subnet as the "
|
||||
"IP address.\n");
|
||||
printf ("\n");
|
||||
printf ("Optional arguments:\n");
|
||||
printf (" --help Show this help text and exit\n");
|
||||
printf (" -h Show this help text and exit\n");
|
||||
printf (" -v Incresase verbosity. Can be repeated.\n");
|
||||
printf (" -f Reset to factory settings, and store to file. "
|
||||
"Exit.\n");
|
||||
printf (" Remember to give the -p flag if necessary.\n");
|
||||
printf (" -r Remove stored files and exit.\n");
|
||||
printf (" Remember to give the -p flag if necessary.\n");
|
||||
printf (" -g Show stack details and exit. Repeat for more "
|
||||
"details.\n");
|
||||
printf (
|
||||
" -i INTERF Name of Ethernet interface to use. Defaults to %s\n",
|
||||
APP_DEFAULT_ETHERNET_INTERFACE);
|
||||
printf (" Comma separated list if more than one interface "
|
||||
"given.\n");
|
||||
printf (
|
||||
" -s NAME Set station name. Defaults to \"%s\". Only used\n",
|
||||
APP_GSDML_DEFAULT_STATION_NAME);
|
||||
printf (" if not already available in storage file.\n");
|
||||
printf (" -b FILE Path (absolute or relative) to read Button1. "
|
||||
"Defaults to not read Button1.\n");
|
||||
printf (" -d FILE Path (absolute or relative) to read Button2. "
|
||||
"Defaults to not read Button2.\n");
|
||||
printf (" -p PATH Absolute path to storage directory. Defaults to "
|
||||
"use current directory.\n");
|
||||
#if PNET_OPTION_DRIVER_ENABLE
|
||||
printf (" -m MODE Application offload mode. Only used if P-Net is\n");
|
||||
printf (" built with hw offload enabled "
|
||||
" (PNET_OPTION_DRIVER_ENABLE). \n");
|
||||
printf (" Supported modes: none, cpu, full\n");
|
||||
printf (" Defaults to none\n");
|
||||
#endif
|
||||
printf ("\n");
|
||||
printf ("p-net revision: " PNET_VERSION "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse command line arguments
|
||||
*
|
||||
* @param argc In: Number of arguments
|
||||
* @param argv In: Arguments
|
||||
* @return Parsed arguments
|
||||
*/
|
||||
app_args_t parse_commandline_arguments (int argc, char * argv[])
|
||||
{
|
||||
app_args_t output_arguments = {0};
|
||||
int option;
|
||||
|
||||
/* Special handling of long argument */
|
||||
if (argc > 1)
|
||||
{
|
||||
if (strcmp (argv[1], "--help") == 0)
|
||||
{
|
||||
show_usage();
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Default values */
|
||||
strcpy (output_arguments.path_button1, "");
|
||||
strcpy (output_arguments.path_button2, "");
|
||||
strcpy (output_arguments.path_storage_directory, "");
|
||||
strcpy (output_arguments.station_name, APP_GSDML_DEFAULT_STATION_NAME);
|
||||
strcpy (output_arguments.eth_interfaces, APP_DEFAULT_ETHERNET_INTERFACE);
|
||||
output_arguments.verbosity = 0;
|
||||
output_arguments.show = 0;
|
||||
output_arguments.factory_reset = false;
|
||||
output_arguments.remove_files = false;
|
||||
output_arguments.mode = MODE_HW_OFFLOAD_NONE;
|
||||
|
||||
while ((option = getopt (argc, argv, "hvgfri:s:b:d:p:m:")) != -1)
|
||||
{
|
||||
switch (option)
|
||||
{
|
||||
case 'v':
|
||||
output_arguments.verbosity++;
|
||||
break;
|
||||
case 'g':
|
||||
output_arguments.show++;
|
||||
break;
|
||||
case 'f':
|
||||
output_arguments.factory_reset = true;
|
||||
break;
|
||||
case 'r':
|
||||
output_arguments.remove_files = true;
|
||||
break;
|
||||
case 'i':
|
||||
if ((strlen (optarg) + 1) > sizeof (output_arguments.eth_interfaces))
|
||||
{
|
||||
printf ("Error: The argument to -i is too long.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
strcpy (output_arguments.eth_interfaces, optarg);
|
||||
break;
|
||||
case 's':
|
||||
strcpy (output_arguments.station_name, optarg);
|
||||
break;
|
||||
case 'b':
|
||||
if (strlen (optarg) + 1 > PNET_MAX_FILE_FULLPATH_SIZE)
|
||||
{
|
||||
printf ("Error: The argument to -b is too long.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
strcpy (output_arguments.path_button1, optarg);
|
||||
break;
|
||||
case 'd':
|
||||
if (strlen (optarg) + 1 > PNET_MAX_FILE_FULLPATH_SIZE)
|
||||
{
|
||||
printf ("Error: The argument to -d is too long.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
strcpy (output_arguments.path_button2, optarg);
|
||||
break;
|
||||
case 'p':
|
||||
if (strlen (optarg) + 1 > PNET_MAX_FILE_FULLPATH_SIZE)
|
||||
{
|
||||
printf ("Error: The argument to -p is too long.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
strcpy (output_arguments.path_storage_directory, optarg);
|
||||
break;
|
||||
#if PNET_OPTION_DRIVER_ENABLE
|
||||
case 'm':
|
||||
if (strcmp ("none", optarg) == 0)
|
||||
{
|
||||
output_arguments.mode = MODE_HW_OFFLOAD_NONE;
|
||||
}
|
||||
else if (strcmp ("cpu", optarg) == 0)
|
||||
{
|
||||
output_arguments.mode = MODE_HW_OFFLOAD_CPU;
|
||||
}
|
||||
else if (strcmp ("full", optarg) == 0)
|
||||
{
|
||||
output_arguments.mode = MODE_HW_OFFLOAD_FULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Error: mode (-m) not supported.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case 'h':
|
||||
/* fallthrough */
|
||||
case '?':
|
||||
/* fallthrough */
|
||||
default:
|
||||
show_usage();
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Use current directory for storage, if not given */
|
||||
if (strlen (output_arguments.path_storage_directory) == 0)
|
||||
{
|
||||
if (
|
||||
getcwd (
|
||||
output_arguments.path_storage_directory,
|
||||
sizeof (output_arguments.path_storage_directory)) == NULL)
|
||||
{
|
||||
printf ("Error: Could not read current working directory. Is "
|
||||
"PNET_MAX_DIRECTORYPATH_SIZE too small?\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
return output_arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a bool from a file
|
||||
*
|
||||
* @param filepath In: Path to file
|
||||
* @return true if file exists and the first character is '1'
|
||||
*/
|
||||
bool read_bool_from_file (const char * filepath)
|
||||
{
|
||||
FILE * fp;
|
||||
char ch;
|
||||
int eof_indicator;
|
||||
|
||||
fp = fopen (filepath, "r");
|
||||
if (fp == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ch = fgetc (fp);
|
||||
eof_indicator = feof (fp);
|
||||
fclose (fp);
|
||||
|
||||
if (eof_indicator)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return ch == '1';
|
||||
}
|
||||
|
||||
bool app_get_button (uint16_t id)
|
||||
{
|
||||
if (id == 0)
|
||||
{
|
||||
if (app_args.path_button1[0] != '\0')
|
||||
{
|
||||
return read_bool_from_file (app_args.path_button1);
|
||||
}
|
||||
}
|
||||
else if (id == 1)
|
||||
{
|
||||
if (app_args.path_button2[0] != '\0')
|
||||
{
|
||||
return read_bool_from_file (app_args.path_button2);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void app_set_led (uint16_t id, bool led_state)
|
||||
{
|
||||
/* Important:
|
||||
* The Linux sample application uses a script to set the LED state,
|
||||
* for easy adaption to different development boards.
|
||||
*
|
||||
* The script typically writes to files in the /sys directory to set LED
|
||||
* state via GPIO operations. If you do not have any physical LEDs you can
|
||||
* use a script that writes to regular files instead.
|
||||
*
|
||||
* However, file operations shall be avoided within the main task
|
||||
* in a real application. File operations may affect the timing of the
|
||||
* Profinet communication depending on file system implementation.
|
||||
*/
|
||||
|
||||
char id_str[7] = {0}; /** Terminated string */
|
||||
const char * argv[4];
|
||||
|
||||
sprintf (id_str, "%u", id);
|
||||
id_str[sizeof (id_str) - 1] = '\0';
|
||||
|
||||
argv[0] = "set_profinet_leds";
|
||||
argv[1] = (char *)&id_str;
|
||||
argv[2] = (led_state == 1) ? "1" : "0";
|
||||
argv[3] = NULL;
|
||||
|
||||
if (pnal_execute_script (argv) != 0)
|
||||
{
|
||||
printf ("Failed to set LED state\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** Update configuration with file storage path.
|
||||
* Validate this path, and Linux button file paths
|
||||
*
|
||||
* @param p_cfg InOut: Configuration to be updated
|
||||
* @param p_args In: Command line arguments
|
||||
* @return 0 on success, -1 on error.
|
||||
*/
|
||||
static int app_pnet_cfg_init_storage (
|
||||
pnet_cfg_t * p_cfg,
|
||||
const app_args_t * p_args)
|
||||
{
|
||||
strcpy (p_cfg->file_directory, p_args->path_storage_directory);
|
||||
|
||||
if (p_args->verbosity > 0)
|
||||
{
|
||||
printf ("Storage directory: %s\n\n", p_cfg->file_directory);
|
||||
}
|
||||
|
||||
/* Validate paths */
|
||||
if (!pnal_does_file_exist (p_cfg->file_directory))
|
||||
{
|
||||
printf (
|
||||
"Error: The given storage directory does not exist: %s\n",
|
||||
p_cfg->file_directory);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (p_args->path_button1[0] != '\0')
|
||||
{
|
||||
if (!pnal_does_file_exist (p_args->path_button1))
|
||||
{
|
||||
printf (
|
||||
"Error: The given input file for Button1 does not exist: %s\n",
|
||||
p_args->path_button1);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_args->path_button2[0] != '\0')
|
||||
{
|
||||
if (!pnal_does_file_exist (p_args->path_button2))
|
||||
{
|
||||
printf (
|
||||
"Error: The given input file for Button2 does not exist: %s\n",
|
||||
p_args->path_button2);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************** Main ******************************************/
|
||||
|
||||
int main (int argc, char * argv[])
|
||||
{
|
||||
int ret;
|
||||
int32_t app_log_level = APP_LOG_LEVEL_FATAL;
|
||||
pnet_cfg_t pnet_cfg = {0};
|
||||
app_data_t * sample_app = NULL;
|
||||
app_utils_netif_namelist_t netif_name_list;
|
||||
pnet_if_cfg_t netif_cfg = {0};
|
||||
uint16_t number_of_ports = 1;
|
||||
|
||||
/* Enable line buffering for printouts, especially when logging to
|
||||
the journal (which is default when running as a systemd job) */
|
||||
setvbuf (stdout, NULL, _IOLBF, 0);
|
||||
|
||||
/* Parse and display command line arguments */
|
||||
app_args = parse_commandline_arguments (argc, argv);
|
||||
|
||||
app_log_level = (app_args.verbosity <= APP_LOG_LEVEL_FATAL)
|
||||
? APP_LOG_LEVEL_FATAL - app_args.verbosity
|
||||
: APP_LOG_LEVEL_DEBUG;
|
||||
app_log_set_log_level (app_log_level);
|
||||
printf ("\n** Starting P-Net sample application " PNET_VERSION " **\n");
|
||||
|
||||
APP_LOG_INFO (
|
||||
"Number of slots: %u (incl slot for DAP module)\n",
|
||||
PNET_MAX_SLOTS);
|
||||
APP_LOG_INFO ("P-net log level: %u (DEBUG=0, FATAL=4)\n", LOG_LEVEL);
|
||||
APP_LOG_INFO ("App log level: %u (DEBUG=0, FATAL=4)\n", app_log_level);
|
||||
APP_LOG_INFO ("Max number of ports: %u\n", PNET_MAX_PHYSICAL_PORTS);
|
||||
APP_LOG_INFO ("Network interfaces: %s\n", app_args.eth_interfaces);
|
||||
APP_LOG_INFO ("Button1 file: %s\n", app_args.path_button1);
|
||||
APP_LOG_INFO ("Button2 file: %s\n", app_args.path_button2);
|
||||
APP_LOG_INFO ("Default station name: %s\n", app_args.station_name);
|
||||
|
||||
/* Prepare configuration */
|
||||
app_pnet_cfg_init_default (&pnet_cfg);
|
||||
strcpy (pnet_cfg.station_name, app_args.station_name);
|
||||
ret = app_utils_pnet_cfg_init_netifs (
|
||||
app_args.eth_interfaces,
|
||||
&netif_name_list,
|
||||
&number_of_ports,
|
||||
&netif_cfg);
|
||||
if (ret != 0)
|
||||
{
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
pnet_cfg.if_cfg = netif_cfg;
|
||||
pnet_cfg.num_physical_ports = number_of_ports;
|
||||
|
||||
app_utils_print_network_config (&netif_cfg, number_of_ports);
|
||||
|
||||
/* Operating system specific settings */
|
||||
pnet_cfg.pnal_cfg.snmp_thread.prio = APP_SNMP_THREAD_PRIORITY;
|
||||
pnet_cfg.pnal_cfg.snmp_thread.stack_size = APP_SNMP_THREAD_STACKSIZE;
|
||||
pnet_cfg.pnal_cfg.eth_recv_thread.prio = APP_ETH_THREAD_PRIORITY;
|
||||
pnet_cfg.pnal_cfg.eth_recv_thread.stack_size = APP_ETH_THREAD_STACKSIZE;
|
||||
pnet_cfg.pnal_cfg.bg_worker_thread.prio = APP_BG_WORKER_THREAD_PRIORITY;
|
||||
pnet_cfg.pnal_cfg.bg_worker_thread.stack_size =
|
||||
APP_BG_WORKER_THREAD_STACKSIZE;
|
||||
|
||||
ret = app_pnet_cfg_init_storage (&pnet_cfg, &app_args);
|
||||
if (ret != 0)
|
||||
{
|
||||
printf ("Failed to initialize storage.\n");
|
||||
printf ("Aborting application\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Remove files and exit */
|
||||
if (app_args.remove_files == true)
|
||||
{
|
||||
printf ("\nRemoving stored files\n");
|
||||
printf ("Exit application\n");
|
||||
(void)pnet_remove_data_files (pnet_cfg.file_directory);
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Initialise stack and application */
|
||||
sample_app = app_init (&pnet_cfg, &app_args);
|
||||
if (sample_app == NULL)
|
||||
{
|
||||
printf ("Failed to initialize P-Net.\n");
|
||||
printf ("Do you have enough Ethernet interface permission?\n");
|
||||
printf ("Aborting application\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Do factory reset and exit */
|
||||
if (app_args.factory_reset == true)
|
||||
{
|
||||
printf ("\nPerforming factory reset\n");
|
||||
printf ("Exit application\n");
|
||||
(void)pnet_factory_reset (app_get_pnet_instance (sample_app));
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Show stack info and exit */
|
||||
if (app_args.show > 0)
|
||||
{
|
||||
int level = 0xFFFF;
|
||||
|
||||
printf ("\nShowing stack information.\n\n");
|
||||
if (app_args.show == 1)
|
||||
{
|
||||
level = 0x2010; /* See documentation for pnet_show() */
|
||||
}
|
||||
|
||||
pnet_show (app_get_pnet_instance (sample_app), level);
|
||||
printf ("Exit application\n");
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Start main loop */
|
||||
pnal_snmp_set_agentx_socket(app_get_pnet_instance (sample_app), "/var/run/agentx/master");
|
||||
if (app_start (sample_app, RUN_IN_SEPARATE_THREAD) != 0)
|
||||
{
|
||||
printf ("Failed to start\n");
|
||||
printf ("Aborting application\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
os_usleep (APP_MAIN_SLEEPTIME_US);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,169 +0,0 @@
|
||||
/*********************************************************************
|
||||
* _ _ _
|
||||
* _ __ | |_ _ | | __ _ | |__ ___
|
||||
* | '__|| __|(_)| | / _` || '_ \ / __|
|
||||
* | | | |_ _ | || (_| || |_) |\__ \
|
||||
* |_| \__|(_)|_| \__,_||_.__/ |___/
|
||||
*
|
||||
* www.rt-labs.com
|
||||
* Copyright 2018 rt-labs AB, Sweden.
|
||||
*
|
||||
* This software is dual-licensed under GPLv3 and a commercial
|
||||
* license. See the file LICENSE.md distributed with this software for
|
||||
* full license information.
|
||||
********************************************************************/
|
||||
|
||||
#ifndef SAMPLEAPP_COMMON_H
|
||||
#define SAMPLEAPP_COMMON_H
|
||||
|
||||
#include "osal.h"
|
||||
#include "pnal.h"
|
||||
#include <pnet_api.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define APP_TICK_INTERVAL_US 1000 /* 1 ms */
|
||||
|
||||
/* Thread configuration for targets where sample
|
||||
* event loop is run in a separate thread (not main).
|
||||
* This applies for linux sample app implementation.
|
||||
*/
|
||||
#define APP_MAIN_THREAD_PRIORITY 15
|
||||
#define APP_MAIN_THREAD_STACKSIZE 4096 /* bytes */
|
||||
|
||||
#define APP_DATA_LED_ID 1
|
||||
#define APP_PROFINET_SIGNAL_LED_ID 2
|
||||
|
||||
#define APP_TICKS_READ_BUTTONS 10
|
||||
#define APP_TICKS_UPDATE_DATA 100
|
||||
|
||||
/** HW Offload configuration. */
|
||||
typedef enum
|
||||
{
|
||||
MODE_HW_OFFLOAD_NONE = 0,
|
||||
MODE_HW_OFFLOAD_CPU,
|
||||
MODE_HW_OFFLOAD_FULL,
|
||||
} app_mode_t;
|
||||
|
||||
/** Command line arguments for sample application */
|
||||
typedef struct app_args
|
||||
{
|
||||
char path_button1[PNET_MAX_FILE_FULLPATH_SIZE]; /** Terminated string */
|
||||
char path_button2[PNET_MAX_FILE_FULLPATH_SIZE]; /** Terminated string */
|
||||
char path_storage_directory[PNET_MAX_DIRECTORYPATH_SIZE]; /** Terminated */
|
||||
char station_name[PNET_STATION_NAME_MAX_SIZE]; /** Terminated string */
|
||||
char eth_interfaces
|
||||
[PNET_INTERFACE_NAME_MAX_SIZE * (PNET_MAX_PHYSICAL_PORTS + 1) +
|
||||
PNET_MAX_PHYSICAL_PORTS]; /** Terminated string */
|
||||
int verbosity;
|
||||
int show;
|
||||
bool factory_reset;
|
||||
bool remove_files;
|
||||
app_mode_t mode;
|
||||
} app_args_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RUN_IN_SEPARATE_THREAD,
|
||||
RUN_IN_MAIN_THREAD
|
||||
} app_run_in_separate_task_t;
|
||||
|
||||
typedef struct app_data_t app_data_t;
|
||||
|
||||
/**
|
||||
* AR specific event handler type.
|
||||
*
|
||||
* Handles an AR specific event.
|
||||
*
|
||||
* @param app InOut: Application handle
|
||||
* @param arep In: Arep of the AR.
|
||||
*
|
||||
* @return 0 to indicate that the arep should be kept
|
||||
* 1 to indicate that the arep should be forgotten
|
||||
*/
|
||||
typedef int (*app_ar_event_handler_t) (app_data_t * app, uint32_t arep);
|
||||
|
||||
/** Partially initialise config values, and use proper callbacks
|
||||
*
|
||||
* @param pnet_cfg Out: Configuration to be updated
|
||||
*/
|
||||
void app_pnet_cfg_init_default (pnet_cfg_t * pnet_cfg);
|
||||
|
||||
/**
|
||||
* Initialize P-Net stack and application.
|
||||
*
|
||||
* The \a pnet_cfg argument shall have been initialized using
|
||||
* \a app_pnet_cfg_init_default() before this function is
|
||||
* called.
|
||||
*
|
||||
* @param pnet_cfg In: P-Net configuration
|
||||
* @param app_args In: Application arguments
|
||||
* @return Application handle, NULL on error
|
||||
*/
|
||||
app_data_t * app_init (const pnet_cfg_t * pnet_cfg, const app_args_t * app_args);
|
||||
|
||||
/**
|
||||
* Start application main loop
|
||||
*
|
||||
* Application must have been initialized using \a app_init() before
|
||||
* this function is called.
|
||||
*
|
||||
* If \a task_config parameters is set to RUN_IN_SEPARATE_THREAD a
|
||||
* thread execution the \a app_loop_forever() function is started.
|
||||
* If task_config is set to RUN_IN_MAIN_THREAD no such thread is
|
||||
* started and the caller must call the \a app_loop_forever() after
|
||||
* calling this function.
|
||||
*
|
||||
* RUN_IN_MAIN_THREAD is intended for rt-kernel targets.
|
||||
* RUN_IN_SEPARATE_THREAD is intended for linux targets.
|
||||
*
|
||||
* @param app In: Application handle
|
||||
* @param task_config In: Defines if stack and application
|
||||
* is run in main or separate task.
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int app_start (app_data_t * app, app_run_in_separate_task_t task_config);
|
||||
|
||||
/**
|
||||
* Application task definition. Handles events in eternal loop.
|
||||
*
|
||||
* @param arg In: Application handle
|
||||
*/
|
||||
void app_loop_forever (void * arg);
|
||||
|
||||
/**
|
||||
* Get P-Net instance from application
|
||||
*
|
||||
* @param app In: Application handle
|
||||
* @return P-Net instance, NULL on failure
|
||||
*/
|
||||
pnet_t * app_get_pnet_instance (app_data_t * app);
|
||||
|
||||
/**
|
||||
* Set LED state
|
||||
* Hardware specific. Implemented in sample app main file for
|
||||
* each supported platform.
|
||||
*
|
||||
* @param id In: LED number, starting from 0.
|
||||
* @param led_state In: LED state. Use true for on and false for off.
|
||||
*/
|
||||
void app_set_led (uint16_t id, bool led_state);
|
||||
|
||||
/**
|
||||
* Read button state
|
||||
*
|
||||
* Hardware specific. Implemented in sample app main file for
|
||||
* each supported platform.
|
||||
*
|
||||
* @param id In: Button number, starting from 0.
|
||||
* @return true if button is pressed, false if not
|
||||
*/
|
||||
bool app_get_button (uint16_t id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SAMPLEAPP_COMMON_H */
|
||||
Reference in New Issue
Block a user