Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Backports:SLE-15-SP4:FactoryCandidates
vcontrold
vcontrold-v0.98.10+git20210418.977e6f5.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File vcontrold-v0.98.10+git20210418.977e6f5.obscpio of Package vcontrold
07070100000000000081A4000028240000003200000001607BF448000007EE000000000000000000000000000000000000003500000000vcontrold-v0.98.10+git20210418.977e6f5/.appveyor.ymlenvironment: matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 ARCH: x86 CYGWIN: C:\Cygwin CYGSH: C:\Cygwin\bin\bash -lc - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 ARCH: x86_64 CYGWIN: C:\Cygwin64 CYGSH: C:\Cygwin64\bin\bash -lc init: # Set "build version number" to "short-commit-hash" or when tagged to "tag name" (Travis style) - ps: >- Try { if ($env:APPVEYOR_REPO_TAG -eq "true") { Update-AppveyorBuild -Version "$env:APPVEYOR_REPO_TAG_NAME" } else { Update-AppveyorBuild -Version "$($env:APPVEYOR_REPO_COMMIT.substring(0,7))-dirty" } } Catch { Update-AppveyorBuild -Version "$($env:APPVEYOR_REPO_COMMIT.substring(0,7))-dirty" } install: - "%CYGWIN%\\setup-%ARCH%.exe -q --no-shortcuts -P cygwin-devel,git,gcc-core,libxml2,libxml2-devel,cmake,p7zip,libiconv,libiconv-devel" - '%CYGWIN%\bin\cygcheck -dc cygwin' build_script: - '%CYGSH% ". /etc/profile && cd $APPVEYOR_BUILD_FOLDER && mkdir build"' - '%CYGSH% ". /etc/profile && cd $APPVEYOR_BUILD_FOLDER/build && cmake -DMANPAGES=OFF -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON .."' - '%CYGSH% ". /etc/profile && cd $APPVEYOR_BUILD_FOLDER/build && cmake --build ."' after_build: - '%CYGSH% "echo $APPVEYOR_BUILD_VERSION > $APPVEYOR_BUILD_FOLDER/build/VERSION"' - '%CYGSH% "cd $APPVEYOR_BUILD_FOLDER/build && cp ../COPYING . && 7z a $APPVEYOR_BUILD_FOLDER/vcontrold_$(echo -n $APPVEYOR_BUILD_VERSION | sed -e s/^v//)-$APPVEYOR_BUILD_NUMBER-cygwin_$ARCH.zip *.exe COPYING VERSION"' artifacts: - name: vcontrold-cygwin_$(ARCH) path: '**\*.zip' type: zip deploy: - provider: GitHub artifact: /.*\.zip/ description: '$(APPVEYOR_REPO_COMMIT_MESSAGE)' draft: false prerelease: false auth_token: secure: qE6hexTUPfCElvkSDkIo9fflU6YweIcrGZ5x2wbw7qHDR2HIYczkMMiSUwvC5y9+ on: appveyor_repo_tag: true # deploy on tag push only 07070100000001000081A4000028240000003200000001607BF44800001648000000000000000000000000000000000000003300000000vcontrold-v0.98.10+git20210418.977e6f5/.travis.ymllanguage: c compiler: - gcc include: &toolchain_amd64 sudo: required addons: apt: packages: - cmake - libxml2-dev - python3-docutils - zip - checkinstall include: &toolchain_cross sudo: required addons: apt: packages: - cmake - libxml2-dev - python3-docutils - gcc-arm-linux-gnueabihf - gcc-multilib-arm-linux-gnueabihf - libc6-dev-armhf-cross - zip - checkinstall - debootstrap - qemu-user-static - binfmt-support include: &toolchain_linux_amd64 <<: *toolchain_amd64 env: - ARCH=$(dpkg --print-architecture) - TARGET=$(gcc -dumpmachine) - CC="gcc" - CMAKE_OPTS="-Wall" include: &toolchain_linux_armhf <<: *toolchain_cross env: - CROSS_TOOLCHAIN="true" - ARCH="armhf" - RELEASE="stable" - TARGET="arm-linux-gnueabihf" - CC="${TARGET}-gcc" - CMAKE_OPTS="-Wall -DCMAKE_TOOLCHAIN_FILE=${TRAVIS_BUILD_DIR}/cmake/Toolchain-rpi.cmake" env: global: - GH_REPO=$(echo -n "${TRAVIS_REPO_SLUG}" | cut -d "/" -f 2) - GH_USER=$(echo -n "${TRAVIS_REPO_SLUG}" | cut -d "/" -f 1) - CHROOT_DIR=${TRAVIS_BUILD_DIR}/chroot-raspbian-armhf matrix: include: - os: linux <<: *toolchain_linux_amd64 - os: linux <<: *toolchain_linux_armhf before_cache: - if [[ "${CROSS_TOOLCHAIN}" == "true" ]] ; then sudo chown -R ${USER} ${CHROOT_DIR} ; fi cache: directories: - ${CHROOT_DIR} before_script: - test -d ${CHROOT_DIR} || mkdir ${CHROOT_DIR} - mkdir build - cd build - if [[ "${CROSS_TOOLCHAIN}" == "true" ]] ; then if [[ "${CHROOT_DIR}" != "" ]] && find ${CHROOT_DIR} -iname "libxml2.so" 2>/dev/null | grep -q libxml2.so && find ${CHROOT_DIR} -iname "parser.h" 2>/dev/null | grep -q libxml ; then echo "Cache found" ; else sudo debootstrap --foreign --no-check-gpg --variant=minbase --include=libxml2,libxml2-dev,libc6-dev --arch=armhf ${RELEASE} ${CHROOT_DIR} http://archive.raspbian.org/raspbian ; sudo cp /usr/bin/qemu-arm-static ${CHROOT_DIR}/usr/bin/ ; sudo chroot ${CHROOT_DIR} ./debootstrap/debootstrap --second-stage; for FILE in $(find ${CHROOT_DIR} -xtype l) ; do sudo ln -sf $(realpath --relative-to=$(dirname ${FILE}) ${CHROOT_DIR}/$(readlink ${FILE})) ${FILE} ; done; fi fi script: - cmake ${CMAKE_OPTS} .. - VERBOSE=1 cmake --build . - VERSION=$(sed -n -e 's/#define VERSION "\(.*\)"/\1/p' ${TRAVIS_BUILD_DIR}/src/version.h) - DEPLOYFILEPREFIX="${GH_REPO}_${VERSION}" - DEPLOYFILEPREFIX_BIN="${DEPLOYFILEPREFIX}-${TRAVIS_BUILD_NUMBER}_${ARCH}" after_success: - cd ${TRAVIS_BUILD_DIR} - zip -j ${TRAVIS_BUILD_DIR}/${DEPLOYFILEPREFIX_BIN}.zip ${TRAVIS_BUILD_DIR}/build/vcontrold ${TRAVIS_BUILD_DIR}/build/vclient ${TRAVIS_BUILD_DIR}/build/doc/man/vcontrold.1.gz ${TRAVIS_BUILD_DIR}/build/doc/man/vclient.1.gz ${TRAVIS_BUILD_DIR}/COPYING ${TRAVIS_BUILD_DIR}/README.md - md5sum "${DEPLOYFILEPREFIX_BIN}.zip" > "${DEPLOYFILEPREFIX_BIN}.zip.md5sum" - sha256sum "${DEPLOYFILEPREFIX_BIN}.zip" > "${DEPLOYFILEPREFIX_BIN}.zip.sha256sum" - unzip -l ${TRAVIS_BUILD_DIR}/${DEPLOYFILEPREFIX_BIN}.zip - if [[ "${TRAVIS_BUILD_NUMBER}.1" == "${TRAVIS_JOB_NUMBER}" ]] ; then git archive --prefix "${GH_REPO}-${VERSION}/" -o "${DEPLOYFILEPREFIX}.orig.tar" ${TRAVIS_COMMIT} ; tar -rf "${DEPLOYFILEPREFIX}.orig.tar" --owner=root --group=root --transform="s#^#${GH_REPO}-${VERSION}/#" src/version.h ; tar --delete -f "${DEPLOYFILEPREFIX}.orig.tar" "${GH_REPO}-${VERSION}/.gitignore" "${GH_REPO}-${VERSION}/.travis.yml" ; gzip --best "${DEPLOYFILEPREFIX}.orig.tar" ; md5sum "${DEPLOYFILEPREFIX}.orig.tar.gz" > "${DEPLOYFILEPREFIX}.orig.tar.gz.md5sum" ; sha256sum "${DEPLOYFILEPREFIX}.orig.tar.gz" > "${DEPLOYFILEPREFIX}.orig.tar.gz.sha256sum" ; tar tzvf "${DEPLOYFILEPREFIX}.orig.tar.gz" --force-local ; fi - if [[ -n "${TRAVIS_TAG}" ]] ; then sudo checkinstall --strip=no --install=no --pkgname="$GH_REPO" --pkgversion="$VERSION" --pkgrelease=$TRAVIS_BUILD_NUMBER --arch="$ARCH" --maintainer="${GH_USER}@GitHub" --pkgsource="https://github.com/${GH_USER}/${GH_REPO}/releases/download/v${VERSION}/${DEPLOYFILEPREFIX}.orig.tar.gz" --pkgaltsource="https://github.com/${GH_USER}/${GH_REPO}/" --pkglicense="GPLv3" --pakdir=${TRAVIS_BUILD_DIR} -D -y cmake --build ./build/ --target install ; sudo chown travis "${DEPLOYFILEPREFIX_BIN}.deb" ; dpkg --info "${DEPLOYFILEPREFIX_BIN}.deb" ; dpkg --contents "${DEPLOYFILEPREFIX_BIN}.deb" ; md5sum "${DEPLOYFILEPREFIX_BIN}.deb" > "${DEPLOYFILEPREFIX_BIN}.deb.md5sum" ; sha256sum "${DEPLOYFILEPREFIX_BIN}.deb" > "${DEPLOYFILEPREFIX_BIN}.deb.sha256sum" ; fi - ls -laF ${TRAVIS_BUILD_DIR}/${DEPLOYFILEPREFIX}* deploy: provider: releases api_key: secure: dzTS/n6w0WXczRZZ/4lbW+zX79aVgsY223d9EEeOneqSsekll9ilU+akEhY0z2SvZPMdeo4ywdhdtopEK+9q7yjeU7qFPC0hbXUIqDc1c78UqNl7X3/n+est7IR2yLdKUSLcLi6E35D0Wr5QEu1sJo2ktVkozaCb69Ql7VajZggyuL/vykJMHU15EVQ4jWVdY5vWJZ/m2gN93JD0FZl/TEdnJX9NkStCbrUFveM411nwwiG7sjh3aSCKqXIERACy6uK70nstMFKZeF+go48V60TVS46iATD5oq64X6Qa8HpfeVR/+307JhcpXd1cWw1MmfUxmKWjcM8A6nED1AY5K/GRPTOLs004N6NjmY5B4svzC2tWt6PQEX/rvOSvQg8d3lcgOBcTznRVhpOuj3O63U/TjNd9WaD5NPeUogqV9lNVXg8UgZ9hrxMs80qNJGAZyid8x7XfDQ5bVnuuAqpSlUuWsyPKdDolq5RMsOUQ/o/yvZdB45C/EX6gZLUPOeiR+GffnXDnniYQKQYm+wL5UcDjqSKZdLCgZMrKKd7rCVIcSqs0E36y8BubK3CeiLOMUxmjcrbSE7YHmYDcnwohczm6QRUDS/fPbzd/XfIuIRzRkc9mliDVCE2JXaRJQA5U+TINBHUMUfnyVSENLrQaOweg/pi96B5XoJKSs6vl9YE= file_glob: true file: ${TRAVIS_BUILD_DIR}/${DEPLOYFILEPREFIX}* skip_cleanup: true on: repo: openv/vcontrold branch: master tags: true 07070100000002000081A4000028240000003200000001607BF44800000CD5000000000000000000000000000000000000003600000000vcontrold-v0.98.10+git20210418.977e6f5/CMakeLists.txtcmake_minimum_required(VERSION 3.2.0) project(vcontrold C) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) # CMAKE_INSTALL_PREFIX defaults to /usr/local, but it should go to /usr set(CMAKE_INSTALL_PREFIX /usr) endif() option(MANPAGES "Build man pages via rst2man" ON) option(VCLIENT "Build the vclient helper program (for communication with vcontrold)" ON) option(VSIM "Build the vsim helper program (for development and testing purposes)" OFF) # Default to -fcommon for GCC 10 if (CMAKE_C_COMPILER_ID MATCHES "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER 10) set (CMAKE_C_FLAGS "-fcommon ${CMAKE_C_FLAGS}") endif () # additional define to compile on macOS Catalina by hmueller01 if (APPLE) set (CMAKE_C_FLAGS "-D_DARWIN_C_SOURCE ${CMAKE_C_FLAGS}") endif (APPLE) find_package(LibXml2 REQUIRED) if(MANPAGES) find_program(RST2MAN NAMES rst2man rst2man.py) if(RST2MAN) message(STATUS "Found rst2man: ${RST2MAN}") else() message(FATAL_ERROR "Could not find a rst2man executable. Either set the \"MANPAGES\" " "option to \"OFF\" (via cmake -DMANPAGES=OFF) or install Python's " "Docutils (cf. http://docutils.sourceforge.net/).") endif() endif() add_custom_target( UpdateVersion ALL COMMAND ${CMAKE_COMMAND} -DBASE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/UpdateVersion.cmake COMMENT "Updating version header." BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/src/version.h ) add_definitions(-D_XOPEN_SOURCE=700) include_directories( ${LIBXML2_INCLUDE_DIR} ) set(vcontrold_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/io.c ${CMAKE_CURRENT_SOURCE_DIR}/src/common.c ${CMAKE_CURRENT_SOURCE_DIR}/src/xmlconfig.c ${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c ${CMAKE_CURRENT_SOURCE_DIR}/src/socket.c ${CMAKE_CURRENT_SOURCE_DIR}/src/semaphore.c ${CMAKE_CURRENT_SOURCE_DIR}/src/framer.c ${CMAKE_CURRENT_SOURCE_DIR}/src/unit.c ${CMAKE_CURRENT_SOURCE_DIR}/src/arithmetic.c ${CMAKE_CURRENT_SOURCE_DIR}/src/vcontrold.c ) set(vclient_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/common.c ${CMAKE_CURRENT_SOURCE_DIR}/src/socket.c ${CMAKE_CURRENT_SOURCE_DIR}/src/io.c ${CMAKE_CURRENT_SOURCE_DIR}/src/client.c ${CMAKE_CURRENT_SOURCE_DIR}/src/vclient.c ) set(vsim_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/socket.c ${CMAKE_CURRENT_SOURCE_DIR}/src/vsim.c ) find_package(Threads) set(LIBS ${LIBS} ${LIBXML2_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS} ) add_executable(vcontrold ${vcontrold_SRCS}) target_link_libraries(vcontrold ${LIBS}) add_dependencies(vcontrold UpdateVersion) if(VCLIENT) add_executable(vclient ${vclient_SRCS}) add_dependencies(vclient UpdateVersion) endif() if(VSIM) add_executable(vsim ${vsim_SRCS}) add_dependencies(vsim UpdateVersion) endif() if(MANPAGES) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/doc/man) endif() install(TARGETS vcontrold DESTINATION ${CMAKE_INSTALL_PREFIX}/sbin) if(VCLIENT) install(TARGETS vclient DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) endif() if(VSIM) install(TARGETS vsim DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) endif() 07070100000003000081A4000028240000003200000001607BF4480000894B000000000000000000000000000000000000002F00000000vcontrold-v0.98.10+git20210418.977e6f5/COPYING GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. <http://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 <http://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 <http://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 <http://www.gnu.org/philosophy/why-not-lgpl.html>. 07070100000004000081A4000028240000003200000001607BF44800000382000000000000000000000000000000000000003100000000vcontrold-v0.98.10+git20210418.977e6f5/README.md# :fire: vcontrold _vcontrold_ is a software daemon written in C for communication with the "Optolink" interface of Viessmann Vito heating controllers. For building and installation instructions see `doc/INSTALL.md`. [Binary packages](https://github.com/openv/vcontrold/releases) are available for different platforms. Please visit the [OpenV Wiki](https://github.com/openv/openv/wiki/) for in-depth info and examples. ## DE _vcontrold_ ist ein in C geschriebener Software-Daemon zur Kommunikation mit der „Optolink“-Schnittstelle von Viessmann-Vito-Heizungssteuerungen. Der Build-Prozess und die Installation sind kurz unter `doc/INSTALL.md` beschrieben. Für einige Plattformen sind kompilierte [Installations-Pakete](https://github.com/openv/vcontrold/releases) verfügbar. Infos zur Einrichtung und Benutzung sind im [OpenV-Wiki](https://github.com/openv/openv/wiki/) beschrieben. 07070100000005000041ED000028240000003200000003607BF44800000000000000000000000000000000000000000000002D00000000vcontrold-v0.98.10+git20210418.977e6f5/cmake07070100000006000081A4000028240000003200000001607BF4480000042F000000000000000000000000000000000000004100000000vcontrold-v0.98.10+git20210418.977e6f5/cmake/Toolchain-rpi.cmake# CMAKE_TOOLCHAIN_FILE for cross-compiling for RPi et al. SET(CMAKE_SYSTEM_NAME Linux) SET(CMAKE_SYSTEM_VERSION 1) if(DEFINED ENV{CHROOT_DIR}) SET(CHROOT_DIR $ENV{CHROOT_DIR}) else(DEFINED ENV{CHROOT_DIR}) SET(CHROOT_DIR /mnt/raspbian_lite) endif(DEFINED ENV{CHROOT_DIR}) SET(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) SET(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++) SET(CMAKE_SYSROOT ${CHROOT_DIR}) SET(CMAKE_FIND_ROOT_PATH ${CHROOT_DIR}) # don't search for programs on CHROOT_DIR, use those on build host SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # search libraries and headers on CHROOT_DIR SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(FLAGS "-Wl,-rpath-link,${CHROOT_DIR}/lib/arm-linux-gnueabihf -Wl,-rpath-link,${CHROOT_DIR}/usr/lib/arm-linux-gnueabihf -Wl,-rpath-link,${CHROOT_DIR}/usr/local/lib,-unresolved-symbols=ignore-in-shared-libs") UNSET(CMAKE_C_FLAGS CACHE) UNSET(CMAKE_CXX_FLAGS CACHE) SET(CMAKE_C_FLAGS ${FLAGS} CACHE STRING "" FORCE) SET(CMAKE_CXX_FLAGS ${FLAGS} CACHE STRING "" FORCE) 07070100000007000041ED000028240000003200000002607BF44800000000000000000000000000000000000000000000003500000000vcontrold-v0.98.10+git20210418.977e6f5/cmake/modules07070100000008000081A4000028240000003200000001607BF4480000057F000000000000000000000000000000000000004A00000000vcontrold-v0.98.10+git20210418.977e6f5/cmake/modules/GitDescription.cmake# Copyright 2012 Johannes Zarl-Zierl <johannes@zarl-zierl.at> # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # This file is under the public domain and can be reused without restrictions. include (CMakeParseArguments) function (git_get_description DESCVAR) cmake_parse_arguments (_GGD "SEND_ERROR" "GIT_ARGS" "" "${ARGN}") if (SEND_ERROR) set (_severity SEND_ERROR) else() set (_severity WARNING) endif() find_package (Git QUIET) if (NOT GIT_FOUND) message (${severity} "git_get_description: could not find package git!") set (${DESCVAR} "-NOTFOUND" PARENT_SCOPE) return() endif() execute_process (COMMAND "${GIT_EXECUTABLE}" describe ${_GGD_GIT_ARGS} WORKING_DIRECTORY "${BASE_DIR}" RESULT_VARIABLE _gitresult OUTPUT_VARIABLE _gitdesc ERROR_VARIABLE _giterror OUTPUT_STRIP_TRAILING_WHITESPACE ) if (NOT _gitresult EQUAL 0) message (${_severity} "git_get_description: error during execution of git describe!") message ( ${_severity} "Error was: ${_giterror}" ) set (${DESCVAR} "-NOTFOUND" PARENT_SCOPE) else() set (${DESCVAR} "${_gitdesc}" PARENT_SCOPE) endif() endfunction() 07070100000009000081A4000028240000003200000001607BF448000008B0000000000000000000000000000000000000004900000000vcontrold-v0.98.10+git20210418.977e6f5/cmake/modules/UpdateVersion.cmake# Copyright 2012 Johannes Zarl <johannes@zarl-zierl.at> # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # This file is under the public domain and can be reused without restrictions. if (NOT DEFINED BASE_DIR) message (FATAL_ERROR "UpdateVersion.cmake: BASE_DIR not set. Please supply base working directory!") endif() function (createVersionH version) # write version info to a temporary file configure_file (${BASE_DIR}/src/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h~) # update info if changed execute_process (COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/version.h~ ${BASE_DIR}/src/version.h) # make sure info doesn't get stale file (REMOVE ${CMAKE_CURRENT_BINARY_DIR}/version.h~) endfunction(createVersionH) # git or tarball? if (EXISTS ${BASE_DIR}/.git) # --> git: include (${CMAKE_CURRENT_LIST_DIR}/GitDescription.cmake) git_get_description (VERSION GIT_ARGS --dirty) if (NOT VERSION) set (VERSION "unknown") else() # Remove a trailing "v" from the version. string(REGEX REPLACE "^v" "" VERSION ${VERSION}) endif() message (STATUS "Updating version information to ${VERSION} ...") createVersionH(${VERSION}) else() # --> tarball if (NOT EXISTS ${BASE_DIR}/src/version.h) message (WARNING "The generated file \"version.h\" does not exist!") message (WARNING "Either, something went wrong when releasing this tarball, or this is some GitHub snapshot.") get_filename_component(BASE_DIR_L "${BASE_DIR}" NAME) string(REGEX REPLACE "[^-]+-([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)" "\\1.\\2.\\3\\4" VERSION "${BASE_DIR_L}") if ("${VERSION}" STREQUAL "${BASE_DIR_L}") message(WARNING "Could not derive version from name of project directory, set version as \"unknown\".") set (VERSION "unknown") else() message(WARNING "Version guessed from project directory name as \"${VERSION}\".") endif() message (WARNING "Generating a dummy version.h.") createVersionH(${VERSION}) endif() endif() 0707010000000A000041ED000028240000003200000004607BF44800000000000000000000000000000000000000000000002B00000000vcontrold-v0.98.10+git20210418.977e6f5/doc0707010000000B000081A4000028240000003200000001607BF44800000092000000000000000000000000000000000000003300000000vcontrold-v0.98.10+git20210418.977e6f5/doc/AUTHORSThis software has many authors. See the source and the repository for some infos. Original authors: * marcust * brainhunter * vheat * fnobis 0707010000000C000081A4000028240000003200000001607BF448000005E7000000000000000000000000000000000000003600000000vcontrold-v0.98.10+git20210418.977e6f5/doc/INSTALL.md# Building via cmake The `vcontrold` package depends on `libxml2`. For the build process on \*nix machines, usually the `libxml2-dev` package is needed. To get the documentation converted from Restructured Text (similar to Markdown) to the format used by `man`, the `rst2man` utility has to be installed. The package can be built with the normal cmake procedure. Simply execute the following steps in your source directory: ``` mkdir build cd build cmake .. make ``` ### Build options There are three options for the build process with their defaults: * _MANPAGES=ON_ Build man pages via `rst2man` * _VCLIENT=ON_ Build the `vclient` helper program (for communication with vcontrold) * _VSIM=OFF_ Build the `vsim` helper program (for development and testing purposes) The installation path can be altered by * _CMAKE_INSTALL_PREFIX=`/usr/local`_ This directory is prepended onto all install directories. This variable defaults to `/usr/local` on UNIX and `c:/Program Files` on Windows Invocation is as follows: ``` cmake -DVSIM=ON -DMANPAGES=OFF -DCMAKE_INSTALL_PREFIX=/usr/local .. ``` ### Installation To install the package, execute ``` sudo make install ``` The whole installation can be relocated to a different directory by supplying a `DESTDIR` variable: ``` sudo make DESTDIR=<DESTDIR> install ``` In this case, the entire package will be installed in a directory with the installation prefix prepended with the `DESTDIR` value, which finally gives `<DESTDIR>/<CMAKE_INSTALL_PREFIX>`. 0707010000000D000081A4000028240000003200000001607BF448000003C9000000000000000000000000000000000000003800000000vcontrold-v0.98.10+git20210418.977e6f5/doc/README-de.md*********************************************************** Aktuelle Informationen und Dokus finden sich im Wiki: https://github.com/openv/vcontrold *********************************************************** Die Software wird unter der GPL veroeffentlicht. *********************************************************** vcontrold ist ein in C geschriebener Daemon, der die Kommunikation mit der Vito-Steuerung übernimmt. Die Konfiguration erfolgt über XML-Dateien. Der Daemon bietet eine ASCII-Socketschnittstelle, die mit telnet oder dem vclient Programm angespochen werden kann. Der Quelltext kann im git Repository heruntergeladen werden. git clone https://github.com/openv/vcontrold.git vcontrold-code cd vcontrold-code mkdir ./build && cd ./build cmake .. make && make install Die Konfiguration des Programms wird in zwei XML-Dateien vorgenommen: vcontrold.xml : Programmspezifische Definitionen vito.xml: Definition der Kommandos und Devices 0707010000000E000041ED000028240000003200000003607BF44800000000000000000000000000000000000000000000003400000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples0707010000000F000081A4000028240000003200000001607BF44800000190000000000000000000000000000000000000003F00000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/README.txt*********************************************************** Aktuelle Informationen und Dokus finden sich im Wiki: https://github.com/openv/openv/wiki *********************************************************** Die Software wird unter der GPL veroeffentlicht. *********************************************************** Die Beispiel Scripte veranschaulichen das Loggen von Betriebsdaten in eine RRD. 07070100000010000081A4000028240000003200000001607BF448000000D3000000000000000000000000000000000000004100000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/rrd.min.cmdsgetTempA getTempWWist getTempKist getTempKsoll getTempVListM2 getTempKol getTempSpu getBrennerStatus getPumpeStatusA1M1 getPumpeStatusM2 getPumpeStatusSp getPumpeStatusZirku getPumpeStatusSolar getSolarStatusWW 07070100000011000081A4000028240000003200000001607BF44800000206000000000000000000000000000000000000003D00000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/rrd.tmpl#/bin/sh # Script Template # solarix@pingos.de # db="/root/vitotools/vitodb.rrd" BrennerStatus=`expr \( $R8 \* 10 \)` PumpeStatusA1M1=`expr \( $R9 \* 20 \)` PumpeStatusM2=`expr \( $R10 \* 30 \)` PumpeStatusSp=`expr \( $R11 \* 40 \)` PumpeStatusZirku=`expr \( $R12 \* 50 \)` PumpeStatusSolar=`expr \( $R13 \* 60 \)` SolarStatusWW=`expr \( $R14 \* 70 \)` /opt/bin/rrdtool update \$db N:$1:$2:$3:$4:$5:$6:$7:$BrennerStatus:$PumpeStatusA1M1:$PumpeStatusM2:$PumpeStatusSp:$PumpeStatusZirku:$PumpeStatusSolar:$SolarStatusWW 07070100000012000041ED000028240000003200000002607BF44800000000000000000000000000000000000000000000003900000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/rrdb07070100000013000081ED000028240000003200000001607BF4480000028F000000000000000000000000000000000000004700000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/rrdb/createRRDB.sh/opt/usr/bin/rrdtool create /extern/rrdb/vito.rrd --step 300 \ DS:tempA:GAUGE:700:-50:100 \ DS:tempWWist:GAUGE:700:0:100 \ DS:tempWWsoll:GAUGE:700:0:100 \ DS:tempKist:GAUGE:700:0:100 \ DS:tempKsoll:GAUGE:700:0:100 \ DS:BetriebsArt:GAUGE:700:0:5 \ DS:PumpeSollM1:GAUGE:700:0:100 \ DS:ExtBA:GAUGE:700:0:1 \ DS:PumpeStatusM1:GAUGE:700:0:1 \ DS:BrennerStunden1:COUNTER:700:0:100000 \ DS:TempRaumNorSollM1:GAUGE:700:0:100 \ DS:TempRaumRedSollM1:GAUGE:700:0:100 \ DS:BrennerStatus:GAUGE:700:0:1 \ DS:PumpeStatusZirku:GAUGE:700:0:1 \ DS:getVentilStatus:GAUGE:700:0:1 \ RRA:AVERAGE:0.5:1:2020 \ RRA:MIN:0.5:12:2400 \ RRA:MAX:0.5:12:2400 \ RRA:AVERAGE:0.5:12:2400 07070100000014000081ED000028240000003200000001607BF44800000705000000000000000000000000000000000000004200000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/rrdb/graph.shLD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/usr/lib export LD_LIBRARY_PATH /opt/usr/bin/rrdtool graph /tmp/vito.png \ --start end-1d --end now --width 800 --height 300 \ --title 'Vito-Messwerte' \ DEF:tempA=/extern/rrdb/vito.rrd:tempA:AVERAGE \ DEF:tempWWist=/extern/rrdb/vito.rrd:tempWWist:AVERAGE \ DEF:tempKist=/extern/rrdb/vito.rrd:tempKist:AVERAGE \ DEF:tempKsoll=/extern/rrdb/vito.rrd:tempKsoll:AVERAGE \ DEF:PumpeSollM1=/extern/rrdb/vito.rrd:PumpeSollM1:AVERAGE \ DEF:PumpeStatusM1=/extern/rrdb/vito.rrd:PumpeStatusM1:AVERAGE \ DEF:BetriebsArt=/extern/rrdb/vito.rrd:BetriebsArt:AVERAGE \ DEF:ExtBA=/extern/rrdb/vito.rrd:ExtBA:AVERAGE \ DEF:BrennerStatus=/extern/rrdb/vito.rrd:BrennerStatus:AVERAGE \ DEF:PumpeStatusZirku=/extern/rrdb/vito.rrd:PumpeStatusZirku:AVERAGE \ DEF:VentilStatus=/extern/rrdb/vito.rrd:getVentilStatus:AVERAGE \ CDEF:PSM1=PumpeStatusM1,30,* \ CDEF:BA=BetriebsArt,10,* \ CDEF:EBA=ExtBA,25,* \ CDEF:BS=BrennerStatus,40,* \ CDEF:VS=VentilStatus,60,* \ CDEF:PS=PumpeStatusZirku,70,* \ LINE1:tempA#0000FF:tempA \ LINE1:tempWWist#FF00FF:tempWWist \ LINE1:tempKist#00FFFF:tempKist \ LINE1:tempKsoll#CCCCCC:tempKsoll \ LINE1:BA#555555:Betriebsart \ LINE1:EBA#779922:Ext.Umschaltung \ LINE1:BS#11ABCD:Brennerstatus \ LINE1:VS#23AA77:Ventilstatus \ LINE1:PS#880044:Zirku-Pumpe \ VDEF:tempAmax=tempA,MAXIMUM \ VDEF:tempAmin=tempA,MINIMUM \ VDEF:tempWWmax=tempWWist,MAXIMUM \ VDEF:tempWWmin=tempWWist,MINIMUM \ VDEF:BSmax=BS,MAXIMUM \ VDEF:VSmax=VS,MAXIMUM \ COMMENT:"\l" \ COMMENT:"Aussentemp." \ GPRINT:tempAmin:" Min. %02.1lf Grad C" \ GPRINT:tempAmax:"Max. %02.1lf Grad C" \ COMMENT:"\l" \ COMMENT:"Warmwassertemp." \ GPRINT:tempWWmin:"Min. %02.1lf Grad C" \ GPRINT:tempWWmax:"Max. %02.1lf Grad C" \ COMMENT:"\l" \ GPRINT:BSmax:"Brenner %02lf" \ GPRINT:VSmax:"Venitl %02lf" 07070100000015000081ED000028240000003200000001607BF44800000692000000000000000000000000000000000000004800000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/rrdb/rrdb-update.shif [ "x" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: getDevType:" >>/tmp/vc-err.txt exit 1; fi if [ "x" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: getTempA:" >>/tmp/vc-err.txt exit 1; fi if [ "x" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: getTempWWist:" >>/tmp/vc-err.txt exit 1; fi if [ "x" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: getTempWWsoll:" >>/tmp/vc-err.txt exit 1; fi if [ "x" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: getTempKist:" >>/tmp/vc-err.txt exit 1; fi if [ "x" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: getTempKsoll:" >>/tmp/vc-err.txt exit 1; fi if [ "x" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: unit off:" >>/tmp/vc-err.txt exit 1; fi if [ "x" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: getBetriebArtM1:" >>/tmp/vc-err.txt exit 1; fi if [ "x" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: unit on:" >>/tmp/vc-err.txt exit 1; fi if [ "x" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: getPumpeSollM1:" >>/tmp/vc-err.txt exit 1; fi BA=`echo 03 |cut -d ' ' -f 1` ST=`echo 21639.000000 h|cut -d '.' -f 1` LD_LIBRARY_PATH=':/opt/lib:/opt/usr/lib:/opt/usr/lib:/opt/usr/lib' export LD_LIBRARY_PATH rrdtool update /home/marcus/rrdb/vito.rrd N:15.500000:56.500000:50.000000:33.500000:39.000000:$BA:33.000000:0:0:$ST 07070100000016000081A4000028240000003200000001607BF44800000ADB000000000000000000000000000000000000004A00000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/rrdb/rrdb-update.tmplif [ "x$E1" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C1:$E1" >>/tmp/vc-err.txt exit 1; fi if [ "x$E2" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C2:$E2" >>/tmp/vc-err.txt exit 1; fi if [ "x$E3" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C3:$E3" >>/tmp/vc-err.txt exit 1; fi if [ "x$E4" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C4:$E4" >>/tmp/vc-err.txt exit 1; fi if [ "x$E5" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C5:$E5" >>/tmp/vc-err.txt exit 1; fi if [ "x$E6" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C6:$E6" >>/tmp/vc-err.txt exit 1; fi if [ "x$E7" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C7:$E7" >>/tmp/vc-err.txt exit 1; fi if [ "x$E8" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C8:$E8" >>/tmp/vc-err.txt exit 1; fi if [ "x$E9" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C9:$E9" >>/tmp/vc-err.txt exit 1; fi if [ "x$E10" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C10:$E10" >>/tmp/vc-err.txt exit 1; fi if [ "x$E11" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C11:$E11" >>/tmp/vc-err.txt exit 1; fi if [ "x$E12" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C12:$E12" >>/tmp/vc-err.txt exit 1; fi if [ "x$E13" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C13:$E13" >>/tmp/vc-err.txt exit 1; fi if [ "x$E14" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C14:$E14" >>/tmp/vc-err.txt exit 1; fi if [ "x$E15" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C15:$E15" >>/tmp/vc-err.txt exit 1; fi if [ "x$E16" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C16:$E16" >>/tmp/vc-err.txt exit 1; fi if [ "x$E17" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C17:$E17" >>/tmp/vc-err.txt exit 1; fi if [ "x$E18" != x ]; then echo -n `date` >>/tmp/vc-err.txt echo "es ist ein Fehler aufgetreten: $C18:$E18" >>/tmp/vc-err.txt exit 1; fi BA=`echo $R8|cut -d ' ' -f 1` ST=`echo $R13|cut -d '.' -f 1` LD_LIBRARY_PATH=':/opt/lib:/opt/usr/lib:/opt/usr/lib:/opt/usr/lib' export LD_LIBRARY_PATH /opt/usr/bin/rrdtool update /extern/rrdb/vito.rrd N:$2:$3:$4:$5:$6:$BA:$10:$R11:$R12:$ST:$14:$15:$R16:$R17:$R18 07070100000017000081A4000028240000003200000001607BF4480000005C000000000000000000000000000000000000004700000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/rrdb/vc-aufruf.txtvclient -h 192.168.1.4:3002 -f ./vc-commands.txt -t ./rrdb-update.tmpl -x ./rrdb-update.sh 07070100000018000081A4000028240000003200000001607BF44800000105000000000000000000000000000000000000004900000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/rrdb/vc-commands.txtgetDevType getTempA getTempWWist getTempWWsoll getTempKist getTempKsoll unit off getBetriebArtM1 unit on getPumpeSollM1 getExtBA getPumpeStatusM1 getBrennerStunden1 getTempRaumNorSollM1 getTempRaumRedSollM1 getBrennerStatus getPumpeStatusZirku getVentilStatus 07070100000019000081A4000028240000003200000001607BF44800000F12000000000000000000000000000000000000004100000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/sim-2098.ini[DATA] ;getTempA 04 = 05 01 F7 08 00 02 = 3C 00 ;getTempWWist 04 = 05 01 F7 08 04 02 = 1E 02 ;getTempWWsoll 04 = 05 01 F7 63 00 01 = 37 ;getTempKist 04 = 05 01 F7 08 02 02 = BF 01 ;getTempKsoll 04 = 05 01 F7 55 02 02 = 46 00 ;getTempVListM2 04 = 05 01 F7 08 0C 02 = E0 00 ;getTempVLsollA1M1 04 = 05 01 F7 25 44 02 = FF FF ;getTempVLsollM2 04 = 05 01 F7 35 44 02 = FF FF ;getTempVLsollM3 04 = 05 01 F7 45 44 02 = FF FF ;getTempKol 04 = 05 01 F7 65 64 02 = 3A 00 ;getTempSpu 04 = 05 01 F7 65 66 02 = A5 00 ;getTempRaumNorSoll1 04 = 05 01 F7 23 06 01 = 16 ;getTempRaumNorSoll2 04 = 05 01 F7 33 06 01 = 16 ;getTempRaumRedSoll1 04 = 05 01 F7 23 07 01 = 03 ;getTempRaumRedSoll2 04 = 05 01 F7 33 07 01 = 03 ;getBrennerStatus 04 = 05 01 F7 55 1E 01 = 00 ;getBrennerStarts 04 = 05 01 F7 08 8A 02 = 5E 06 ;getBrennerStunden 04 = 05 01 F7 08 A7 04 = 87 03 1A 00 ;getPumpeStatusA1M1 04 = 05 01 F7 29 06 01 = 00 ;getPumpeStatusSp 04 = 05 01 F7 08 45 01 = 00 ;getPumpeStatusZirku 04 = 05 01 F7 08 46 01 = 00 ;getPumpeStatusSolar 04 = 05 01 F7 65 52 01 = 00 ;getPumpeStatusM2 04 = 05 01 F7 39 06 01 = 00 ;getMischerA1M1 04 = 05 01 F7 25 4C 01 = FF ;getMischerM2 04 = 05 01 F7 35 4C 01 = FF ;getMischerM3 04 = 05 01 F7 45 4C 01 = FF ;getSolarStatusWW 04 = 05 01 F7 65 51 01 = 00 ;getTimerM1Mo 04 = 05 01 F7 20 00 08 = 93 A0 FF FF FF FF FF FF ;getTimerM1Di 04 = 05 01 F7 20 08 08 = 93 A0 FF FF FF FF FF FF ;getTimerM1Mi 04 = 05 01 F7 20 10 08 = 93 A0 FF FF FF FF FF FF ;getTimerM1Do 04 = 05 01 F7 20 18 08 = 93 A0 FF FF FF FF FF FF ;getTimerM1Fr 04 = 05 01 F7 20 20 08 = 93 A0 FF FF FF FF FF FF ;getTimerM1Sa 04 = 05 01 F7 20 28 08 = 93 A0 FF FF FF FF FF FF ;getTimerM1So 04 = 05 01 F7 20 30 08 = 93 A0 FF FF FF FF FF FF ;getTimerM2Mo 04 = 05 01 F7 30 00 08 = 30 48 FF FF FF FF FF FF ;getTimerM2Di 04 = 05 01 F7 30 08 08 = 30 48 FF FF FF FF FF FF ;getTimerM2Mi 04 = 05 01 F7 30 10 08 = 30 48 FF FF FF FF FF FF ;getTimerM2Do 04 = 05 01 F7 30 18 08 = 30 48 FF FF FF FF FF FF ;getTimerM2Fr 04 = 05 01 F7 30 20 08 = 30 48 FF FF FF FF FF FF ;getTimerM2Sa 04 = 05 01 F7 30 28 08 = 88 9B FF FF FF FF FF FF ;getTimerM2So 04 = 05 01 F7 30 30 08 = FF FF FF FF FF FF FF FF ;getTimerWWMo 04 = 05 01 F7 21 00 08 = 30 48 93 9B FF FF FF FF ;getTimerWWDi 04 = 05 01 F7 21 08 08 = 30 48 93 9B FF FF FF FF ;getTimerWWMi 04 = 05 01 F7 21 10 08 = 30 48 93 9B FF FF FF FF ;getTimerWWDo 04 = 05 01 F7 21 18 08 = 30 48 93 9B FF FF FF FF ;getTimerWWFr 04 = 05 01 F7 21 20 08 = 30 48 93 9B FF FF FF FF ;getTimerWWSa 04 = 05 01 F7 21 28 08 = 38 48 90 9B FF FF FF FF ;getTimerWWSo 04 = 05 01 F7 21 30 08 = 38 48 93 9B FF FF FF FF ;getTimerZirkuMo 04 = 05 01 F7 22 00 08 = 28 2A 58 5D 95 A2 FF FF ;getTimerZirkuDi 04 = 05 01 F7 22 08 08 = 28 2A 58 5D 95 A2 FF FF ;getTimerZirkuMi 04 = 05 01 F7 22 10 08 = 28 2A 58 5D 95 A2 FF FF ;getTimerZirkuDo 04 = 05 01 F7 22 18 08 = 28 2A 58 5D 95 A2 FF FF ;getTimerZirkuFr 04 = 05 01 F7 22 20 08 = 28 2A 58 5D 95 A2 FF FF ;getTimerZirkuSa 04 = 05 01 F7 22 28 08 = 3B 45 58 5D 92 A2 FF FF ;getTimerZirkuSo 04 = 05 01 F7 22 30 08 = 40 45 58 5D 95 A2 FF FF ;getBetriebArtM1 04 = 05 01 F7 23 01 01 = 04 ;getBetriebArtM2 04 = 05 01 F7 33 01 01 = 04 ;getBetriebSparM1 04 = 05 01 F7 23 02 01 = 00 ;getBetriebSparM2 04 = 05 01 F7 33 02 01 = 00 ;getBetriebPartyM1 04 = 05 01 F7 23 03 01 = 00 ;getBetriebPartyM2 04 = 05 01 F7 33 03 01 = 00 ;getSolarStunden 04 = 05 01 F7 65 68 02 = D1 05 ;getSolarLeistung 04 = 05 01 F7 65 60 04 = A0 06 00 00 ;getStatusFrostM1 04 = 05 01 F7 25 00 01 = 02 ;getStatusFrostM2 04 = 05 01 F7 35 00 01 = 02 ;getStatusStoerung 04 = 05 01 F7 75 79 01 = 00 ;getTempPartyM1 04 = 05 01 F7 23 08 01 = 18 ;getTempPartyM2 04 = 05 01 F7 33 08 01 = 16 0707010000001A000081A4000028240000003200000001607BF44800000033000000000000000000000000000000000000003D00000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/sql.tmplINSERT INTO messwerte values (CURRENT_DATE,$1,$2); 0707010000001B000081A4000028240000003200000001607BF4480000108A000000000000000000000000000000000000004700000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/vcontrold.initd.sh#! /bin/sh ### BEGIN INIT INFO # Provides: vcontrold # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Initscript to start Viessmann vcontrold deamon # Description: This file should be used to construct scripts to be # placed in /etc/init.d. ### END INIT INFO # Author: Michael Pucher <tech@michaelpucher.net> # # Please remove the "Author" lines above and replace them # with your own name if you copy and modify this script. # Do NOT "set -e" # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="Viessmann vcontrold deamon" NAME=vcontrold DAEMON=/usr/local/sbin/$NAME #DAEMON_ARGS="--options args" DAEMON_ARGS="" PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME # Exit if the package is not installed [ -x "$DAEMON" ] || exit 0 # Read configuration variable file if it is present [ -r /etc/default/$NAME ] && . /etc/default/$NAME # Load the VERBOSE setting and other rcS variables . /lib/init/vars.sh # Define LSB log_* functions. # Depend on lsb-base (>= 3.2-14) to ensure that this file is present # and status_of_proc is working. . /lib/lsb/init-functions # # Function that starts the daemon/service # do_start() { # Return # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ || return 1 start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ $DAEMON_ARGS \ || return 2 # Add code here, if necessary, that waits for the process to be ready # to handle requests from services started subsequently which depend # on this one. As a last resort, sleep for some time. } # # Function that stops the daemon/service # do_stop() { # Return # 0 if daemon has been stopped # 1 if daemon was already stopped # 2 if daemon could not be stopped # other if a failure occurred start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 # Wait for children to finish too if this is a daemon that forks # and if the daemon is only ever run from this initscript. # If the above conditions are not satisfied then add some other code # that waits for the process to drop all resources that could be # needed by services started subsequently. A last resort is to # sleep for some time. start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON [ "$?" = 2 ] && return 2 # Many daemons don't delete their pidfiles when they exit. rm -f $PIDFILE return "$RETVAL" } # # Function that sends a SIGHUP to the daemon/service # do_reload() { # # If the daemon can reload its configuration without # restarting (for example, when it is sent a SIGHUP), # then implement that here. # start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME return 0 } case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; #reload|force-reload) # # If do_reload() is not implemented then leave this commented out # and leave 'force-reload' as an alias for 'restart'. # #log_daemon_msg "Reloading $DESC" "$NAME" #do_reload #log_end_msg $? #;; restart|force-reload) # # If the "reload" option is implemented then remove the # 'force-reload' alias # log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 exit 3 ;; esac : 0707010000001C000081A4000028240000003200000001607BF44800000B62000000000000000000000000000000000000004200000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/vcontrold.xml<?xml version="1.0"?> <V-Control xmlns:vcontrol="http://www.openv.de/vcontrol"> <unix> <config> <serial> <tty>192.168.1.112:3000</tty> </serial> <net> <port>3002</port> </net> <logging> <file>/tmp/vcontrold.log</file> <syslog>n</syslog> <debug>y</debug> </logging> <device ID="2098"/> </config> </unix> <units> <unit name='Temperatur'> <abbrev>UT</abbrev> <calc get='V/10' set='V*10'/> <type>short</type> <entity>Grad Celsius</entity> </unit> <unit name='Status'> <abbrev>ST</abbrev> <calc get='V' set='V'/> <type>char</type> <entity></entity> </unit> <unit name='Counter'> <abbrev>CO</abbrev> <calc get='V' set='V'/> <type>int</type> <entity></entity> </unit> <unit name='Prozent'> <abbrev>PR</abbrev> <calc get='V/2' set='V*2'/> <type>short</type> <entity>%</entity> </unit> <unit name='CounterS'> <abbrev>CS</abbrev> <calc get='V/3600' set='V*3600'/> <type>int</type> <entity>Stunden</entity> </unit> <unit name='CycleTime'> <abbrev>CT</abbrev> <type>cycletime</type> </unit> <unit name='ReturnStatus'> <abbrev>RT</abbrev> <type>enum</type> <enum bytes='00' text='0'/> <enum bytes='01' text='1'/> <enum text='NOT OK'/> </unit> <unit name='BetriebsArt'> <abbrev>BA</abbrev> <type>enum</type> <enum bytes='00' text='AUS'/> <enum bytes='01' text='WW'/> <enum bytes='02' text='H+WW'/> <enum bytes='03' text='RED'/> <enum bytes='04' text='NORM'/> <enum text='UNKNOWN'/> </unit> <unit name='SetReturnStatus'> <abbrev>SR</abbrev> <type>enum</type> <enum bytes='00' text='OK'/> <enum bytes='05' text='SYNC (NOT OK)'/> <enum text='NOT OK'/> </unit> </units> <protocols> <protocol name='KW2'> <macros> <macro name='SYNC'> <command>SEND 04;WAIT 05</command> </macro> <macro name='GETADDR'> <command>SEND 01 F7</command> </macro> <macro name='SETADDR'> <command>SEND 01 F4</command> </macro> </macros> <commands> <command name="getaddr"> <send>SYNC;GETADDR $addr $len;RECV $len $unit</send> </command> <command name="setaddr"> <send>SYNC;SETADDR $addr $len;SEND BYTES $unit;RECV 1 SR</send> </command> </commands> </protocol> <protocol name='GWG'> <macros> <macro name='SYNC'> <command>SEND 04;WAIT 05</command> </macro> <macro name='GETADDR'> <command>SEND 01 CB</command> </macro> </macros> <commands> <command name="getaddr"> <send>SYNC;GETADDR $addr $len;RECV $len $unit</send> </command> <command name="setaddr"> <send>SYNC;RECV 1</send> </command> </commands> </protocol> </protocols> <extern xmlns:xi="http://www.w3.org/2003/XInclude"> <xi:include href="vito.xml" parse="xml"/> </extern> </V-Control> 0707010000001D000081A4000028240000003200000001607BF448000000C3000000000000000000000000000000000000003F00000000vcontrold-v0.98.10+git20210418.977e6f5/doc/examples/vupdate.sh#/bin/sh # RDD Update V200KW2 # solarix@pingos.de # /root/vitotools/vclient -h 192.168.1.153:3002 -f /root/vitotools/rrd.min.cmds -t /root/vitotools/rrd.tmpl -x /root/vitotools/rrd.sh exit 0707010000001E000041ED000028240000003200000002607BF44800000000000000000000000000000000000000000000002F00000000vcontrold-v0.98.10+git20210418.977e6f5/doc/man0707010000001F000081A4000028240000003200000001607BF448000003F5000000000000000000000000000000000000003E00000000vcontrold-v0.98.10+git20210418.977e6f5/doc/man/CMakeLists.txt# Generate classic *roff manual pages from ReStructuredText. # This requires Python's Docutils (http://docutils.sourceforge.net/) cmake_minimum_required(VERSION 3.2.0) set(RST2MAN_OPTS) set(MANUALS vcontrold) if(VCLIENT) list(APPEND MANUALS vclient) endif(VCLIENT) if(VSIM) list(APPEND MANUALS vsim) endif(VSIM) foreach(MANUAL IN LISTS MANUALS) set(MANPAGE_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${MANUAL}.1) set(MANPAGE_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/${MANUAL}.rst) add_custom_command(OUTPUT ${MANPAGE_OUTPUT} COMMAND ${RST2MAN} ${RST2MAN_OPTS} ${MANPAGE_SOURCE} ${MANPAGE_OUTPUT} DEPENDS ${MANPAGE_SOURCE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Converting ${MANUAL}.rst from ReStructuredText into manpage ${MANUAL}.1" VERBATIM ) list(APPEND MANPAGES_LIST ${MANPAGE_OUTPUT}) endforeach() add_custom_target(man ALL DEPENDS ${MANPAGES_LIST}) install(FILES ${MANPAGES_LIST} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1) 07070100000020000081A4000028240000003200000001607BF44800001027000000000000000000000000000000000000003B00000000vcontrold-v0.98.10+git20210418.977e6f5/doc/man/vclient.rst========= vclient ========= -------------------------------------- tool for getting values from vcontrold -------------------------------------- :Author: Frank Nobis fn@radio-do.de, other contributors see `vcontrold @GitHub <https://github.com/openv/vcontrold>`__ :Copyright: GPLv3 :Manual section: 1 SYNOPSIS ======== vclient [-h <ip:port>] [-c <command1,command2,...>] [-f <commandfile>] [-s <csv-file>] [-t <template-file>] [-o <outputfile>] [-x <executablescript>] [-k] [-m] [-v] [-j] [-J] DESCRIPTION =========== vclient is the client program to communicate with the vcontrold daemon. It features a template mode to prepare received data for logging or database input. OPTIONS ======= -h, \--host <IPv4:port> or <IPv6> of vcontrold. Defaults to localhost -p, \--port <port> of vcontrold when using IPv6. Defaults to 3002 -c, \--command <commandlist> comma-separated list of commands -f, \-commandfile <commandfile> optional file with commands, one command per line -s, \--csvfile output results in CSV format -t, \--template <templatefile> template file, variables get replaced by returned values -o, \--output <outputfile> redirect stdout into <outputfile> -x, \--execute <scriptfile> write template output to <scriptfile>, then run the generated <scriptfile> -m, \--munin Munin datalogger compatible output, omits units and error details -k, \--cacti Cacti datalogger compatible output, omits units and error details -j, \--json-short JSON output short format (obeject with cmd as key and result as value) -J, \--json-long JSON output long (list with objects per command, contains cmd, raw, value and error) -v, \--verbose verbose mode -V, \--Version print version info, then exit -4, \--inet4 IPv4 preferred -6, \--inet6 IPv6 preferred. If no option provided, us OS defaults. \--help usage information TEMPLATE MODE ============= In template mode, variables contained in the <templatefile> get replaced with the values returned by a command issued in vclient. Variables $1, $2, ..., $n gets replaced with 1st, 2nd, ..., nth return value. The following variable types exist for conversion of return values: +------------+-----------------------------------+ | variable | function | +------------+-----------------------------------+ | $1..$n | return value converted to float | +------------+-----------------------------------+ | $R1..$Rn | return value converted to text | +------------+-----------------------------------+ | $C1..$Cn | issued command | +------------+-----------------------------------+ | $E1..$En | error message of command | +------------+-----------------------------------+ EXAMPLES ======== Preparation of a simple template for a database statement to insert some values in database: :: $ cat > sql.tmpl <<EOF INSERT INTO messwerte values (CURRENT_DATE,$1,$2); EOF Calling ``vclient`` with the given template shows the variables being replaced by their values: :: $ vclient -h 127.0.0.1:1234 -t sql.tmpl -c gettempA,gettempWW INSERT INTO messwerte values (CURRENT\_DATE,-2.600000,54.299999); These lines could be written directly into a database by piping the output to a DB cli: ``$ vclient -h 127.0.0.1:1234 -t sql.tmpl -c gettempA,gettempWW 2>/dev/null | mysql -D vito`` The -o <outputfile> option writes (overwrites, not appends) the output to the given file. With the option -x <scriptfile*, the generated output is treated like a script, which is run after output generation. Example: :: $ cat > sh-example.tmpl <<EOF #!/bin/sh DB=vitodb.rrd echo "command 1: $C1 ; command 2: $C2" echo "rrdtool update $DB N:$1:$2" EOF ``$ vclient -h 127.0.0.1:1234 -c getTempA,getTempWW -t sh-example.tmpl -x sh-example.sh`` Output: :: command 1: getTempA ; command 2: getTempWW rrdb update vitodb.rrd N:-2.600000:54.299999 SEE ALSO ======== * man 1 vcontrold * vcontrold @GitHub: `https://github.com/openv/vcontrold <https://github.com/openv/vcontrold>`__ 07070100000021000081A4000028240000003200000001607BF44800000CE7000000000000000000000000000000000000003D00000000vcontrold-v0.98.10+git20210418.977e6f5/doc/man/vcontrold.rst=========== vcontrold =========== ---------------------------------------------------------- Unix daemon for communication with Viessmann Vito heatings ---------------------------------------------------------- :Author: Frank Nobis fn@radio-do.de, other contributors see `vcontrold @GitHub <https://github.com/openv/vcontrold>`__ :Copyright: GPLv3 :Manual section: 1 SYNOPSIS ======== vcontrold [-x <xml-file>] [-d <device>] [-l <logfile>] [-p <port>] [-s] [-n] [-c <command-file>] [-P <pid-file>] [-U <username>] [-G <groupname>] [-i] [-g] [-4] [-6] [-v] [-V] [-?] DESCRIPTION =========== vcontrold uses a serial optical link or an IP connection to communicate with a Viessmann vito heating controller. OPTIONS ======= -x <xml-file>, \--xmlfile <xml-file> location of the main config file -d <device>, \--device <device> serial device to use. This option overrides corresponding entry in the config file. -l <logfile>, \--logfile <logfile> use <logfile> instead of syslog. -p <port>, \--port <port> TCP <port> to use for remote connections. The default is 3002 and can be specified in the config file. This option overrides the corresponding entry in the config file. -s, \--syslog use syslog -n, \--nodaemon do not fork. This is for testing purpose only. Normaly vcontrold will detach from the controlling terminal and put itself into the background. -c <command-file>, \--commandfile <command-file> file with lines containing sequences of icmds (WAIT, SEND, RECV, PAUSE) as used in protocol definitions. Lines get executed in order (developer option) -P <pid-file>, \--pidfile <pid-file> write process id to <pid-file> when started as a daemon. When started as root, <pid-file> is written prior to dropping privileges. This overrides the corresponding entry in the config file. -U <username>, \--username <username> when started by root, drop privileges to user <username> instead of user nobody. This overrides the corresponding entry in the config file. If using a serial link, ensure that user or group has access rights to the serial device. -G <groupname>, \--groupname <groupname> when started by root, drop privileges to group <groupname> instead of group dialout. This overrides the corresponding entry in the config file. If using a serial link, ensure that user or group has access rights to the serial device. -i, \--vsim use a temp file in ``/tmp/sim-devid.ini`` for use with the vsim simulator (developer option) -g, \--debug enable debug mode -4, --inet4 use IP v4 socket -6, --inet6 use IP v6 socket -v, \--verbose verbose mode -V, \--Version print version information, then exit -?, \--help usage information FILES ===== ``/etc/vcontrold/vcontrold.xml`` These are the programm specific configurations. E.g. device, baudrate, IP etc. ``/etc/vcontrold/vito.xml`` These are the command definitions for the devices in use. LICENSE ======= The vcontrold software, its accompanying files and documentation are licensed under the **GPLv3**. See COPYING in the package. SEE ALSO ======== * man 1 vclient * vcontrold @GitHub: `https://github.com/openv/vcontrold <https://github.com/openv/vcontrold>`__ 07070100000022000081A4000028240000003200000001607BF44800000296000000000000000000000000000000000000003800000000vcontrold-v0.98.10+git20210418.977e6f5/doc/man/vsim.rst====== vsim ====== ----------------------------- simulation tool for vcontrold ----------------------------- :Author: Frank Nobis fn@radio-do.de, other contributors see `vcontrold @GitHub <https://github.com/openv/vcontrold>`__ :Copyright: GPLv3 :Manual section: 1 DESCRIPTION =========== ``vsim`` is a simulation tool for the ``vcontrold`` daemon to simulate a connected Viessmann device. It is a simple developer tool, and features only a limited commandset which is not runtime configurable. SEE ALSO ======== * man 1 vcontrold * man 1 vclient * vcontrold @GitHub: `https://github.com/openv/vcontrold <https://github.com/openv/vcontrold>`__ 07070100000023000041ED000028240000003200000002607BF44800000000000000000000000000000000000000000000002B00000000vcontrold-v0.98.10+git20210418.977e6f5/src07070100000024000081A4000028240000003200000001607BF44800003C3A000000000000000000000000000000000000003800000000vcontrold-v0.98.10+git20210418.977e6f5/src/arithmetic.c/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ // Calculation of arithmetic expressions #include <stdlib.h> #include <stdio.h> #include <string.h> #include <ctype.h> #define HEX 8 #define HEXDIGIT 10 #define DIGIT 11 #define PUNKT 12 #define END 0 #define ERROR -100 #define PLUS 100 #define MINUS 101 #define MAL 102 #define GETEILT 103 #define MODULO 104 #define KAUF 110 #define KZU 111 #define BYTE0 200 #define BYTE1 201 #define BYTE2 202 #define BYTE3 203 #define BYTE4 204 #define BYTE5 205 #define BYTE6 206 #define BYTE7 207 #define BYTE8 208 #define BYTE9 209 #define PBYTE0 210 #define PBYTE1 211 #define PBYTE2 212 #define PBYTE3 213 #define PBYTE4 214 #define PBYTE5 215 #define PBYTE6 216 #define PBYTE7 217 #define PBYTE8 218 #define PBYTE9 219 #define BITPOS 220 #define VALUE 300 #define NICHT 400 #define UND 401 #define ODER 402 #define XOR 403 #define SHL 404 #define SHR 405 int nextToken(char **str, char **c, int *count); void pushBack(char **str, int n); float execExpression(char **str, unsigned char *bPtr, float floatV, char *err); float execTerm(char **str, unsigned char *bPtr, float floatV, char *err); float execFactor(char **str, unsigned char *bPtr, float floatV, char *err); int execIExpression(char **str, unsigned char *bPtr, char bitpos, char *pPtr, char *err); int execITerm(char **str, unsigned char *bPtr, char bitpos, char *pPtr, char *err); int execIFactor(char **str, unsigned char *bPtr, char bitpos, char *pPtr, char *err); float execExpression(char **str, unsigned char *bInPtr, float floatV, char *err) { int f = 1; float term1, term2; //float exp1,exp2; char *item; //unsigned char bPtr[10]; unsigned char bPtr[10]; int n; //printf("execExpression: %s\n",*str); // Tweak bPtr Bytes 0..9 and copy them to nPtr // We did not receive characters for (n = 0; n <= 9; n++) { //bPtr[n]=*bInPtr++ & 255; bPtr[n] = *bInPtr++; } switch (nextToken(str, &item, &n)) { case PLUS: f = 1; break; case MINUS: f = -1; break; default: pushBack(str, n); break; } term1 = execTerm(str, bPtr, floatV, err) * f; if (*err) { return 0; } //printf(" T1=%f\n",term1); int t; while ((t = nextToken(str, &item, &n)) != END) { f = 1; switch (t) { case PLUS: f = 1; break; case MINUS: f = -1; break; default: //printf(" Exp=%f\n",term1); pushBack(str, n); return term1; } term2 = execTerm(str, bPtr, floatV, err); if (*err) { return 0; } //printf(" T2=%f\n",term2); term1 += term2 * f; } //printf(" Exp=%f\n",term1); return term1; } float execTerm(char **str, unsigned char *bPtr, float floatV, char *err) { float factor1, factor2; int op; char *item; int n; //printf("execTerm: %s\n",*str); factor1 = execFactor(str, bPtr, floatV, err); if (*err) { return 0; } //printf(" F1=%f\n",factor1); while (1) { switch (nextToken(str, &item, &n)) { case MAL: op = MAL; break; case GETEILT: op = GETEILT; break; default: pushBack(str, n); //printf(" ret(%f)\n",factor1); return factor1; } factor2 = execFactor(str, bPtr, floatV, err); //printf(" F2=%f\n",factor2); if (*err) { return 0; } if (op == MAL) { factor1 *= factor2; } else { factor1 /= factor2; } } } float execFactor(char **str, unsigned char *bPtr, float floatV, char *err) { char nstring[100]; float expression; float factor; char *nPtr; char *item; char token; int n; //printf("execFactor: %s\n",*str); switch (nextToken(str, &item, &n)) { case BYTE0: return bPtr[0]; case BYTE1: return bPtr[1]; case BYTE2: return bPtr[2]; case BYTE3: return bPtr[3]; case BYTE4: return bPtr[4]; case BYTE5: return bPtr[5]; case BYTE6: return bPtr[6]; case BYTE7: return bPtr[7]; case BYTE8: return bPtr[8]; case BYTE9: return bPtr[9]; case VALUE: return floatV; case HEX: nPtr = nstring; memset(nstring, 0, sizeof(nstring)); strcpy(nstring, "0x"); nPtr += 2; token = nextToken(str, &item, &n); while ((token == DIGIT) || (token == HEXDIGIT)) { *nPtr++ = *item; token = nextToken(str, &item, &n); } pushBack(str, n); sscanf(nstring, "%f", &factor); return factor; case DIGIT: nPtr = nstring; do { *nPtr++ = *item; } while ((token = nextToken(str, &item, &n)) == DIGIT); // If a . follows, we have a decimal number if (token == PUNKT) { do { *nPtr++ = *item; } while ((token = nextToken(str, &item, &n)) == DIGIT); } pushBack(str, n); *nPtr = '\0'; factor = atof(nstring); //printf(" Zahl: %s (f:%f)\n",nstring,factor); return factor; case KAUF: expression = execExpression(str, bPtr, floatV, err); if (*err) { return 0; } if (nextToken(str, &item, &n) != KZU) { sprintf(err, "expected factor:) [%c]\n", *item); return 0; } return expression; default: sprintf(err, "expected factor: B0..B9 number ( ) [%c]\n", *item); return 0; } } int execIExpression(char **str, unsigned char *bInPtr, char bitpos, char *pPtr, char *err) { int f = 1; int term1, term2; //int exp1, exp2; int op; char *item; unsigned char bPtr[10]; int n; //printf("execExpression: %s\n", *str); // Tweak bPtr bytes 0..9 and copy them to nPtr // We have received characters for (n = 0; n <= 9; n++) { //bPtr[n]=*bInPtr++ & 255; bPtr[n] = *bInPtr++; } op = ERROR; switch (nextToken(str, &item, &n)) { case PLUS: op = PLUS; break; case MINUS: op = MINUS; break; case NICHT: op = NICHT; break; default: pushBack(str, n); break; } if (op == MINUS) { term1 = execITerm(str, bPtr, bitpos, pPtr, err) * -1; } else if (op == NICHT) { term1 = ~(execITerm(str, bPtr, bitpos, pPtr, err)); } else { term1 = execITerm(str, bPtr, bitpos, pPtr, err); } if (*err) { return 0; } int t; op = ERROR; while ((t = nextToken(str, &item, &n)) != END) { f = 1; switch (t) { case PLUS: op = PLUS; break; case MINUS: op = MINUS; break; case NICHT: op = NICHT; break; default: pushBack(str, n); return term1; } if (op == MINUS) { term2 = execITerm(str, bPtr, bitpos, pPtr, err) * -1; } else if (op == NICHT) { term2 = ~(execITerm(str, bPtr, bitpos, pPtr, err)); } else if (op == PLUS) { term2 = execITerm(str, bPtr, bitpos, pPtr, err); } if (*err) { return 0; } term1 += term2; } return term1; } int execITerm(char **str, unsigned char *bPtr, char bitpos, char *pPtr, char *err) { int factor1, factor2; int op; char *item; int n; //printf("execTerm: %s\n",*str); factor1 = execIFactor(str, bPtr, bitpos, pPtr, err); if (*err) { return 0; } while (1) { switch (nextToken(str, &item, &n)) { case MAL: op = MAL; break; case GETEILT: op = GETEILT; break; case MODULO: op = MODULO; break; case UND: op = UND; break; case ODER: op = ODER; break; case XOR: op = XOR; break; case SHL: op = SHL; break; case SHR: op = SHR; break; default: pushBack(str, n); //printf(" ret(%f)\n",factor1); return factor1; } factor2 = execIFactor(str, bPtr, bitpos, pPtr, err); if (*err) { return 0; } if (op == MAL) { factor1 *= factor2; } else if (op == GETEILT) { factor1 /= factor2; } else if (op == MODULO) { factor1 %= factor2; } else if (op == UND) { factor1 &= factor2; } else if (op == ODER) { factor1 |= factor2; } else if (op == XOR) { factor1 ^= factor2; } else if (op == SHL) { factor1 <<= factor2; } else if (op == SHR) { factor1 >>= factor2; } else { sprintf(err, "Error exec ITerm: Unknown token %d", op); return 0; } } } int execIFactor(char **str, unsigned char *bPtr, char bitpos, char *pPtr, char *err) { char nstring[100]; int expression; int factor; char *nPtr; char *item; char token; int n; //printf("execFactor: %s\n",*str); switch (nextToken(str, &item, &n)) { case BYTE0: return ((int)bPtr[0]) & 0xff; case BYTE1: return ((int)bPtr[1]) & 0xff; case BYTE2: return ((int)bPtr[2]) & 0xff; case BYTE3: return ((int)bPtr[3]) & 0xff; case BYTE4: return ((int)bPtr[4]) & 0xff; case BYTE5: return ((int)bPtr[5]) & 0xff; case BYTE6: return ((int)bPtr[6]) & 0xff; case BYTE7: return ((int)bPtr[7]) & 0xff; case BYTE8: return ((int)bPtr[8]) & 0xff; case BYTE9: return ((int)bPtr[9]) & 0xff; case BITPOS: return ((int)bitpos) & 0xff; case PBYTE0: return ((int)pPtr[0]) & 0xff; case PBYTE1: return ((int)pPtr[1]) & 0xff; case PBYTE2: return ((int)pPtr[2]) & 0xff; case PBYTE3: return ((int)pPtr[3]) & 0xff; case PBYTE4: return ((int)pPtr[4]) & 0xff; case PBYTE5: return ((int)pPtr[5]) & 0xff; case PBYTE6: return ((int)pPtr[6]) & 0xff; case PBYTE7: return ((int)pPtr[7]) & 0xff; case PBYTE8: return ((int)pPtr[8]) & 0xff; case PBYTE9: return ((int)pPtr[9]) & 0xff; case HEX: nPtr = nstring; memset(nstring, 0, sizeof(nstring)); strcpy(nstring, "0x"); nPtr += 2; token = nextToken(str, &item, &n); while ((token == DIGIT) || (token == HEXDIGIT)) { *nPtr++ = *item; token = nextToken(str, &item, &n); } pushBack(str, n); sscanf(nstring, "%i", &factor); return factor; case DIGIT: nPtr = nstring; do { *nPtr++ = *item; } while ((token = nextToken(str, &item, &n)) == DIGIT); // If a . follows, we have a decimal number if (token == PUNKT) { do { *nPtr++ = *item; } while ((token = nextToken(str, &item, &n)) == DIGIT); } pushBack(str, n); *nPtr = '\0'; factor = atof(nstring); return factor; case KAUF: expression = execIExpression(str, bPtr, bitpos, pPtr, err); if (*err) { return 0; } if (nextToken(str, &item, &n) != KZU) { sprintf(err, "expected factor:) [%c]\n", *item); return 0; } return expression; case NICHT: return ~execIFactor(str, bPtr, bitpos, pPtr, err); default: sprintf(err, "expected factor: B0..B9 P0..P9 BP number ( ) [%c]\n", *item); return 0; } } int nextToken(char **str, char **c, int *count) { char item; //printf("\tInput String:%s\n",*str); item = **str; while (isblank(item)) { item = *(++*str); } *c = *str; (*str)++; //printf("\t Token: %c [ %s ] \n",**c,*str); *count = 1; switch (**c) { case '+': return PLUS; case '-': return MINUS; case '*': return MAL; case '/': return GETEILT; case '%': return MODULO; case '(': return KAUF; case ')': return KZU; case 'V': return VALUE; case '^': return XOR; case '&': return UND; case '|': return ODER; case '~': return NICHT; case '0': if (*(*str) == 'x') { (*str)++; *count = 2; return HEX; } return DIGIT; case '<': *count = 2; switch (*(*str)++) { case '<' : return SHL; } case '>': *count = 2; switch (*(*str)++) { case '>': return SHR; } case 'B': *count = 2; switch (*(*str)++) { case '0': return BYTE0; case '1': return BYTE1; case '2': return BYTE2; case '3': return BYTE3; case '4': return BYTE4; case '5': return BYTE5; case '6': return BYTE6; case '7': return BYTE7; case '8': return BYTE8; case '9': return BYTE9; case 'P': return BITPOS; } case 'P': *count = 2; switch (*(*str)++) { case '0': return PBYTE0; case '1': return PBYTE1; case '2': return PBYTE2; case '3': return PBYTE3; case '4': return PBYTE4; case '5': return PBYTE5; case '6': return PBYTE6; case '7': return PBYTE7; case '8': return PBYTE8; case '9': return PBYTE9; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return DIGIT; case 'a': case 'b': case 'c': case 'd': case 'e' : case 'f': return HEXDIGIT; case '.': return PUNKT; case '\0': return END; default: return ERROR; } } void pushBack(char **str, int count) { (*str) -= count; //printf("\t<<::%s\n",*str); } 07070100000025000081A4000028240000003200000001607BF448000003D6000000000000000000000000000000000000003800000000vcontrold-v0.98.10+git20210418.977e6f5/src/arithmetic.h/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ // Calculation of arithmetic expressions #ifndef ARITHMETIC_H #define ARITHMETIC_H float execExpression(char **str, char *bPtr, float floatV, char *err); int execIExpression(char **str, char *bPtr, char bitpos, char *pPtr, char *err); #endif // ARITHMETIC_H 07070100000026000081A4000028240000003200000001607BF44800001B6C000000000000000000000000000000000000003400000000vcontrold-v0.98.10+git20210418.977e6f5/src/client.c/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ // Client routines for vcontrold queries #include <syslog.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <time.h> #include <setjmp.h> #include <signal.h> #include <unistd.h> #include <ctype.h> #include "client.h" #include "prompt.h" #include "common.h" #include "socket.h" static void sig_alrm(int); static jmp_buf env_alrm; int sendTrList(int sockfd, trPtr ptr); trPtr newTrNode(trPtr ptr) { trPtr nptr; if (ptr && ptr->next) { return newTrNode(ptr->next); } nptr = calloc(1, sizeof(*ptr)); if (! nptr) { fprintf(stderr, "malloc failed\n"); exit(1); } if (ptr) { ptr->next = nptr; } return nptr; } ssize_t recvSync(int fd, char *wait, char **recv) { char *rptr; char *pptr; char c; ssize_t count; int rcount = 1; if (signal(SIGALRM, sig_alrm) == SIG_ERR) { logIT1(LOG_ERR, "SIGALRM error"); } if (setjmp(env_alrm) != 0) { logIT(LOG_ERR, "timeout wait:%s", wait); return -1; } alarm(CL_TIMEOUT); if (! (*recv = calloc(ALLOCSIZE, sizeof(char)))) { logIT1(LOG_ERR, "calloc error"); exit(1); } rptr = *recv; size_t i = 0; while ((count = readn(fd, &c, 1))) { alarm(0); if (count < 0) { continue; } *rptr++ = c; *(rptr + 1) = '\0'; i++; if (! ((rptr - *recv + 1) % ALLOCSIZE)) { char *tmp = realloc(*recv, ALLOCSIZE * sizeof(char) * ++rcount); if (tmp == NULL) { logIT1(LOG_ERR, "realloc error"); exit(1); } else { *recv = tmp; rptr = *recv + i; } } if ((pptr = strstr(*recv, wait))) { *pptr = '\0'; logIT(LOG_INFO, "recv:%s", *recv); break; } alarm(CL_TIMEOUT); } char *tmp = realloc(*recv, strlen(*recv) + 1); if (tmp == NULL) { logIT1(LOG_ERR, "realloc error"); exit(1); } else { *recv = tmp; } if (count <= 0) { logIT(LOG_ERR, "exit with count=%ld", count);; } return count; } // port is never 0, which is a bad number for a tcp port int connectServer(char *host, int port) { int sockfd; if (host[0] != '/' ) { sockfd = openCliSocket(host, port, 0); if (sockfd) { logIT(LOG_INFO, "Setup connection to %s port %d", host, port); } else { logIT(LOG_INFO, "Setting up connection to %s port %d failed", host, port); return -1; } } else { logIT(LOG_ERR, "Host format: IP|Name:Port"); return -1; } return sockfd; } void disconnectServer(int sockfd) { char string[8]; char *ptr; snprintf(string, sizeof(string), "quit\n"); sendServer(sockfd, string, strlen(string)); recvSync(sockfd, BYE, &ptr); free(ptr); close(sockfd); } size_t sendServer(int fd, char *s_buf, size_t len) { char string[256]; // Empty buffer // As tcflush does not work correctly, we use nonblocking read fcntl(fd, F_SETFL, O_NONBLOCK); while (readn(fd, string, sizeof(string)) > 0) { } fcntl(fd, F_SETFL, ! O_NONBLOCK); return Writen(fd, s_buf, len); } trPtr sendCmdFile(int sockfd, const char *filename) { FILE *filePtr; char line[MAXBUF]; trPtr ptr; trPtr startPtr = NULL; if (! (filePtr = fopen(filename, "r"))) { return NULL; } else { logIT(LOG_INFO, "Opened command file %s", filename); } memset(line, 0, sizeof(line)); while (fgets(line, MAXBUF - 1, filePtr)) { ptr = newTrNode(startPtr); if (! startPtr) { startPtr = ptr; } ptr->cmd = calloc(strlen(line), sizeof(char)); strncpy(ptr->cmd, line, strlen(line) - 1); } if (! sendTrList(sockfd, startPtr)) { // Something with the communication went wrong return NULL; } return startPtr; } trPtr sendCmds(int sockfd, char *commands) { char *sptr; trPtr ptr; trPtr startPtr = NULL; sptr = strtok(commands, ","); do { ptr = newTrNode(startPtr); if (! startPtr) { startPtr = ptr; } ptr->cmd = calloc(strlen(sptr) + 1, sizeof(char)); strncpy(ptr->cmd, sptr, strlen(sptr)); } while ((sptr = strtok(NULL, ",")) != NULL); if (! sendTrList(sockfd, startPtr)) { // Something with the communication went wrong return NULL; } return startPtr; } int sendTrList(int sockfd, trPtr ptr) { char string[1000 + 1]; char prompt[] = PROMPT; char errTXT[] = ERR; char *sptr; char *dumPtr; if (recvSync(sockfd, prompt, &sptr) <= 0) { free(sptr); return 0; } while (ptr) { //memset(string, 0,sizeof(string)); snprintf(string, sizeof(string), "%s\n", ptr->cmd); if (sendServer(sockfd, string, strlen(string)) <= 0) { return 0; } //memset(string, 0,sizeof(string)); logIT(LOG_INFO, "SEND:%s", ptr->cmd); if (recvSync(sockfd, prompt, &sptr) <= 0) { free(sptr); return 0; } ptr->raw = sptr; if (iscntrl(*(ptr->raw + strlen(ptr->raw) - 1))) { *(ptr->raw + strlen(ptr->raw) - 1) = '\0'; } dumPtr = calloc(strlen(sptr) + 20, sizeof(char)); snprintf(dumPtr, (strlen(sptr) + 20) * sizeof(char), "RECV:%s", sptr); logIT1(LOG_INFO, dumPtr); free(dumPtr); // We fill errors and result if (strstr(ptr->raw, errTXT) == ptr->raw) { ptr->err = ptr->raw; fprintf(stderr, "SRV %s\n", ptr->err); } else { // Here, we search the first word in raw and save it as result char *rptr; char len; rptr = strchr(ptr->raw, ' '); if (! rptr) { rptr = ptr->raw + strlen(ptr->raw); } len = rptr - ptr->raw; ptr->result = atof(ptr->raw); ptr->err = NULL; } ptr = ptr->next; } return 1; } static void sig_alrm(int signo) { longjmp(env_alrm, 1); } 07070100000027000081A4000028240000003200000001607BF4480000050D000000000000000000000000000000000000003400000000vcontrold-v0.98.10+git20210418.977e6f5/src/client.h/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ #ifndef CLIENT_H #define CLIENT_H #define CL_TIMEOUT 25 #ifndef MAXBUF #define MAXBUF 4096 #endif #define ALLOCSIZE 256 typedef struct txRx *trPtr; ssize_t recvSync(int fd, char *wait, char **recv); int connectServer(char *host, int port); void disconnectServer(int sockfd); size_t sendServer(int fd, char *s_buf, size_t len); trPtr sendCmdFile(int sockfd, const char *tmpfile); trPtr sendCmds(int sockfd, char *commands); struct txRx { char *cmd; float result; char *err; char *raw; time_t timestamp; trPtr next; } TxRx; #endif // CLIENT_H 07070100000028000081A4000028240000003200000001607BF44800001248000000000000000000000000000000000000003400000000vcontrold-v0.98.10+git20210418.977e6f5/src/common.c/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ // Common functions for vcontrold like logging and converting #define _GNU_SOURCE #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <syslog.h> #include <unistd.h> #include <string.h> #include <time.h> #include <ctype.h> #include <stdarg.h> #include "common.h" int syslogger = 0; int debug = 0; FILE *logFD; char errMsg[2000]; int errClass = 99; int dbgFD = -1; int initLog(int useSyslog, char *logfile, int debugSwitch) { // If needed, opes the syslog or log file if (useSyslog) { syslogger = 1; openlog("vito", LOG_PID, LOG_LOCAL0); syslog(LOG_LOCAL0, "vito started"); } if (logfile) { // Log file is not NULL and not empty if (strcmp(logfile, "") == 0) { return 0; } logFD = fopen(logfile, "a"); if (! logFD) { printf("Could not open %s: %s", logfile, strerror (errno)); return 0 ; } } debug = debugSwitch; memset(errMsg, 0, sizeof(errMsg)); return 1; } void logIT (int class, char *string, ...) { va_list arguments; time_t t; char *tPtr; char *cPtr; time(&t); tPtr = ctime(&t); char *print_buffer; int pid; long avail; va_start(arguments, string); vasprintf(&print_buffer, string, arguments); va_end(arguments); if (class <= LOG_ERR) { avail = sizeof(errMsg) - strlen(errMsg) - 2; if ( avail > 0 ) { strncat(errMsg, print_buffer, avail); strcat(errMsg, "\n"); } else { strcpy(&errMsg[sizeof(errMsg) - 12], "OVERFLOW\n"); // Should solve the semop error } } errClass = class; // Remove control characters cPtr = tPtr; while (*cPtr) { if (iscntrl(*cPtr)) { *cPtr = ' '; } cPtr++; } if (dbgFD >= 0) { // The debug FD is set and we firstly send the info there dprintf(dbgFD, "DEBUG:%s: %s\n", tPtr, print_buffer); } if (! debug && (class > LOG_NOTICE)) { free(print_buffer); return; } pid = getpid(); if (syslogger) { syslog(class, "%s", print_buffer); } if (logFD) { fprintf(logFD, "[%d] %s: %s\n", pid, tPtr, print_buffer); fflush(logFD); } // Output only if 2 is open as STDERR if (isatty(2)) { fprintf(stderr, "[%d] %s: %s\n", pid, tPtr, print_buffer); } free(print_buffer); } void sendErrMsg(int fd) { char string[256]; if ((fd >= 0) && (errClass <= 3)) { snprintf(string, sizeof(string), "ERR: %s", errMsg); write(fd, string, strlen(string)); errClass = 99; // Thus it's only displayed once memset(errMsg, 0, sizeof(errMsg)); } *errMsg = '\0'; // Back to start, no matter if we actually output // Can be commented out for debugging, then we get the errors in errMsg } void setDebugFD(int fd) { dbgFD = fd; } char hex2chr(char *hex) { char buffer[16]; int hex_value = -1; snprintf(buffer, sizeof(buffer), "0x%s", hex); if (sscanf(hex, "%x", &hex_value) != 1) { logIT(LOG_WARNING, "Invalid hex char in %s", hex); } return hex_value; } int char2hex(char *outString, const char *charPtr, int len) { int n; char string[MAXBUF]; memset(string, 0, sizeof(string)); for (n = 0; n < len; n++) { unsigned char byte = *charPtr++ & 255; snprintf(string, sizeof(string), "%02X ", byte); strcat(outString, string); } // Remove last space outString[strlen(outString) - 1] = '\0'; return len; } short string2chr(char *line, char *buf, short bufsize) { char *sptr; short count; count = 0; sptr = strtok(line, " "); do { if (*sptr == ' ') { continue; } buf[count++] = hex2chr(sptr); } while ((sptr = strtok(NULL, " ")) && (count < bufsize)); return count; } 07070100000029000081A4000028240000003200000001607BF448000004F8000000000000000000000000000000000000003400000000vcontrold-v0.98.10+git20210418.977e6f5/src/common.h/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ #ifndef COMMON_H #define COMMON_H int initLog(int useSyslog, char *logfile, int debugSwitch); void logIT (int class, char *string, ...); char hex2chr(char *hex); int char2hex(char *outString, const char *charPtr, int len); short string2chr(char *line, char *buf, short bufsize); void sendErrMsg(int fd); void setDebugFD(int fd); ssize_t readn(int fd, void *vptr, size_t n); #ifndef MAXBUF #define MAXBUF 4096 #endif #ifndef DEFAULT_PORT #define DEFAULT_PORT 3002 #endif #define logIT1(class, string) logIT(class, "%s", string) #endif // COMMON_H 0707010000002A000081A4000028240000003200000001607BF44800004A5E000000000000000000000000000000000000003400000000vcontrold-v0.98.10+git20210418.977e6f5/src/framer.c/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ /* * Framer interface * * For P300 framing is supported here * * Control is by a controlling byte P300_LEADING = 0x41 * * with open and close P300 Mode is switched on, there is new xml-tag <pid> with protocol * definition which controls the switching of vitotronic to P300 mode. * additional assuming PDUs start by P300_LEADIN, else transferred as send by client * TODO: when PID is set, there is no need for defining a controlling x41 in getaddr etc. * * semaphore handling in vcontrol.c is changed to cover all from open until close to avoid * disturbance by other client trying to do uncoordinated open/close * * 2013-01-31 vheat */ #include <stdlib.h> #include <stdio.h> #include <syslog.h> #include <unistd.h> #include <string.h> #include <time.h> #include <ctype.h> #include "common.h" #include "io.h" #include "framer.h" typedef unsigned short int uint16; // general marker of P300 protocol #define P300_LEADIN 0x41 #define P300_RESET 0x04 #define P300_ENABLE { 0x16, 0x00, 0x00 } // message type #define P300_REQUEST 0x00 #define P300_RESPONSE 0x01 #define P300_ERROR_REPORT 0x03 #define P300X_LINK_MNT 0x0f // function #define P300_READ_DATA 0x01 #define P300_WRITE_DATA 0x02 #define P300_FUNCT_CALL 0x07 #define P300X_OPEN 0x01 #define P300X_CLOSE 0x00 #define P300X_ATTEMPTS 3 // response #define P300_ERROR 0x15 #define P300_NOT_INIT 0x05 #define P300_INIT_OK 0x06 // message buffer structure #define P300_LEADIN_OFFSET 0 #define P300_LEN_OFFSET 1 #define P300_TYPE_OFFSET 2 #define P300_FCT_OFFSET 3 #define P300_ADDR_OFFSET 4 #define P300_RESP_LEN_OFFSET 6 #define P300_BUFFER_OFFSET 7 #define P300_LEADIN_LEN 1 #define P300_LEN_LEN 1 #define P300_CRC_LEN 1 #define P300_EXTRA_BYTES (P300_LEADIN_LEN + P300_LEN_LEN + P300_CRC_LEN) #define FRAMER_READ_ERROR (-1) #define FRAMER_LINK_STATUS(st) (0xFE00 + st) #define FRAMER_READ_TIMEOUT 0 #define FRAMER_NO_ADDR ((uint16) (-1)) // current active command static uint16 framer_current_addr = FRAMER_NO_ADDR; // stored value depends on Endianess // current active protocol static char framer_pid = 0; // status handling of current command static void framer_set_actaddr(void *pdu) { char string[100]; uint16 framer_old_addr; if (framer_current_addr != FRAMER_NO_ADDR) { snprintf(string, sizeof(string), ">FRAMER: addr was still active %04X", framer_current_addr); logIT(LOG_ERR, string); } framer_old_addr = framer_current_addr; framer_current_addr = *(uint16 *) (((char *) pdu) + P300_ADDR_OFFSET); snprintf(string, sizeof(string), ">FRAMER: framer_set_actaddr framer_current_addr = %04X (was %04X)", framer_current_addr, framer_old_addr); logIT(LOG_DEBUG, string); } static void framer_reset_actaddr(void) { char string[100]; snprintf(string, sizeof(string), ">FRAMER: framer_reset_actaddr framer_current_addr = FRAMER_NO_ADDR (was %04X)", framer_current_addr); logIT(LOG_DEBUG, string); framer_current_addr = FRAMER_NO_ADDR; } static int framer_check_actaddr(void *pdu) { char string[100]; if (framer_current_addr != *(uint16 *) (((char *) pdu) + P300_ADDR_OFFSET)) { snprintf(string, sizeof(string), ">FRAMER: addr corrupted stored %04X, now %04X", framer_current_addr, *(uint16 *) (((char *) pdu) + P300_ADDR_OFFSET)); logIT(LOG_ERR, string); return -1; } return 0; } // TODO: could cause trouble on addr containing 0xFE static void framer_set_result(char result) { char string[100]; snprintf(string, sizeof(string), ">FRAMER: framer_reset_actaddr framer_current_addr = FRAMER_LINK_STATUS(%02X) (was %04X)", result, framer_current_addr); logIT(LOG_DEBUG, string); framer_current_addr = FRAMER_LINK_STATUS(result); } static int framer_preset_result(char *r_buf, int r_len, unsigned long *petime) { char string[100]; if ((framer_pid == P300_LEADIN) && ((framer_current_addr & FRAMER_LINK_STATUS(0)) == FRAMER_LINK_STATUS(0))) { r_buf[0] = (char) (framer_current_addr ^ FRAMER_LINK_STATUS(0)); snprintf(string, sizeof(string), ">FRAMER: preset result %02X", r_buf[0]); logIT(LOG_INFO, string); return FRAMER_SUCCESS; } snprintf(string, sizeof(string), ">FRAMER: no preset result"); logIT(LOG_INFO, string); return FRAMER_ERROR; } // Synchronization for P300 + switch to P300, back to normal for close -> repeating P300X_ATTEMPTS static int framer_close_p300(int fd) { char string[100]; int i; char wbuf = P300_RESET; char rbuf = 0; unsigned long etime; int rlen; for (i = 0; i < P300X_ATTEMPTS; i++) { if (! my_send(fd, &wbuf, 1)) { framer_set_result(P300_ERROR); snprintf(string, sizeof(string), ">FRAMER: reset not send"); logIT(LOG_ERR, string); return FRAMER_ERROR; } etime = 0; rlen = receive_nb(fd, &rbuf, 1, &etime); if (rlen < 0) { framer_set_result(P300_ERROR); snprintf(string, sizeof(string), ">FRAMER: close read failure for ack"); logIT(LOG_ERR, string); return FRAMER_ERROR; } else if (rlen == 0) { framer_set_result(P300_ERROR); snprintf(string, sizeof(string), ">FRAMER: close read timeout for ack"); logIT(LOG_ERR, string); return FRAMER_ERROR; } else if ((rbuf == P300_INIT_OK) || (rbuf == P300_NOT_INIT)) { framer_set_result(P300_NOT_INIT); snprintf(string, sizeof(string), ">FRAMER: closed"); logIT(LOG_INFO, string); return FRAMER_SUCCESS; } else { snprintf(string, sizeof(string), ">FRAMER: unexpected data 0x%02X", rbuf); logIT(LOG_ERR, string); // continue anyway } } framer_set_result(P300_ERROR); snprintf(string, sizeof(string), ">FRAMER: could not close (%d attempts)", P300X_ATTEMPTS); logIT(LOG_ERR, string); return FRAMER_ERROR; } static int framer_open_p300(int fd) { char string[100]; int i; char rbuf = 0; char enable[] = P300_ENABLE; unsigned long etime; int rlen; for (i = 0; i < P300X_ATTEMPTS; i++) { if (! framer_close_p300(fd)) { snprintf(string, sizeof(string), ">FRAMER: could not set start condition"); logIT(LOG_ERR, string); return FRAMER_ERROR; } if (! my_send(fd, enable, sizeof(enable))) { framer_set_result(P300_ERROR); snprintf(string, sizeof(string), ">FRAMER: enable not send"); logIT(LOG_ERR, string); return FRAMER_ERROR; } etime = 0; rlen = receive_nb(fd, &rbuf, 1, &etime); if (rlen < 0) { framer_set_result(P300_ERROR); snprintf(string, sizeof(string), ">FRAMER: enable read failure for ack"); logIT(LOG_ERR, string); return FRAMER_ERROR; } else if (rlen == 0) { framer_set_result(P300_ERROR); snprintf(string, sizeof(string), ">FRAMER: enable read timeout for ack"); logIT(LOG_ERR, string); return FRAMER_ERROR; } else if (rbuf == P300_INIT_OK) { // hmueller: Replaced framer_set_result(P300_INIT_OK) // by framer_reset_actaddr() to avoid error log // >FRAMER: addr was still active FE06 framer_reset_actaddr(); snprintf(string, sizeof(string), ">FRAMER: opened"); logIT(LOG_INFO, string); return FRAMER_SUCCESS; } } framer_set_result(P300_ERROR); snprintf(string, sizeof(string), ">FRAMER: could not close (%d attempts)", P300X_ATTEMPTS); logIT(LOG_ERR, string); return FRAMER_ERROR; } // calculation check sum for P300, assuming buffer is frame and starts by P300_LEADIN static char framer_chksum(char *buf, int len) { char sum = 0; while (len) { sum += *buf; //printf("framer chksum %d %02X %02X\n", len, *buf, sum); buf++; len--; } //printf("framer chksum %02x\n", sum); return sum; } /* * Frame a message in case P300 protocol is indicated * * Return 0: Error, else length of written bytes * This routine reads the first response byte for success status * * Format * Downlink * to framer * | type | function | addr | exp len | * to Vitotronic * | LEADIN | payload len | type | function | addr | exp len | chk | */ int framer_send(int fd, char *s_buf, int len) { char string[256]; if ((len < 1) || (! s_buf)) { snprintf(string, sizeof(string), ">FRAMER: invalid buffer %d %p", len, s_buf); logIT(LOG_ERR, string); return FRAMER_ERROR; } if (framer_pid != P300_LEADIN) { return my_send(fd, s_buf, len); } else if (len < 3) { snprintf(string, sizeof(string), ">FRAMER: too few for P300"); logIT(LOG_ERR, string); return FRAMER_ERROR; } else { int pos = 0; char l_buf[256]; unsigned long etime; int rlen; // prepare a new message, fill buffer starting with leadin l_buf[P300_LEADIN_OFFSET] = P300_LEADIN; l_buf[P300_LEN_OFFSET] = len; // only payload but len may contain other bytes memcpy(&l_buf[P300_TYPE_OFFSET], s_buf, len); l_buf[P300_LEADIN_LEN + P300_LEN_LEN + len] = framer_chksum(l_buf + P300_LEADIN_LEN, len + P300_LEN_LEN); if (! my_send(fd, l_buf, len + P300_EXTRA_BYTES)) { snprintf(string, sizeof(string), ">FRAMER: write failure %d", len + P300_EXTRA_BYTES); logIT(LOG_ERR, string); return FRAMER_ERROR; } etime = 0; rlen = receive_nb(fd, l_buf, 1, &etime); if (rlen < 0) { snprintf(string, sizeof(string), ">FRAMER: read failure %d", pos + 1); logIT(LOG_ERR, string); return FRAMER_ERROR; } else if (rlen == 0) { snprintf(string, sizeof(string), ">FRAMER: timeout for ack %d", pos + 1); logIT(LOG_ERR, string); return FRAMER_ERROR; } else if (*l_buf != P300_INIT_OK) { snprintf(string, sizeof(string), ">FRAMER: Error 0x%02X != 0x%02X (P300_INIT_OK)", *l_buf, P300_INIT_OK); logIT(LOG_ERR, string); return FRAMER_ERROR; } framer_set_actaddr(l_buf); snprintf(string, sizeof(string), ">FRAMER: Command send"); logIT(LOG_INFO, string); return FRAMER_SUCCESS; } } /* * Read a framed message in case P300 protocol is indicated * * Return 0: Error, else length of written bytes * This routine reads the first response byte for success status * * Format * from Vitotronic * | LEADIN | payload len | type | function | addr | exp len | chk | * Uplink * from framer * | data | * This simulates KW return, respective checking of the frame is done in this function * * etime is forwarded * return is FRAMER_ERROR, FRAMER_TIMEOUT or read len * * WEAKNESS: * If any other protocol gets an answer beginning 0x41, then this will return erroneous * KW may have values returned starting 0x41 */ int framer_receive(int fd, char *r_buf, int r_len, unsigned long *petime) { char string[256]; int rlen; int total; int rtmp; char l_buf[256]; unsigned long etime; char chk; // to identify TimerWWMi bug l_buf[P300_ADDR_OFFSET] = 0; l_buf[P300_ADDR_OFFSET + 1] = 0; if ((r_len < 1) || (! r_buf)) { snprintf(string, sizeof(string), ">FRAMER: invalid read buffer %d %p", r_len, r_buf); logIT(LOG_ERR, string); return FRAMER_ERROR; } if (framer_preset_result(r_buf, r_len, petime)) { framer_reset_actaddr(); return FRAMER_SUCCESS; } *petime = 0; rtmp = receive_nb(fd, l_buf, r_len, petime); if (rtmp < 0) { framer_reset_actaddr(); snprintf(string, sizeof(string), ">FRAMER: read failure"); logIT(LOG_ERR, string); return FRAMER_READ_ERROR; } else if (rtmp == 0) { framer_reset_actaddr(); snprintf(string, sizeof(string), ">FRAMER: read timeout"); logIT(LOG_ERR, string); return FRAMER_READ_TIMEOUT; } else if (framer_pid != P300_LEADIN) { // no P300 frame, just forward memcpy(r_buf, l_buf, r_len); return rtmp; } // this is not GWG / KW we know now etime = 0; // read at least the length info if (rtmp < 2) { rlen = receive_nb(fd, l_buf + 1, 1, &etime); *petime += etime; if (rlen < 0) { framer_reset_actaddr(); snprintf(string, sizeof(string), ">FRAMER: read failure"); logIT(LOG_ERR, string); return FRAMER_READ_ERROR; } else if (rlen == 0) { framer_reset_actaddr(); snprintf(string, sizeof(string), ">FRAMER: read timeout"); logIT(LOG_ERR, string); return FRAMER_READ_TIMEOUT; } rtmp += rlen; } total = l_buf[P300_LEN_OFFSET] + P300_EXTRA_BYTES; rlen = total - rtmp; if (rlen <= 0) { framer_reset_actaddr(); snprintf(string, sizeof(string), ">FRAMER: strange read %d", rlen); logIT(LOG_ERR, string); return rtmp; // strange should not happen here } // now read what is extra rtmp = receive_nb(fd, l_buf + rtmp, rlen, &etime); *petime += etime; // check for leadin if (l_buf[P300_LEADIN_OFFSET] != P300_LEADIN) { framer_reset_actaddr(); snprintf(string, sizeof(string), ">FRAMER: read leadin error received 0x%02X expected 0x%02X", l_buf[P300_LEADIN_OFFSET], P300_LEADIN); logIT(LOG_ERR, string); return FRAMER_READ_ERROR; } // bug in Vitotronic getTimerWWMi, we got it, but complete if ((l_buf[P300_ADDR_OFFSET] == 0x21) && (l_buf[P300_ADDR_OFFSET + 1] == 0x10) && (rtmp == -1)) { snprintf(string, sizeof(string), ">FRAMER: bug of getTimerWWMi - omit checksum"); logIT(LOG_ERR, string); } else { if (rtmp < 0) { framer_reset_actaddr(); snprintf(string, sizeof(string), ">FRAMER: read final failure"); logIT(LOG_ERR, string); return FRAMER_READ_ERROR; } else if (rtmp == 0) { framer_reset_actaddr(); snprintf(string, sizeof(string), ">FRAMER: read final timeout"); logIT(LOG_ERR, string); return FRAMER_READ_TIMEOUT; } chk = framer_chksum(l_buf + P300_LEADIN_LEN, total - 2); if (l_buf[total - 1] != chk) { framer_reset_actaddr(); snprintf(string, sizeof(string), ">FRAMER: read chksum error received 0x%02X calc 0x%02X", (unsigned char)l_buf[total - 1], (unsigned char)chk); logIT(LOG_ERR, string); return FRAMER_READ_ERROR; } } if (l_buf[P300_TYPE_OFFSET] == P300_ERROR_REPORT) { framer_reset_actaddr(); snprintf(string, sizeof(string), ">FRAMER: ERROR address %02X%02X code %d", l_buf[P300_ADDR_OFFSET], l_buf[P300_ADDR_OFFSET + 1], l_buf[P300_BUFFER_OFFSET]); logIT(LOG_ERR, string); return FRAMER_READ_ERROR; } // TODO: could add check for address receive matching address send before if (framer_check_actaddr(l_buf)) { framer_reset_actaddr(); snprintf(string, sizeof(string), ">FRAMER: not matching response addr"); logIT(LOG_ERR, string); return FRAMER_READ_ERROR; } if ((l_buf[P300_FCT_OFFSET] == P300_WRITE_DATA) && (r_len == 1)) { // TODO: could add check for length matching previously requested data length if (r_len != (l_buf[P300_LEN_OFFSET] - 4)) { snprintf(string, sizeof(string), ">FRAMER: unexpected length r_len=0x%02X != 0x%02X=l_buf[P300_LEN_OFFSET]-4", r_len, l_buf[P300_LEN_OFFSET] - 4); logIT(LOG_ERR, string); framer_reset_actaddr(); return FRAMER_READ_ERROR; } // if we have a P300 setaddr we do not get data back ... if (l_buf[P300_TYPE_OFFSET] == P300_RESPONSE) { // OK r_buf[rtmp] = 0x00; } else { // NOT OK r_buf[rtmp] = 0x01; } } else { if (r_len != (l_buf[P300_RESP_LEN_OFFSET])) { snprintf(string, sizeof(string), ">FRAMER: unexpected length r_len=0x%02X != 0x%02X=l_buf[P300_RESP_LEN_OFFSET]", r_len, l_buf[P300_RESP_LEN_OFFSET]); logIT(LOG_ERR, string); framer_reset_actaddr(); return FRAMER_READ_ERROR; } memcpy(r_buf, &l_buf[P300_BUFFER_OFFSET], r_len); } framer_reset_actaddr(); return r_len; } int framer_waitfor(int fd, char *w_buf, int w_len) { unsigned long etime; if (framer_preset_result(w_buf, w_len, &etime)) { framer_reset_actaddr(); return FRAMER_SUCCESS; } return waitfor(fd, w_buf, w_len); } // Device handling, with open and close the mode is also switched to P300/back int framer_openDevice(char *device, char pid) { char string[100]; int fd; snprintf(string, sizeof(string), ">FRAMER: open device %s ProtocolID %02X", device, pid); logIT(LOG_INFO, string); if ((fd = openDevice(device)) == -1) { return -1; } if (pid == P300_LEADIN) { if (! framer_open_p300(fd)) { closeDevice(fd); return -1; } } framer_pid = pid; return fd; } void framer_closeDevice(int fd) { if (framer_pid == P300_LEADIN) { framer_close_p300(fd); } framer_pid = 0; closeDevice(fd); } 0707010000002B000081A4000028240000003200000001607BF44800000518000000000000000000000000000000000000003400000000vcontrold-v0.98.10+git20210418.977e6f5/src/framer.h/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ /* * Framer interface * * For P300 framing is supported here * * Control is by a controlling byte defining the action * * 2013-01-31 vheat */ /* * Main indentification of P300 Protocol is about leadin 0x41 */ #ifndef FRAMER_H #define FRAMER_H #define FRAMER_ERROR 0 #define FRAMER_SUCCESS 1 int framer_send(int fd, char *s_buf, int len); int framer_waitfor(int fd, char *w_buf, int w_len); int framer_receive(int fd, char *r_buf, int r_len, unsigned long *petime); int framer_openDevice(char *device, char pid); void framer_closeDevice(int fd); #endif // FRAMER_H 0707010000002C000081A4000028240000003200000001607BF4480000248A000000000000000000000000000000000000003000000000vcontrold-v0.98.10+git20210418.977e6f5/src/io.c/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ // Communication with the vito controller #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <signal.h> #include <syslog.h> #include <unistd.h> #include <termios.h> #include <string.h> #include <time.h> #include <setjmp.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/times.h> #include <fcntl.h> #include <sys/time.h> #include <sys/ioctl.h> #include "io.h" #include "socket.h" #include "common.h" #ifdef __CYGWIN__ // NCC is not defined under cygwin #define NCC NCCS #endif static void sig_alrm(int); static jmp_buf env_alrm; void closeDevice(int fd) { close(fd); } int openDevice(char *device) { // We differentiate TTY and Socket connections. // Socker: no / at the beginning and a : int fd; char *dptr; if (device[0] != '/' && (dptr = strchr(device, ':'))) { char host[MAXBUF]; int port; port = atoi(dptr + 1); // The dptr device gives us the length of the host memset(host, 0, sizeof(host)); strncpy(host, device, dptr - device); // Third parameter == 1 --> noTCPDelay set fd = openCliSocket(host, port, 1); } else { fd = opentty(device); } if (fd < 0) { // Here goes some error stuff return -1; } return fd; } int opentty(char *device) { int fd; logIT(LOG_LOCAL0, "Configuring serial interface %s", device); if ((fd = open(device, O_RDWR)) < 0) { logIT(LOG_ERR, "cannot open %s:%m", device); exit(1); } int s; struct termios oldsb, newsb; s = tcgetattr(fd, &oldsb); if (s < 0) { logIT(LOG_ERR, "error tcgetattr %s:%m", device); exit(1); } newsb = oldsb; #ifdef NCC // NCC is not always defined for (s = 0; s < NCC; s++) { newsb.c_cc[s] = 0; } #else memset(&newsb, 0, sizeof(newsb)); #endif newsb.c_iflag = IGNBRK | IGNPAR; newsb.c_oflag = 0; newsb.c_lflag = 0; // removed ISIG for susp=control-z problem; newsb.c_cflag = (CLOCAL | B4800 | CS8 | CREAD | PARENB | CSTOPB); newsb.c_cc[VMIN] = 1; newsb.c_cc[VTIME] = 0; tcsetattr(fd, TCSADRAIN, &newsb); // DTR High for voltage supply int modemctl = 0; ioctl(fd, TIOCMGET, &modemctl); modemctl |= TIOCM_DTR; s = ioctl(fd, TIOCMSET, &modemctl); if (s < 0) { logIT(LOG_ERR, "error ioctl TIOCMSET %s:%m", device); exit(1); } return fd; } int my_send(int fd, char *s_buf, int len) { int i; int wr; // Empty buffer tcflush(fd, TCIOFLUSH); // We use the socket fixed variant from socket.c wr = writen(fd, s_buf, len); for (i = 0; i < len; i++) { unsigned char byte = s_buf[i] & 255; logIT(LOG_INFO, ">SENT: %02X", (int)byte); } if (wr == len) { return wr; } else { logIT(LOG_ERR, ">ERROR: sent %d of %d bytes", wr, len); return 0; } } int receive(int fd, char *r_buf, int r_len, unsigned long *etime) { int i; struct tms tms_t; clock_t start, end, mid, mid1; unsigned long clktck; clktck = sysconf(_SC_CLK_TCK); start = times(&tms_t); mid1 = start; for (i = 0; i < r_len; i++) { if (signal(SIGALRM, sig_alrm) == SIG_ERR) { logIT1(LOG_ERR, "SIGALRM error"); } if (setjmp(env_alrm) != 0) { logIT1(LOG_ERR, "read timeout"); return -1; } alarm(TIMEOUT); // We use the socket fixed variant from socket.c if (readn(fd, &r_buf[i], 1) <= 0) { logIT1(LOG_ERR, "error read tty");; alarm(0); return -1; } alarm(0); unsigned char byte = r_buf[i] & 255; mid = times(&tms_t); logIT(LOG_INFO, "<RECV: %02X (%0.1f ms)", byte, ((float)(mid - mid1) / clktck) * 1000); mid1 = mid; } end = times(&tms_t); *etime = ((float)(end - start) / clktck) * 1000; return i; } static int setnonblock(int fd) { int flags; // If they have O_NONBLOCK, use the Posix way to do it #if defined(O_NONBLOCK) if (-1 == (flags = fcntl(fd, F_GETFL, 0))) { flags = 0; } return fcntl(fd, F_SETFL, flags | O_NONBLOCK); #else // Otherwise, use the old way of doing it flags = 1; return ioctl(fd, FIOBIO, &flags); #endif } static int setblock(int fd) { int flags; // If they have O_BLOCK, use the Posix way to do it #if defined(O_NONBLOCK) if (-1 == (flags = fcntl(fd, F_GETFL, 0))) { flags = 0; } return fcntl(fd, F_SETFL, flags & (~O_NONBLOCK)); #else // Otherwise, use the old way of doing it flags = 0; return ioctl(fd, FIOBIO, &flags); #endif } static char *dump( char *dest, char *title, char *buf, int len) { int pos = 0; int i; pos = sprintf(dest, "%s", title); for ( i = 0; i < len; i++) { pos += sprintf(dest + pos, " %02X", buf[i] & 0xff); } return dest; } int receive_nb(int fd, char *r_buf, int r_len, unsigned long *etime) { int i; ssize_t len; char string[100]; fd_set rfds; struct timeval tv; int retval; struct tms tms_t; clock_t start, end, mid, mid1; unsigned long clktck; clktck = sysconf(_SC_CLK_TCK); start = times(&tms_t); mid1 = start; i = 0; while ( i < r_len ) { setnonblock(fd); FD_ZERO(&rfds); FD_SET(fd, &rfds); tv.tv_sec = TIMEOUT; tv.tv_usec = 0; retval = select(fd + 1, &rfds, NULL, NULL, &tv); if (retval == 0) { logIT(LOG_ERR, "<RECV: read timeout"); setblock(fd); logIT(LOG_INFO, dump(string, "<RECV: received", r_buf, i)); return -1; } else if (retval < 0) { if (errno == EINTR) { logIT(LOG_INFO, "<RECV: select interrupted - redo"); continue; } else { logIT(LOG_ERR, "<RECV: select error %d", retval); setblock(fd); logIT(LOG_INFO, dump(string, "<RECV: received", r_buf, i)); return -1; } } else if ( FD_ISSET(fd, &rfds)) { len = read(fd, &r_buf[i], r_len - i); if (len == 0) { logIT(LOG_ERR, "<RECV: read eof"); setblock(fd); logIT(LOG_INFO, dump(string, "<RECV: received", r_buf, i)); return -1; } else if (len < 0) { if (errno == EINTR) { logIT(LOG_INFO, "<RECV: read interrupted - redo"); continue; } else { logIT(LOG_ERR, "<RECV: read error %d", errno); setblock(fd); logIT(LOG_INFO, dump(string, "<RECV: received", r_buf, i)); return -1; } } else { unsigned char byte = r_buf[i] & 255; mid = times(&tms_t); logIT(LOG_INFO, "<RECV: len=%zd %02X (%0.1f ms)", len, byte, ((float)(mid - mid1) / clktck) * 1000); mid1 = mid; i += len; } } else { continue; } } end = times(&tms_t); *etime = ((float)(end - start) / clktck) * 1000; setblock(fd); logIT(LOG_INFO, dump(string, "<RECV: received", r_buf, i)); return i; } static void sig_alrm(int signo) { longjmp(env_alrm, 1); } int waitfor(int fd, char *w_buf, int w_len) { int i; time_t start; char r_buf[MAXBUF]; char hexString[128] = "\0"; char dummy[3]; unsigned long etime; for (i = 0; i < w_len; i++) { sprintf(dummy, "%02X", w_buf[i]); strncat(hexString, dummy, strlen(dummy)); } logIT(LOG_INFO, "Waiting for %s", hexString); start = time(NULL); // We wait for the first character, then everything has to apply do { etime = 0; if (receive(fd, r_buf, 1, &etime) < 0) { return 0; } if (time(NULL) - start > TIMEOUT) { logIT1(LOG_WARNING, "Timeout wait"); return 0; } } while (r_buf[0] != w_buf[0]); for (i = 1; i < w_len; i++) { etime = 0; if (receive(fd, r_buf, 1, &etime) < 0) { return 0; } if (time(NULL) - start > TIMEOUT) { logIT1(LOG_WARNING, "Timeout wait"); return 0; } if ( r_buf[0] != w_buf[i]) { logIT1(LOG_ERR, "Lost synchronization"); exit(1); } } // logIT1(LOG_INFO,"Recognized string"); return 1; } 0707010000002D000081A4000028240000003200000001607BF448000004A4000000000000000000000000000000000000003000000000vcontrold-v0.98.10+git20210418.977e6f5/src/io.h/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ #ifndef IO_H #define IO_H int my_send(int fd, char *s_buf, int len); int receive(int fd, char *r_buf, int r_len, unsigned long *etime); int receive_nb(int fd, char *r_buf, int r_len, unsigned long *etime); int waitfor(int fd, char *w_buf, int w_len); int opentty(char *device); int openDevice(char *device); void closeDevice(int fd); // Interface parameters #define TTY "/dev/usb/tts/0" #ifndef MAXBUF #define MAXBUF 4096 #endif #define TIMEOUT 5 #endif // IO_H 0707010000002E000081A4000028240000003200000001607BF448000054AD000000000000000000000000000000000000003400000000vcontrold-v0.98.10+git20210418.977e6f5/src/parser.c/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ // Routines for reading commands #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <signal.h> #include <syslog.h> #include <unistd.h> #include <termios.h> #include <string.h> #include <time.h> #include <stdint.h> #include <ctype.h> #include "xmlconfig.h" #include "parser.h" #include "unit.h" #include "common.h" #include "io.h" #include "framer.h" extern FILE *iniFD; // For creation of the Sim. INI Files void *getUnit(char *str) { // We parse the input for a known unit and return a pointer to the struct return NULL; } int parseLine(char *line, char *hex, int *hexlen, char *uSPtr, ssize_t uSPtrLen) { int token = 0; if (strstr(line, "WAIT") == line) { token = WAIT; } else if (strstr(line, "SEND BYTES") == line) { token = BYTES; } else if (strstr(line, "SEND") == line) { token = SEND; } else if (strstr(line, "RECV") == line) { token = RECV; } else if (strstr(line, "PAUSE") == line) { token = PAUSE; } if (token) { // We parse a hex string and return it processed // Search first blank char *ptr; ptr = strchr(line, ' '); if (! ptr) { logIT(LOG_ERR, "Parse error: Found no blanks: %s", line); } else { // We process the rst of the line char pString[MAXBUF]; char *pPtr; while (*ptr != '\0') { int i; pPtr = pString; for (i = 0; i < MAXBUF; i++) { pPtr[i] = '\0'; } pPtr = pString; // Remove blanks int endFound = 0; while (*++ptr == ' ') { if (*ptr == '\0') { endFound = 1; break; } } if (endFound) { break; } // Now, we read the characters to the next blank or end while ((*ptr != ' ') && (*ptr != '\0') && (*ptr != '\n') && (*ptr != '\r')) { *pPtr++ = *ptr++; } if (! *pString) { break; } *pPtr = '\0'; ++*hexlen; // If it's Pause or Reveice, we tread it as an integer if (token == PAUSE || token == RECV) { *hexlen = atoi(pString); // With RECV, one can give the unit to be converted if (token == RECV) { pPtr = pString; while (*ptr && (isdigit(*ptr) || isspace(*ptr))) { ptr++; } strncpy(uSPtr, ptr, uSPtrLen); } return token; } else if (token == BYTES ) { // Here follows the unit pPtr = pString; while (*ptr && (isdigit(*ptr) || isspace(*ptr))) { ptr++; } strncpy(uSPtr, ptr, uSPtrLen); return token; } else { *hex++ = hex2chr(pString); } *pString = '\0'; } } } return token; } int execByteCode(compilePtr cmpPtr, int fd, char *recvBuf, short recvLen, char *sendBuf, short sendLen, short supressUnit, char bitpos, int retry, char *pRecvPtr, unsigned short recvTimeout) { char string[256]; char result[MAXBUF]; char simIn[500]; char simOut[500]; short len; compilePtr cPtr; unsigned long etime; char out_buff[1024]; int out_len; memset(simIn, 0, sizeof(simIn)); memset(simOut, 0, sizeof(simOut)); // First copy or convert the bytes of sendBuf to the BYTES token of cmpPtr // to be sure not to abort right in the middle of it cPtr = cmpPtr; // do not change cmpPtr, use local cPtr while (cPtr) { if (cPtr->token != BYTES) { cPtr = cPtr->next; continue; } if (supressUnit) { // No unit conversion needed, just copy the bytes if (sendLen != cPtr->len) { // This should never happen! logIT(LOG_ERR, "Error in length of the hex string (%d) != send length of the command (%d), terminating", sendLen, cPtr->len); return -1; } if (cPtr->send) { free(cPtr->send); } cPtr->send = calloc(cPtr->len, sizeof(char)); sendLen = 0; // We don't send the converted sendBuf memcpy(cPtr->send, sendBuf, cPtr->len); } else if (cPtr->uPtr) { len = sendLen; // we need this in procSetUnit() to clear sendBuf if (procSetUnit(cPtr->uPtr, sendBuf, &len, bitpos, pRecvPtr) <= 0) { logIT(LOG_ERR, "Error in unit conversion: %s, terminating", sendBuf); return -1; } if (cPtr->send) { free(cPtr->send); } cPtr->send = calloc(len, sizeof(char)); cPtr->len = len; sendLen = 0; // We don't send the converted sendBuf memcpy(cPtr->send, sendBuf, len); } cPtr = cPtr->next; } do { cPtr = cmpPtr; // We need the starting point for the next round while (cmpPtr) { switch (cmpPtr->token) { case WAIT: if (! framer_waitfor(fd, cmpPtr->send, cmpPtr->len)) { logIT1(LOG_ERR, "Error in wait, terminating"); return -1; } memset(string, 0, sizeof(string)); char2hex(string, cmpPtr->send, cmpPtr->len); strcat(simIn, string); strcat(simIn, " "); break; case SEND: out_len = 0; while (1) { if (out_len + cmpPtr->len > sizeof(out_buff)) { // Hopefully, we never end up here logIT1(LOG_ERR, "Error out_buff buffer overflow, terminating"); return -1; } // Copy all SEND data and BYTES data to out_buff, that CRC calculation // works in framer_send() memcpy(out_buff + out_len, cmpPtr->send, cmpPtr->len); out_len += cmpPtr->len; if (! (cmpPtr->next && cmpPtr->next->token == BYTES)) { break; } cmpPtr = cmpPtr->next; } if (! framer_send(fd, out_buff, out_len)) { logIT1(LOG_ERR, "Error in send, terminating"); return -1; } if (iniFD && *simIn && *simOut) { // We already sent and received something, so we output it fprintf(iniFD, "%s= %s\n", simOut, simIn); memset(simOut, 0, sizeof(simOut)); memset(simIn, 0, sizeof(simIn)); } memset(string, 0, sizeof(string)); char2hex(string, out_buff, out_len); strcat(simOut, string); strcat(simOut, " "); break; case RECV: if (cmpPtr->len > recvLen) { // Hopefully, we don't end up here logIT(LOG_ERR, "Recv buffer too small. Is: %d, should be %d", recvLen, cmpPtr->len); cmpPtr->len = recvLen; } etime = 0; memset(recvBuf, 0, recvLen); if (framer_receive(fd, recvBuf, cmpPtr->len, &etime) <= 0) { logIT1(LOG_ERR, "Error in recv, terminating"); return -1; } // If receiving took longer than the timeout, we start the next round if (recvTimeout && (etime > recvTimeout)) { logIT(LOG_NOTICE, "Recv Timeout: %ld ms > %d ms (Retry: %d)", etime, recvTimeout, (int)(retry - 1)); if (retry <= 1) { logIT1(LOG_ERR, "Recv timeout, terminating"); return -1; } goto RETRY; } // If some errStr is defined, we check if the result is correct if (cmpPtr->errStr && *cmpPtr->errStr) { if (memcmp(recvBuf, cmpPtr->errStr, cmpPtr->len) == 0) { // Wrong answer logIT(LOG_NOTICE, "Errstr matched, wrong result (Retry: %d)", retry - 1); if (retry <= 1) { logIT1(LOG_ERR, "Wrong result, terminating"); return -1; } goto RETRY; } } memset(string, 0, sizeof(string)); char2hex(string, recvBuf, cmpPtr->len); strcat(simIn, string); strcat(simIn, " "); // If we have a Unit (== uPtr), we convert the received value and also // return the converted value to uPtr memset(result, 0, sizeof(result)); if (! supressUnit && cmpPtr->uPtr) { if (procGetUnit(cmpPtr->uPtr, recvBuf, cmpPtr->len, result, bitpos, pRecvPtr) <= 0) { logIT(LOG_ERR, "Error in unit conversion: %s, terminating", result); return -1; } strncpy(recvBuf, result, recvLen); if (iniFD && *simIn && *simOut) { // We already sent and received, now we output it. fprintf(iniFD, "%s= %s \n", simOut, simIn); } return 0; // 0 == converted to unit } if (iniFD && *simIn && *simOut) { // We already sent and received, now we output it. fprintf(iniFD, "%s= %s \n", simOut, simIn); } return cmpPtr->len; break; case PAUSE: logIT(LOG_INFO, "Waiting %i ms", cmpPtr->len); struct timespec sleepTime = { .tv_sec = cmpPtr->len / 1000L, .tv_nsec = (cmpPtr->len % 1000L) * 1000000L}; nanosleep(&sleepTime, NULL); break; case BYTES: // We send the forwarded sendBuffer. No converting has been done. if (sendLen) { if (!my_send(fd, sendBuf, sendLen)) { logIT1(LOG_ERR, "Error in send, terminating"); return -1; } char2hex(string, sendBuf, sendLen); strcat(simOut, string); strcat(simOut, " "); } else if (cmpPtr->len) { // A unit to use is already defined, and we already converted it if (! my_send(fd, cmpPtr->send, cmpPtr->len)) { logIT1(LOG_ERR, "Error in send unit bytes, terminating"); free(cmpPtr->send); cmpPtr->send = NULL; cmpPtr->len = 0; return -1; } memset(string, 0, sizeof(string)); char2hex(string, cmpPtr->send, cmpPtr->len); strcat(simOut, string); strcat(simOut, " "); } break; default: logIT(LOG_ERR, "Unknown token: %d, terminating", cmpPtr->token); return -1; } cmpPtr = cmpPtr->next; } RETRY: retry--; cmpPtr = cPtr; // One more time, please } while ((cmpPtr->errStr || recvTimeout) && (retry > 0)); return 0; } int execCmd(char *cmd, int fd, char *recvBuf, int recvLen) { char uString[100]; // We parse the individual lines char hex[MAXBUF]; int token; int hexlen = 0; int t; unsigned long etime; logIT(LOG_INFO, "Execute %s", cmd); token = parseLine(cmd, hex, &hexlen, uString, sizeof(uString)); // If noOpen is set for debugging, we do nothing here. switch (token) { case WAIT: if (! waitfor(fd, hex, hexlen)) { logIT1(LOG_ERR, "Error wait, terminating"); return -1; } break; case SEND: if (! my_send(fd, hex, hexlen)) { logIT1(LOG_ERR, "Error send, terminating"); exit(1); } break; case RECV: if (hexlen > recvLen) { logIT(LOG_ERR, "Recv buffer too small. Is: %d should be %d", recvLen, hexlen); hexlen = recvLen; } etime = 0; if (receive(fd, recvBuf, hexlen, &etime) <= 0) { logIT1(LOG_ERR, "Error recv, terminating"); exit(1); } logIT(LOG_INFO, "Recv: %ld ms", etime); // If we have a unit (== uPtr), we convert the received value and also return it to uPtr return hexlen; break; case PAUSE: t = (int) hexlen / 1000; logIT(LOG_INFO, "Waiting %i s", t); sleep(t); break; default: logIT(LOG_INFO, "Unknown command: %s", cmd); } return 0; } compilePtr newCompileNode(compilePtr ptr) { compilePtr nptr; if (ptr && ptr->next) { return newCompileNode(ptr->next); } nptr = calloc(1, sizeof(Compile)); if (! nptr) { fprintf(stderr, "malloc failed\n"); exit(1); } if (ptr) { ptr->next = nptr; } nptr->token = 0; nptr->len = 0; nptr->uPtr = NULL; nptr->next = NULL; return nptr; } void removeCompileList(compilePtr ptr) { if (ptr && ptr->next) { removeCompileList(ptr->next); } if (ptr) { free(ptr->send); ptr->send = NULL; free(ptr); ptr = NULL; } } int expand(commandPtr cPtr, protocolPtr pPtr) { // Recursion if (! cPtr) { return 0; } if (cPtr->next) { expand(cPtr->next, pPtr); } // If no address has been set, we do nothing if (! cPtr->addr) { return 0; } char eString[2000]; char *ePtr = eString;; char var[100]; char name[100]; char *ptr, *bptr; macroPtr mFPtr; char string[256]; char *sendPtr, *sendStartPtr; char *tmpPtr; icmdPtr iPtr; // The command pointer's send has to be assembled // 1. Search command pcmd at the protocol's command if (! (iPtr = (icmdPtr) getIcmdNode( pPtr->icPtr, cPtr->pcmd))) { logIT(LOG_ERR, "Protocol command %s (at %s) not defined", cPtr->pcmd, cPtr->name); exit(3); } // 2. Parse the line and replace the variables with values from cPtr sendPtr = iPtr->send; sendStartPtr = iPtr->send; if (! sendPtr) { return 0; } logIT(LOG_INFO, "protocmd line: %s", sendPtr); memset(eString, 0, sizeof(eString)); cPtr->retry = iPtr->retry; // We take the Retry value from the protocol command cPtr->recvTimeout = iPtr->recvTimeout; // Same for the receive timeout do { ptr = sendPtr; while (*ptr++) { if ((*ptr == '$') || (*ptr == '\0')) { break; } } bptr = ptr; while (*bptr++) { if ((*bptr == ' ') || (*bptr == ';') || (*bptr == '\0')) { break; } } // Don't copy the converted string strncpy(ePtr, sendPtr, ptr - sendPtr); ePtr += ptr - sendPtr; memset(var, 0, sizeof(var)); strncpy(var, ptr + 1, bptr - ptr - 1); //snprintf(string, sizeof(string)," Var: %s",var); //logIT(LOG_INFO,string); if (*var) { // Do we have variabls to expand at all? if (strstr(var, "addr") == var) { // Always two bytes int i; memset(string, 0, sizeof(string)); for (i = 0; i < strlen(cPtr->addr) - 1; i += 2) { strncpy(ePtr, cPtr->addr + i, 2); ePtr += 2; *ePtr++ = ' '; } ePtr--; } else if (strstr(var, "len") == var) { snprintf(string, sizeof(string), "%d", cPtr->len); strncpy(ePtr, string, strlen(string)); ePtr += strlen(string); } else if (strstr(var, "hexlen") == var) { snprintf(string, sizeof(string), "%02X", cPtr->len); strncpy(ePtr, string, strlen(string)); ePtr += strlen(string); } else if (strstr(var, "unit") == var) { if (cPtr->unit) { strncpy(ePtr, cPtr->unit, strlen(cPtr->unit)); ePtr += strlen(cPtr->unit); } } else { logIT(LOG_ERR, "Variable %s Unknown", var); exit(3); } } sendPtr = bptr; } while (*sendPtr); logIT(LOG_INFO, " After substitution: %s", eString); tmpPtr = calloc(strlen(eString) + 1, sizeof(char)); strcpy(tmpPtr, eString); // 3. Expand the line as usual sendPtr = tmpPtr; sendStartPtr = sendPtr; // We search for words and look if we have them as macros memset(eString, 0, sizeof(eString)); ePtr = eString; do { ptr = sendPtr; while (*ptr++) { if ((*ptr == ' ') || (*ptr == ';') || (*ptr == '\0')) { break; } } memset(name, 0, sizeof(name)); strncpy(name, sendPtr, ptr - sendPtr); if ((mFPtr = getMacroNode(pPtr->mPtr, name))) { strncpy(ePtr, mFPtr->command, strlen(mFPtr->command)); ePtr += strlen(mFPtr->command); *ePtr++ = *ptr; } else { strncpy(ePtr, sendPtr, ptr - sendPtr + 1); ePtr += ptr - sendPtr + 1; } sendPtr = ptr + 1; } while (*sendPtr); free(tmpPtr); logIT(LOG_INFO, " after EXPAND:%s", eString); if (! (cPtr->send = calloc(strlen(eString) + 1, sizeof(char)))) { logIT1(LOG_ERR, "calloc failed"); exit(1); } strcpy(cPtr->send, eString); return 1; } compilePtr buildByteCode(commandPtr cPtr, unitPtr uPtr) { // Recursion if (!cPtr) { return 0; } if (cPtr->next) { buildByteCode(cPtr->next, uPtr); } // If no address has been given, we do nothing if (! cPtr->addr) { return 0; } char eString[2000]; char cmd[200]; char *ptr; char hex[MAXBUF]; int hexlen; int token; char uString[100]; char *uSPtr = uString; compilePtr cmpPtr, cmpStartPtr; cmpStartPtr = NULL; char *sendPtr, *sendStartPtr; sendPtr = cPtr->send; sendStartPtr = cPtr->send; if (! sendPtr) { // Nothing to do here return 0; } logIT(LOG_INFO, "BuildByteCode: %s", sendPtr); memset(eString, 0, sizeof(eString)); do { ptr = sendPtr; while (*ptr++) { if ((*ptr == '\0') || (*ptr == ';')) { break; } } memset(cmd, 0, sizeof(cmd)); strncpy(cmd, sendPtr, ptr - sendPtr); hexlen = 0; memset(uSPtr, 0, sizeof(uString)); token = parseLine(cmd, hex, &hexlen, uString, sizeof(uString)); logIT(LOG_INFO, " Token: %d Hexlen: %d, Unit: %s", token, hexlen, uSPtr); cmpPtr = newCompileNode(cmpStartPtr); if (!cmpStartPtr) { cmpStartPtr = cmpPtr; } cmpPtr->token = token; cmpPtr->len = hexlen; cmpPtr->errStr = cPtr->errStr; cmpPtr->send = calloc(hexlen, sizeof(char)); memcpy(cmpPtr->send, hex, hexlen); if (*uSPtr && !(cmpPtr->uPtr = getUnitNode(uPtr, uSPtr))) { logIT(LOG_ERR, "Unit %s not defined", uSPtr); exit(3); } sendPtr += strlen(cmd) + 1; } while (*sendPtr); cPtr->cmpPtr = cmpStartPtr; return cmpStartPtr; } void compileCommand(devicePtr dPtr, unitPtr uPtr) { if (! dPtr) { return; } if (dPtr->next) { compileCommand(dPtr->next, uPtr); } logIT(LOG_INFO, "Expanding command for device %s", dPtr->id); expand(dPtr->cmdPtr, dPtr->protoPtr); buildByteCode(dPtr->cmdPtr, uPtr); } 0707010000002F000081A4000028240000003200000001607BF4480000056F000000000000000000000000000000000000003400000000vcontrold-v0.98.10+git20210418.977e6f5/src/parser.h/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ #ifndef PARSER_H #define PARSER_H int parseLine(char *lineo, char *hex, int *hexlen, char *uSPtr, ssize_t uSPtrLen); int execCmd(char *cmd, int fd, char *result, int resultLen); void removeCompileList(compilePtr ptr); int execByteCode(compilePtr cmpPtr, int fd, char *recvBuf, short recvLen, char *sendBuf, short sendLen, short supressUnit, char bitpos, int retry, char *pRecvPtr, unsigned short recvTimeout); void compileCommand(devicePtr dPtr, unitPtr uPtr); // Token Definition #define WAIT 1 #define RECV 2 #define SEND 3 #define PAUSE 4 #define BYTES 5 #ifndef MAXBUF #define MAXBUF 4096 #endif #endif // PARSER_H 07070100000030000081A4000028240000003200000001607BF448000003C1000000000000000000000000000000000000003400000000vcontrold-v0.98.10+git20210418.977e6f5/src/prompt.h/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ /* Prompt Definition fuer die gemeinsame Nutzung in client und Server */ #ifndef PROMPT_H #define PROMPT_H #define PROMPT "vctrld>" #define BYE "good bye!\n" #define UNKNOWN "ERR: command unknown\n" #define ERR "ERR:" #endif // PROMPT_H 07070100000031000081A4000028240000003200000001607BF448000010F4000000000000000000000000000000000000003700000000vcontrold-v0.98.10+git20210418.977e6f5/src/semaphore.c/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <string.h> #include <syslog.h> #include <sys/param.h> #include "common.h" #include "semaphore.h" #define MAX_RETRIES 10 #if !defined(__APPLE__) // on my mac this is a redefinition union semun { int val; struct semid_ds *buf; unsigned short *array; }; #endif /* * initsem() -- more-than-inspired by W. Richard Stevens' UNIX Network * Programming 2nd edition, volume 2, lockvsem.c, page 295. */ int initsem(key_t key, int nsems) { // key from ftok() int i; union semun arg; struct semid_ds buf; struct sembuf sb; int semid; semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666); if (semid >= 0) { // we got it first sb.sem_op = 1; sb.sem_flg = 0; arg.val = 1; for (sb.sem_num = 0; sb.sem_num < nsems; sb.sem_num++) { // do a semop() to "free" the semaphores. // this sets the sem_otime field, as needed below. if (semop(semid, &sb, 1) == -1) { int e = errno; semctl(semid, 0, IPC_RMID); // clean up errno = e; return -1; // error, check errno } } } else if (errno == EEXIST) { // someone else got it first int ready = 0; semid = semget(key, nsems, 0); // get the id if (semid < 0) { // error, check errno return semid; } // wait for other process to initialize the semaphore: arg.buf = &buf; for (i = 0; i < MAX_RETRIES && !ready; i++) { semctl(semid, nsems - 1, IPC_STAT, arg); if (arg.buf->sem_otime != 0) { ready = 1; } else { sleep(1); } } if (! ready) { errno = ETIME; return -1; } } else { return semid; // error, check errno } return semid; } int semid; char tmpfilename[MAXPATHLEN + 1]; // account for the leading '\0' int vcontrol_seminit() { key_t key; struct sembuf sb; int tmpfile; strncpy(tmpfilename, TMPFILENAME, sizeof(TMPFILENAME)); if ((tmpfile = mkstemp(tmpfilename)) < 0) { perror("mkstemp"); exit(1); } close(tmpfile); sb.sem_num = 0; sb.sem_op = -1; // set to allocate resource sb.sem_flg = SEM_UNDO; if ((key = ftok(tmpfilename, 'V')) == -1) { perror("ftok"); exit(1); } // grab the semaphore set created by seminit.c: if ((semid = initsem(key, 1)) == -1) { perror("initsem"); exit(1); } return 1; } int vcontrol_semfree() { // remove it: if (semctl(semid, 0, IPC_RMID) == -1) { perror("semctl"); exit(1); } unlink(tmpfilename); return 1; // what should we return? } int vcontrol_semget() { logIT(LOG_INFO, "Process %d tries to aquire lock", getpid()); struct sembuf sb; sb.sem_num = 0; sb.sem_op = -1; // set to allocate resource sb.sem_flg = SEM_UNDO; if (semop(semid, &sb, 1) == -1) { perror("semop"); exit(1); } logIT(LOG_INFO, "Process %d got lock", getpid()); return 1; } int vcontrol_semrelease() { struct sembuf sb; logIT(LOG_INFO, "Process %d released lock", getpid()); sb.sem_num = 0; sb.sem_op = 1; // free resource sb.sem_flg = SEM_UNDO; if (semop(semid, &sb, 1) == -1) { perror("semop"); exit(1); } return 1; } 07070100000032000081A4000028240000003200000001607BF4480000044D000000000000000000000000000000000000003700000000vcontrold-v0.98.10+git20210418.977e6f5/src/semaphore.h/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ #ifndef SEMAPHORE_H #define SEMAPHORE_H #include <sys/param.h> #ifdef _CYGWIN__ #define TMPFILENAME "vcontrol.lockXXXXXX" #else #define TMPFILENAME "/tmp/vcontrol.lockXXXXXX" #endif extern char tmpfilename[MAXPATHLEN + 1]; // account for the leading '\0' int vcontrol_seminit(); int vcontrol_semfree(); int vcontrol_semget(); int vcontrol_semrelease(); #endif // SEMAPHORE_H 07070100000033000081A4000028240000003200000001607BF448000024DF000000000000000000000000000000000000003400000000vcontrold-v0.98.10+git20210418.977e6f5/src/socket.c/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ #define _GNU_SOURCE #include <sys/time.h> #include <time.h> #include <errno.h> #include <fcntl.h> #include <netdb.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <syslog.h> #include <time.h> #include <setjmp.h> #include <signal.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/tcp.h> // TCP_NODELAY is defined there -fn- #if defined (__FreeBSD__) || defined(__APPLE__) #include <netinet/in.h> #endif #include "socket.h" #include "common.h" #include "vclient.h" const int LISTEN_QUEUE = 128; int openSocket(int tcpport) { int listenfd; int n; char *port; struct addrinfo hints, *res, *ressave; memset(&hints, 0, sizeof(struct addrinfo)); switch (inetversion) { case 6: hints.ai_family = PF_INET6; break; case 4: // this is for backward compatibility. We can explictly // activate IPv6 with the -6 switch. Later we can use // PF_UNSPEC as default and let the OS decide default: hints.ai_family = PF_INET; } hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; asprintf(&port, "%d", tcpport); n = getaddrinfo(NULL, port, &hints, &res); free(port); if (n < 0) { logIT(LOG_ERR, "getaddrinfo error: [%s]\n", gai_strerror(n)); return -1; } ressave = res; // Try open socket with each address getaddrinfo returned, // until getting a valid listening socket. listenfd = -1; while (res) { listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); int optval = 1; if (listenfd > 0 && setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval) < 0 ) { logIT1(LOG_ERR, "setsockopt failed!"); exit(1); } if (! (listenfd < 0)) { if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) { break; } close(listenfd); listenfd = -1; } res = res->ai_next; } if (listenfd < 0) { freeaddrinfo(ressave); fprintf(stderr, "socket error: could not open socket\n"); exit(1); } listen(listenfd, LISTEN_QUEUE); logIT(LOG_NOTICE, "TCP socket %d opened", tcpport); freeaddrinfo(ressave); return listenfd; } int listenToSocket(int listenfd, int makeChild) { int connfd; pid_t childpid; struct sockaddr_storage cliaddr; socklen_t cliaddrlen = sizeof(cliaddr); char clienthost [NI_MAXHOST]; char clientservice[NI_MAXSERV]; signal(SIGCHLD, SIG_IGN); for (;;) { connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &cliaddrlen); getnameinfo((struct sockaddr *) &cliaddr, cliaddrlen, clienthost, sizeof(clienthost), clientservice, sizeof(clientservice), NI_NUMERICHOST); if (connfd < 0) { logIT(LOG_NOTICE, "accept on host %s: port %s", clienthost, clientservice); close(connfd); continue; } logIT(LOG_NOTICE, "Client connected %s:%s (FD:%d)", clienthost, clientservice, connfd); if (! makeChild) { return connfd; } else if ( (childpid = fork()) == 0) { // unser Kind close(listenfd); return connfd; } else { logIT(LOG_INFO, "Child process started with pid %d", childpid); } close(connfd); } } void closeSocket(int sockfd) { logIT(LOG_INFO, "Closed connection (fd:%d)", sockfd); close(sockfd); } int openCliSocket(char *host, int port, int noTCPdelay) { struct addrinfo hints; // use hints for ipv46 address resolution struct addrinfo *res; struct addrinfo *ressave; int n; int sockfd; char port_string[16]; // the IPv6 world use a char* instead of an int in getaddrinfo memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ALL | AI_V4MAPPED; snprintf(port_string, sizeof(port_string), "%d", port); n = getaddrinfo(host, port_string, &hints, &res); if (n < 0) { logIT(LOG_ERR, "Error in getaddrinfo: %s:%s", host, gai_strerror(n)); exit(1); } ressave = res; sockfd = -1; while (res) { sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (! (sockfd < 0)) { if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0) { break; } // we have a succesfull connection close(sockfd); sockfd = -1; } res = res->ai_next; } freeaddrinfo(ressave); if (sockfd < 0) { logIT(LOG_ERR, "TTY Net: No connection to %s:%d", host, port); return -1; } logIT(LOG_INFO, "ClI Net: connected %s:%d (FD:%d)", host, port, sockfd); int flag = 1; if (noTCPdelay && (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)))) { logIT(LOG_ERR, "Error in setsockopt TCP_NODELAY (%s)", strerror(errno)); } return sockfd; } // Stuff aus Unix Network Programming Vol 1 // include writen // Write "n" bytes to a descriptor. ssize_t writen(int fd, const void *vptr, size_t n) { size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ((nwritten = write(fd, ptr, nleft)) <= 0) { if (errno == EINTR) { // and call write() again nwritten = 0; } else { // error return -1; } } nleft -= nwritten; ptr += nwritten; } return n; } // end writen ssize_t Writen(int fd, void *ptr, size_t nbytes) { if (writen(fd, ptr, nbytes) != nbytes) { logIT1(LOG_ERR, "Error writing to socket"); return 0; } return nbytes; } // include readn // Read "n" bytes from a descriptor. ssize_t readn(int fd, void *vptr, size_t n) { size_t nleft; ssize_t nread; char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ((nread = read(fd, ptr, nleft)) < 0) { if (errno == EINTR) { // and call read() again nread = 0; } else { return -1; } } else if (nread == 0) { // EOF break; } #ifdef __CYGWIN__ // This is a workaround for Cygwin. // Here cygwins read(fd,buff,count) is reading more than count chars! this is bad! if (nread > nleft) { nleft = 0; } else { nleft -= nread; } #else nleft -= nread; #endif ptr += nread; } return n - nleft; //return >= 0 } // end readn ssize_t Readn(int fd, void *ptr, size_t nbytes) { ssize_t n; if ((n = readn(fd, ptr, nbytes)) < 0) { logIT1(LOG_ERR, "Error reading from socket"); return 0; } return n; } // include readline static ssize_t my_read(int fd, char *ptr) { static ssize_t read_cnt = 0; static char *read_ptr; static char read_buf[MAXLINE]; if (read_cnt <= 0) { again: if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) { if (errno == EINTR) { goto again; } return -1; } else if (read_cnt == 0) { return 0; } read_ptr = read_buf; } read_cnt--; *ptr = *read_ptr++; return 1; } ssize_t readline(int fd, void *vptr, size_t maxlen) { int n; ssize_t rc; char c; char *ptr; ptr = vptr; for (n = 1; n < maxlen; n++) { if ( (rc = my_read(fd, &c)) == 1) { *ptr++ = c; if (c == '\n') { // newline is stored, like fgets() break; } } else if (rc == 0) { if (n == 1) { // EOF, no data read return 0; } else { // EOF, some data was read break; } } else { // error, errno set by read() return -1; } } *ptr = 0; // null terminate like fgets() return n; } // end readline ssize_t Readline(int fd, void *ptr, size_t maxlen) { ssize_t n; if ((n = readline(fd, ptr, maxlen)) < 0) { logIT1(LOG_ERR, "Error reading from socket"); return 0; } return n; } 07070100000034000081A4000028240000003200000001607BF4480000053B000000000000000000000000000000000000003400000000vcontrold-v0.98.10+git20210418.977e6f5/src/socket.h/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ #ifndef SOCKET_H #define SOCKET_H #include <arpa/inet.h> int openSocket(int tcpport); int listenToSocket(int listenfd, int makeChild); int openCliSocket(char *host, int port, int noTCPdelay); void closeSocket(int sockfd); ssize_t writen(int fd, const void *vptr, size_t n); ssize_t Writen(int fd, void *ptr, size_t nbytes); ssize_t readn(int fd, void *vptr, size_t n); ssize_t Readn(int fd, void *ptr, size_t nbytes); ssize_t readline(int fd, void *vptr, size_t maxlen); ssize_t Readline(int fd, void *ptr, size_t maxlen); #define LISTENQ 1024 #define MAXLINE 1000 #define CONNECT_TIMEOUT 3 #endif // SOCKET_H 07070100000035000081A4000028240000003200000001607BF44800005363000000000000000000000000000000000000003200000000vcontrold-v0.98.10+git20210418.977e6f5/src/unit.c/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ // Conversion of units #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <signal.h> #include <syslog.h> #include <unistd.h> #include <termios.h> #include <string.h> #include <time.h> #include <stdint.h> #include <ctype.h> #include <arpa/inet.h> #if defined __linux__ || defined __CYGWIN__ #include <asm/byteorder.h> #endif #ifdef __CYGWIN__ #define __le64_to_cpu(x) (x) #define __le32_to_cpu(x) (x) #define __le16_to_cpu(x) (x) #define __cpu_to_le64(x) (x) #define __cpu_to_le32(x) (x) #define __cpu_to_le16(x) (x) #endif #include "xmlconfig.h" #include "common.h" #include "arithmetic.h" // We need this at procSet ... #define FLOAT 1 #define INT 2 #if defined (__APPLE__) // this is needed to emulate the linux API calls #include <libkern/OSByteOrder.h> #define __cpu_to_be64(x) OSSwapHostToBigInt64(x) #define __cpu_to_le64(x) OSSwapHostToLittleInt64(x) #define __cpu_to_be32(x) OSSwapHostToBigInt32(x) #define __cpu_to_le32(x) OSSwapHostToLittleInt32(x) #define __cpu_to_be16(x) OSSwapHostToBigInt16(x) #define __cpu_to_le16(x) OSSwapHostToLittleInt16(x) #define __be64_to_cpu(x) OSSwapBigToHostInt64(x) #define __le64_to_cpu(x) OSSwapLittleToHostInt64(x) #define __be32_to_cpu(x) OSSwapBigToHostInt32(x) #define __le32_to_cpu(x) OSSwapLittleToHostInt32(x) #define __be16_to_cpu(x) OSSwapBigToHostInt16(x) #define __le16_to_cpu(x) OSSwapLittleToHostInt16(x) #endif int getCycleTime(char *recv, int len, char *result); int setCycleTime(char *string, char *sendBuf); short bytes2Enum(enumPtr ptr, char *bytes, char **text, short len); short text2Enum(enumPtr ptr, char *text, char **bytes, short *len); int getErrState(enumPtr ePtr, char *recv, int len, char *result); int getSysTime(char *recv, int len, char *result); int setSysTime(char *input, char *sendBuf); int getCycleTime(char *recv, int len, char *result) { int i; char string[80]; if (len % 2) { sprintf(result, "Byte count not even"); return 0; } memset(string, 0, sizeof(string)); for (i = 0; i < len; i += 2) { // TODO - vitoopen: Leave output in German. // CHANGING THIS WOULD BREAK existing applications. // => maybe we could enable english results later with a build option, // but not for the default. if (recv[i] == (char)0xff) { snprintf(string, sizeof(string), "%d:An:-- Aus:--\n", (i / 2) + 1); } else { snprintf(string, sizeof(string), "%d:An:%02d:%02d Aus:%02d:%02d\n", (i / 2) + 1, (recv[i] & 0xF8) >> 3, (recv[i] & 7) * 10, (recv[i + 1] & 0xF8) >> 3, (recv[i + 1] & 7) * 10); } strcat(result, string); } result[strlen(result) - 1] = '\0'; // remove \n return 1; } int setCycleTime(char *input, char *sendBuf) { char *sptr, *cptr; char *bptr = sendBuf; int hour, min; int count = 0; // We split at the blank sptr = strtok(input, " "); cptr = NULL; // First, we fill the sendBuf with 8 x ff for (count = 0; count < 8; sendBuf[count++] = 0xff); count = 0; do { if (sptr < cptr) { // We already have been here (by double blanks) continue; } while (isblank(*sptr)) { sptr++; } // Does the string only consist of one or two minus? --> This line remains empty if ((0 == strcmp(sptr, "-")) || (0 == strcmp(sptr, "--"))) { // We skip the next time designation, as it also must be a "-" bptr++; count++; sptr = strtok(NULL, " "); logIT(LOG_INFO, "Cycle Time: -- -- -> [%02X%02X]", 0xff, 0xff); } else { // Is the a : in the string? if (! strchr(sptr, ':')) { sprintf(sendBuf, "Wrong time format: %s", sptr); return 0; } sscanf(sptr, "%u:%u", &hour, &min); *bptr = ((hour << 3) + (min / 10)) & 0xff; logIT(LOG_INFO, "Cycle Time: %02d:%02d -> [%02X]", hour, min, (unsigned char) *bptr); } bptr++; cptr = sptr; count++; } while ((sptr = strtok(NULL, " ")) != NULL); if ((count / 2) * 2 != count) { logIT(LOG_WARNING, "Times count odd, ignoring %s", cptr); *(bptr - 1) = 0xff; } return 8; } int bcd2dec(int bcd) { int dec = bcd - ((int)(bcd / 16) * 6); return dec; } int getSysTime(char *recv, int len, char *result) { struct tm *t; time_t tt; if (len != 8) { sprintf(result, "System time: Len <> 8 bytes"); return 0; } // Use timezone information from the host system time(&tt); t = localtime(&tt); t->tm_year = bcd2dec(recv[0]) * 100 + bcd2dec(recv[1]) - 1900; t->tm_mon = bcd2dec(recv[2]) - 1; t->tm_mday = bcd2dec(recv[3]); t->tm_wday = bcd2dec(recv[4]) % 7; t->tm_hour = bcd2dec(recv[5]); t->tm_min = bcd2dec(recv[6]); t->tm_sec = bcd2dec(recv[7]); // This might break existing applications. But changing the string to some custom format // that is not recognized by strptime for parsing dates has a symmetry impact that the // format for getTime is different from the format required by setTime. // I would consider the command symmetry more important for the future. strftime(result, 48, "%FT%T%z", t); return 1; } int setSysTime(char *input, char *sendBuf) { char systime[80]; time_t tt; struct tm t_in = {0}; struct tm *t; struct tm *th; memset(systime, 0, sizeof(systime)); time(&tt); th = localtime(&tt); // No parameter, set the current system time if (!*input) { t = th; } else { #ifdef _XOPEN_SOURCE char *parseEnd = strptime(input, "%FT%T%z", &t_in); // If the string is fully parsed, parseEnd should be the terminating '0' character of the input string. if (!parseEnd || *parseEnd) { logIT(LOG_ERR, "Can not parse time string '%s'. Use the same ISO 8601 time format for setting a time as you get when getting a time.", input); return 0; } #else logIT1(LOG_ERR, "Setting an explicit time is not supported yet"); return 0; #endif // Recalculate the input time adjusted to the hosts timezone. // It is probably not the best idea to use internal variables, but // there doesn't seem to be an efficient way to transform times // between timezones. #if defined(__CYGWIN__) || defined(__APPLE__) t_in.tm_sec += (th->tm_gmtoff - t_in.tm_gmtoff); t_in.tm_gmtoff = th->tm_gmtoff; #else t_in.tm_sec += (th->__tm_gmtoff - t_in.__tm_gmtoff); t_in.__tm_gmtoff = th->__tm_gmtoff; #endif t_in.tm_isdst = th->tm_isdst; mktime(&t_in); t = &t_in; } strftime(systime, 24, "%C %y %m %d %w %H %M %S", t); return string2chr(systime, sendBuf, 8); } int getErrState(enumPtr ePtr, char *recv, int len, char *result) { int i; char *errtext; char systime[35]; char string[300]; char *ptr; if (len % 9) { sprintf(result, "Bytes count is not mod 9"); return 0; } for (i = 0; i < len; i += 9) { ptr = recv + i; memset(string, 0, sizeof(string)); memset(systime, 0, sizeof(systime)); // Error code: Byte 0 if (bytes2Enum(ePtr, ptr, &errtext, 1)) // Rest SysTime if (getSysTime(ptr + 1, 8, systime)) { snprintf(string, sizeof(string), "%s %s (%02X)\n", systime, errtext, (unsigned char) *ptr); strcat(result, string); continue; } // Format error sprintf(result, "%s %s", errtext, systime); return 0; } result[strlen(result) - 1] = '\0'; // Remove \n return 1; } short bytes2Enum(enumPtr ptr, char *bytes, char **text, short len) { enumPtr ePtr = NULL; char string[200]; if (! len) { return 0; } // Search for the appropriate enum and return the value if (! (ePtr = getEnumNode(ptr, bytes, len))) { // We search for the default ePtr = getEnumNode(ptr, bytes, -1); } if (ePtr) { *text = ePtr->text; memset(string, 0, sizeof(string)); char2hex(string, bytes, len); strcat(string, " -> "); strcat(string, ePtr->text); logIT1(LOG_INFO, string); return 1; } else { return 0; } } short text2Enum(enumPtr ptr, char *text, char **bytes, short *len) { enumPtr ePtr = NULL; char string[200]; char string2[1000]; // Search for the appropriate enum and return the value if (! (ePtr = getEnumNode(ptr, text, 0))) { return 0; } *bytes = ePtr->bytes; *len = ePtr->len; memset(string, 0, sizeof(string)); strncpy(string, text, sizeof(string)); strcat(string, " -> "); memset(string2, 0, sizeof(string2)); char2hex(string2, ePtr->bytes, ePtr->len); strcat(string, string2); logIT1(LOG_INFO, string); return *len; } int procGetUnit(unitPtr uPtr, char *recvBuf, int recvLen, char *result, char bitpos, char *pRecvPtr) { char string[256]; char error[1000]; char buffer[MAXBUF]; char *errPtr = error; //short t; float erg; int ergI; char formatI[20]; float floatV = 0; char *inPtr; char *tPtr; // Here the types for the conversion in <type> tags int8_t charV; uint8_t ucharV; int16_t shortV; int16_t tmpS; uint16_t ushortV; uint16_t tmpUS; int32_t intV; int32_t tmpI; uint32_t tmpUI; uint32_t uintV; memset(errPtr, 0, sizeof(error)); // We tread the different <type> entries if (strstr(uPtr->type, "cycletime") == uPtr->type) { // Cycle time if (getCycleTime(recvBuf, recvLen, result)) { return 1; } else { return -1; } } else if (strstr(uPtr->type, "systime") == uPtr->type) { // System time if (getSysTime(recvBuf, recvLen, result)) { return 1; } else { return -1; } } else if (strstr(uPtr->type, "errstate") == uPtr->type) { // Error code + System time if (getErrState(uPtr->ePtr, recvBuf, recvLen, result)) { return 1; } else { return -1; } } else if (strstr(uPtr->type, "enum") == uPtr->type) { // enum if (bytes2Enum(uPtr->ePtr, recvBuf, &tPtr, recvLen)) { strcpy(result, tPtr); return 1; } else { sprintf(result, "Didn't find an appropriate enum"); return -1; } } // Here are all the numeric types if (strstr(uPtr->type, "char") == uPtr->type) { // Conversion to Char 1Byte memcpy(&charV, recvBuf, 1); floatV = charV; // Implicit type conversion to float for our arithmetic sprintf(formatI, "%%02X %%s"); } else if (strstr(uPtr->type, "uchar") == uPtr->type) { // Conversion to Unsigned Char 1Byte memcpy(&ucharV, recvBuf, 1); floatV = ucharV; // Implicit type conversion to float for our arithmetic sprintf(formatI, "%%02X %%s"); } else if (strstr(uPtr->type, "short") == uPtr->type) { // Conversion to Short 2Byte memcpy(&tmpS, recvBuf, 2); // According to the CPU, the conversion is done here shortV = __le16_to_cpu(tmpS); floatV = shortV; // Implicit type conversion to float for our arithmetic sprintf(formatI, "%%04X %%s"); } else if (strstr(uPtr->type, "ushort") == uPtr->type) { // Conversion to Short 2Byte memcpy(&tmpUS, recvBuf, 2); // According to the CPU, the conversion is done here ushortV = __le16_to_cpu(tmpUS); floatV = ushortV; // Implicit type conversion to float for our arithmetic sprintf(formatI, "%%04X %%s"); } else if (strstr(uPtr->type, "int") == uPtr->type) { // Conversion to Int 4Byte memcpy(&tmpI, recvBuf, 4); // According to the CPU, the conversion is done here intV = __le32_to_cpu(tmpI); floatV = intV; // Implicit type conversion to float for our arithmetic sprintf(formatI, "%%08X %%s"); } else if (strstr(uPtr->type, "uint") == uPtr->type) { // Conversion to Unsigned Int 4Byte memcpy(&tmpUI, recvBuf, 4); // According to the CPU, the conversion is done here uintV = __le32_to_cpu(tmpUI); floatV = uintV; // Implicit type conversion to float for our arithmetic sprintf(formatI, "%%08X %%s"); } else if (uPtr->type) { logIT(LOG_ERR, "Unknown type %s in unit %s", uPtr->type, uPtr->name); return -1; } // Some logging int n; char *ptr; char res; ptr = recvBuf; memset(buffer, 0, sizeof(buffer)); for (n = 0; n <= 9; n++) { // The bytes 0..9 are of interest memset(string, 0, sizeof(string)); unsigned char byte = *ptr++ & 255; snprintf(string, sizeof(string), "B%d:%02X ", n, byte); strcat(buffer, string); if (n >= MAXBUF - 3) { break; } } if (uPtr->gCalc && *uPtr->gCalc) { // calc in XML and get defined within logIT(LOG_INFO, "Typ: %s (in float: %f)", uPtr->type, floatV); inPtr = uPtr->gCalc; logIT(LOG_INFO, "(FLOAT) Exp: %s [%s]", inPtr, buffer); erg = execExpression(&inPtr, recvBuf, floatV, errPtr); if (*errPtr) { logIT(LOG_ERR, "Exec %s: %s", uPtr->gCalc, error); strcpy(result, string); return -1; } sprintf(result, "%f %s", erg, uPtr->entity); } else if (uPtr->gICalc && *uPtr->gICalc) { // icalc in XML and get defined within inPtr = uPtr->gICalc; logIT(LOG_INFO, "(INT) Exp: %s [BP:%d] [%s]", inPtr, bitpos, buffer); ergI = execIExpression(&inPtr, recvBuf, bitpos, pRecvPtr, errPtr); if (*errPtr) { logIT(LOG_ERR, "Exec %s: %s", uPtr->gCalc, error); strcpy(result, string); return -1; } logIT(LOG_INFO, "Res: (Hex max. 4 bytes) %08x", ergI); res = ergI; if ( uPtr->ePtr && bytes2Enum(uPtr->ePtr, &res, &tPtr, recvLen)) { strcpy(result, tPtr); return 1; } else { sprintf(result, formatI, ergI, uPtr->entity); return 1; } // Probably do the enum search here } return 1; } int procSetUnit(unitPtr uPtr, char *sendBuf, short *sendLen, char bitpos, char *pRecvPtr) { char string[256]; char error[1000]; char buffer[MAXBUF]; char input[MAXBUF]; char *errPtr = error; // short t; float erg = 0.0; int ergI = 0; short count; char ergType; float floatV; char *inPtr; // Here the types for the <type> tag conversion int8_t charV; uint8_t ucharV; int16_t shortV; int16_t tmpS; uint16_t ushortV; uint16_t tmpUS; int32_t intV; int32_t tmpI; uint32_t tmpUI; uint32_t uintV; memset(errPtr, 0, sizeof(error)); // Some logging int n = 0; char *ptr; char dumBuf[10]; memset(dumBuf, 0, sizeof(dumBuf)); memset(buffer, 0, sizeof(buffer)); // We copy the sendBuf, as this one is also used for return strncpy(input, sendBuf, sizeof(input)); memset(sendBuf, 0, *sendLen); if (strstr(uPtr->type, "cycletime") == uPtr->type) { // Cycle time if (! *input) { return -1; } if (! (*sendLen = setCycleTime(input, sendBuf))) { return -1; } else { return 1; } } if (strstr(uPtr->type, "systime") == uPtr->type) { // System time if (! (*sendLen = setSysTime(input, sendBuf))) { return -1; } else { return 1; } } else if (strstr(uPtr->type, "enum") == uPtr->type) { // enum if (! *input) { return -1; } if (!(count = text2Enum(uPtr->ePtr, input, &ptr, sendLen))) { sprintf(sendBuf, "Did not find an appropriate enum"); return -1; } else { memcpy(sendBuf, ptr, count); return 1; } } if (! *input) { return -1; } // Here the forwarded value if (uPtr->sCalc && *uPtr->sCalc) { // calc in XML and get defined within floatV = atof(input); inPtr = uPtr->sCalc; logIT(LOG_INFO, "Send Exp: %s [V=%f]", inPtr, floatV); erg = execExpression(&inPtr, dumBuf, floatV, errPtr); if (*errPtr) { logIT(LOG_ERR, "Exec %s: %s", uPtr->sCalc, error); strcpy(sendBuf, string); return -1; } ergType = FLOAT; } if (uPtr->sICalc && *uPtr->sICalc) { // icalc in XML and get defined within inPtr = uPtr->sICalc; if (uPtr->ePtr) { // There are enums if (! *input) { sprintf(sendBuf, "Input missing"); return -1; } if (! (count = text2Enum(uPtr->ePtr, input, &ptr, sendLen))) { sprintf(sendBuf, "Did not find an appropriate enum"); return -1; } else { memset(dumBuf, 0, sizeof(dumBuf)); memcpy(dumBuf, ptr, count); logIT(LOG_INFO, "(INT) Exp: %s [BP:%d]", inPtr, bitpos); ergI = execIExpression(&inPtr, dumBuf, bitpos, pRecvPtr, errPtr); if (*errPtr) { logIT(LOG_ERR, "Exec %s: %s", uPtr->sICalc, error); strcpy(sendBuf, string); return -1; } ergType = INT; snprintf(string, sizeof(string), "Res: (Hex max. 4 bytes) %08x", ergI); } } } // The result is in erg and has to be converted according to the type if (uPtr->type) { if (strstr(uPtr->type, "char") == uPtr->type) { // Conversion to Short 2Byte // According to the CPU, the conversion is done here (ergType == FLOAT) ? (charV = erg) : (charV = ergI); memcpy(sendBuf, &charV, 1); *sendLen = 1; } else if (strstr(uPtr->type, "uchar") == uPtr->type) { // According to the CPU, the conversion is done here (ergType == FLOAT) ? (ucharV = erg) : (ucharV = ergI); memcpy(sendBuf, &ucharV, 1); *sendLen = 1; } else if (strstr(uPtr->type, "short") == uPtr->type) { // According to the CPU, the conversion is done here (ergType == FLOAT) ? (tmpS = erg) : (tmpS = ergI); shortV = __cpu_to_le16(tmpS); memcpy(sendBuf, &shortV, 2); *sendLen = 2; } else if (strstr(uPtr->type, "ushort") == uPtr->type) { // According to the CPU, the conversion is done here (ergType == FLOAT) ? (tmpUS = erg) : (tmpUS = ergI); ushortV = __cpu_to_le16(tmpUS); memcpy(sendBuf, &ushortV, 2); *sendLen = 2; } else if (strstr(uPtr->type, "int") == uPtr->type) { // According to the CPU, the conversion is done here (ergType == FLOAT) ? (tmpI = erg) : (tmpI = ergI); intV = __cpu_to_le32(tmpI); memcpy(sendBuf, &intV, 2); *sendLen = 4; } else if (strstr(uPtr->type, "uint") == uPtr->type) { // According to the CPU, the conversion is done here (ergType == FLOAT) ? (tmpUI = erg) : (tmpUI = ergI); uintV = __cpu_to_le32(tmpUI); memcpy(sendBuf, &uintV, 2); } else if (uPtr->type) { memset(string, 0, sizeof(string)); logIT(LOG_ERR, "Unknown type %s in unit %s", uPtr->type, uPtr->name); return -1; } memset(buffer, 0, sizeof(buffer)); ptr = sendBuf; while (*ptr) { memset(string, 0, sizeof(string)); unsigned char byte = *ptr++ & 255; snprintf(string, sizeof(string), "%02X ", byte); strcat(buffer, string); if (n >= MAXBUF - 3) { // FN: Where is 'n' initialized?! break; } } logIT(LOG_INFO, "Type: %s (bytes: %s) ", uPtr->type, buffer); return 1; } // We should never reach here. But we want to keep the compiler happy. return 0; } 07070100000036000081A4000028240000003200000001607BF448000003BF000000000000000000000000000000000000003200000000vcontrold-v0.98.10+git20210418.977e6f5/src/unit.h/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ #ifndef UNIT_H #define UNIT_H int procGetUnit(unitPtr uPtr, char *recvBuf, int len, char *result, char bitpos, char *pRecvPtr); int procSetUnit(unitPtr uPtr, char *sendBuf, short *sendLen, char bitpos, char *pRecvPtr); #endif // UNIT_H 07070100000037000081A4000028240000003200000001607BF448000058C5000000000000000000000000000000000000003500000000vcontrold-v0.98.10+git20210418.977e6f5/src/vclient.c/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ // Vcontrold client #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <signal.h> #include <syslog.h> #include <unistd.h> #include <termios.h> #include <string.h> #include <time.h> #include <ctype.h> #include <getopt.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/param.h> #include <sys/time.h> #include <sys/ioctl.h> #include "common.h" #include "socket.h" #include "io.h" #include "client.h" #include "vclient.h" #include "version.h" #include "prompt.h" // global variables int inetversion = 0; void usage() { // 1 10 20 30 40 50 60 70 80 printf("usage:\n"); printf(" vclient [-h <ip:port>] [-c <command1,command2,..>] [-f <commandfile>]\n"); printf(" [-s <csv file>] [-t <template file>] [-o <output file>]\n"); printf(" [-x <exec file>] [-k] [-m] [-v] [-j] [-J]\n\n"); printf("or:\n"); printf(" vclient [--host <ip>] [--port <port>] [--command <command1,command2,..>]\n"); printf(" [--commandfile <command file>] [--csvfile <csv file>]\n"); printf(" [--template <template file>] [--output <output file>]\n"); printf(" [--execute <exec file>] [--cacti] [--munin] [--verbose]\n"); printf(" [--json-short] [--json-long]\n"); printf(" [command3 [command4] ...]\n\n"); printf(" -h|--host <IPv4>:<Port> or <IPv6> of vcontrold\n"); printf(" -p|--port <port> of vcontrold when using IPv6\n"); printf(" -c|--command List of commands to be executed, sparated by commas\n"); printf(" -f|--commandfile Optional command file, one command per line\n"); printf(" -s|--csvfile Format output in CSV for further processing\n"); printf(" -t|--template Template, variables are substituted with acquired values\n"); printf(" -o|--output Write to given file instead of STDOUT\n"); printf(" -x|--execute The converted template (cf. -t) is written to the given\n"); printf(" file and executed subsequently\n"); printf(" -m|--munin Output a Munin data logger compatible format (units and\n"); printf(" error details are discarded)\n"); printf(" -k|--cacti Output a Cacti data logger compatible format (units and\n"); printf(" error details are discarded)\n"); printf(" -j|--json-short Output json data (short form, just command and value)\n"); printf(" -J|--json-long Output json data (long form including raw and errors)\n"); printf(" -v|--verbose Be verbose (for testing purposes)\n"); printf(" -V|--Version Print version and exit\n"); printf(" -4|--inet4 IPv4 is preferred\n"); printf(" -6|--inet6 IPv6 is preferred\n"); printf(" (if none of the two above is set, the system default will\n"); printf(" be used)\n"); printf(" --help Display this help message\n\n"); exit(1); } int main(int argc, char *argv[]) { // Get the command line options char *host = NULL; int port = 0; char commands[512] = ""; const char *cmdfile = NULL; const char *csvfile = NULL; const char *tmplfile = NULL; const char *outfile = NULL; char string[1024] = ""; char result[1024] = ""; int sockfd; char dummylog[] = "\0"; int opt; static int verbose = 0; static int munin = 0; static int cacti = 0; static int json_short = 0; static int json_long = 0; short execMe = 0; trPtr resPtr; FILE *filePtr; FILE *ofilePtr; while (1) { static struct option long_options[] = { {"host", required_argument, 0, 'h'}, {"port", required_argument, 0, 'p'}, {"command", required_argument, 0, 'c'}, {"commandfile", required_argument, 0, 'f'}, {"csvfile", required_argument, 0, 's'}, {"template", required_argument, 0, 't'}, {"output", required_argument, 0, 'o'}, {"execute", required_argument, 0, 'x'}, {"verbose", no_argument, &verbose, 1 }, {"Version", no_argument, 0, 0 }, {"munin", no_argument, &munin, 1 }, {"cacti", no_argument, &cacti, 1 }, {"json-short", no_argument, &json_short, 1 }, {"json-long", no_argument, &json_long, 1 }, {"inet4", no_argument, &inetversion, 4 }, {"inet6", no_argument, &inetversion, 6 }, {"help", no_argument, 0, 0 }, {0, 0, 0, 0 } }; // getopt_long stores the option index here. int option_index = 0; opt = getopt_long(argc, argv, "h:p:c:f:s:t:o:x:vVmkjJ46", long_options, &option_index); // Detect the end of the options. if (opt == -1) { break; } switch (opt) { case 0: // If this option sets a flag, we do nothing for now if (long_options[option_index].flag != 0) { break; } if (verbose) { printf("option %s", long_options[option_index].name); if (optarg) { printf(" with arg %s", optarg); } printf("\n"); } if (strcmp("help", long_options[option_index].name) == 0) { usage(); } break; case 'v': puts("option -v\n"); verbose = 1; break; case 'V': printf("vclient version %s\n", VERSION); exit(1); break; case 'm': if (verbose) { puts("option -m\n"); } munin = 1; break; case 'k': if (verbose) { puts("option -k\n"); } cacti = 1; break; case 'j': if (verbose) { puts("option -j\n"); } json_short = 1; break; case 'J': if (verbose) { puts("option -J\n"); } json_long = 1; break; case 'h': if (verbose) { printf("option -h with value `%s'\n", optarg); } host = optarg; break; case 'p': if (verbose) { printf("option -p with value `%s'\n", optarg); } port = atoi(optarg); if (port == 0) { fprintf(stderr, "Invalid value for option --port: %s\n", optarg); usage(); // and exit } break; case 'c': if (verbose) { printf("option -c with value `%s'\n", optarg); printf("sizeof optarg:%zu, strlen:%zu, sizeof commands:%zu, strlen:%zu, [%s]\n", sizeof(optarg), strlen(optarg), sizeof(commands), strlen(commands), commands); } if (strlen(commands) == 0) { strncpy(commands, optarg, sizeof(commands)); } else { if (strlen(optarg) + 2 > sizeof(commands) - strlen(commands)) { fprintf(stderr, "too many commands\n"); break; } strcat(commands, ","); strncat(commands, optarg, sizeof(commands) - strlen(commands) - 2); } break; case 'f': if (verbose) { printf("option -f with value `%s'\n", optarg); } cmdfile = optarg; break; case 's': if (verbose) { printf("option -s with value `%s'\n", optarg); } csvfile = optarg; break; case 't': if (verbose) { printf("option -t with value `%s'\n", optarg); } tmplfile = optarg; break; case 'o': case 'x': if (verbose) { printf("option -%c with value `%s'\n", opt, optarg); } outfile = optarg; if (opt == 'x') { execMe = 1; } break; case '4': if (verbose) { printf("option -%c with value `%s'\n", opt, optarg); } inetversion = 4; break; case '6': if (verbose) { printf("option -%c with value `%s'\n", opt, optarg); } inetversion = 6; break; case '?': // getopt_long already printed an error message. usage(); break; default: abort(); } } if (host == NULL) { host = "localhost"; } // Collect any remaining command line arguments (not options). // and use the as commands like for the -c option. if (optind < argc) { if (verbose) { printf("non-option ARGV-elements: "); } while (optind < argc) { if (verbose) { printf("%s ", argv[optind]); } if (strlen(commands) == 0) { strncpy(commands, argv[optind], sizeof(commands)); } else { if (strlen(argv[optind]) + 2 > sizeof(commands) - strlen(commands)) { fprintf(stderr, "Command list too long\n"); optind++; break; } strcat(commands, ","); strncat(commands, argv[optind], sizeof(commands) - strlen(commands) - 2); } optind++; } if (verbose) { putchar('\n'); } } /* Check for :<port> if port==0 then separate the port number from the host name or the IP adsress. The IP address could be a plain old IPv4 or a IPv6 one, which could contain more than one ':', so that makes a bad separator in the IPv6 case and you better use --port -h 192.168.2.1:3002 vs --host 2003:abcd:ff::1 --port 3002 or --host 2003:abcd:ff::1:3002, assume the last :3002 be the port This is just for backwards compatibility. */ if (port == 0) { // check for last ':' in host char *last_colon = NULL; last_colon = strrchr(host, ':'); if (last_colon != NULL) { port = atoi(last_colon + 1); *last_colon = '\0'; } } if (port == 0) { port = DEFAULT_PORT; } if (verbose) { printf("Host: %s Port: %d\n",host,port); } initLog(0, dummylog, verbose); if (! *commands && !cmdfile) { usage(); } sockfd = connectServer(host, port); if (sockfd < 0) { logIT(LOG_ERR, "No connection to host %s on port %d", host, port); exit(1); } // Give commands directly resPtr = NULL; if (*commands) { resPtr = sendCmds(sockfd, commands); } else if (cmdfile) { resPtr = sendCmdFile(sockfd, cmdfile); } if (! resPtr) { logIT(LOG_ERR, "Error communicating with the server"); exit(1); } disconnectServer(sockfd); if (outfile) { if (! (ofilePtr = fopen(outfile, "w"))) { logIT(LOG_ERR, "Could not create file %s", outfile); exit(1); } memset(string, 0, sizeof(string)); logIT(LOG_INFO, "Output file %s", outfile); } else { ofilePtr = fdopen(fileno(stdout), "w"); } // The result is in the resPtr list, now we differentiate the output if (csvfile) { // Kompakt Format mit Semikolon getrennt if (! (filePtr = fopen(csvfile, "a"))) { logIT(LOG_ERR, "Could not create file %s", csvfile); exit(1); } memset(string, 0, sizeof(string)); memset(result, 0, sizeof(result)); while (resPtr) { if (resPtr->err) { //fprintf(stderr,"%s:%s\n",resPtr->cmd,resPtr->err); fprintf(stderr, "%s: server error\n", resPtr->cmd); strcat(result, ";"); resPtr = resPtr->next; continue; } memset(string, 0, sizeof(string)); sprintf(string, "%f;", resPtr->result); strncat(result, string, sizeof(result) - strlen(result) - 1); resPtr = resPtr->next; } // Remove the last semicolon and add \n if (*result) { *(result + strlen(result) - 1) = '\n'; fputs(result, filePtr); } fclose(filePtr); } else if (tmplfile) { // Template given char line[1000]; char *lptr; char *lSptr; char *lEptr; char varname[20]; unsigned short count; unsigned short idx; unsigned short maxIdx; trPtr tPtr = resPtr; trPtr *idxPtr; short varReplaced; // In array idxPtr, the particular results are referenced via the index for (count = 0; tPtr; tPtr = tPtr->next) { count++; } // We reserve an array with a suitable size idxPtr = calloc(count, sizeof(tPtr)); maxIdx = count; // Biggest index in the variables count = 0; tPtr = resPtr; while (tPtr) { idxPtr[count++] = tPtr; tPtr = tPtr->next; } if (! (filePtr = fopen(tmplfile, "r"))) { logIT(LOG_ERR, "Could not open template file %s", tmplfile); exit(1); } // The following variables are to replace: // $Rn: Result (trPtr->raw) // $n: Float (trPtr->result) while ((fgets(line, sizeof(line) - 1, filePtr))) { logIT(LOG_INFO, "Tmpl line: %s", line); lSptr = line; while ((lptr = strchr(lSptr, '$'))) { varReplaced = 0; if ((lptr > line) && (*(lptr - 1) == '\\')) { // $ is masked by a backslash memset(string, 0, sizeof(string)); strncpy(string, lSptr, lptr - lSptr - 1); fprintf(ofilePtr, "%s%c", string, *lptr); lSptr = lptr + 1; continue; } lEptr = lptr + 1; // Noew, we search the end of the variables. while (isalpha(*lEptr) || isdigit(*lEptr)) { lEptr++; } memset(varname, 0, sizeof(varname)); strncpy(varname, lptr + 1, lEptr - lptr - 1); logIT(LOG_INFO, " Recognized variable: %s", varname); // We output everything up to this memset(string, 0, sizeof(string)); strncpy(string, lSptr, lptr - lSptr); fprintf(ofilePtr, "%s", string); // We differentiate the different variables // $Rn if ((strlen(varname) > 1) && (*varname == 'R') && (idx = atoi(varname + 1))) { // Variable R index then in idx if ((idx - 1) < maxIdx) { tPtr = idxPtr[idx - 1]; logIT(LOG_INFO, "%s:%s", tPtr->cmd, tPtr->raw); if (tPtr->raw) { // if tPtr->raw starts with "ERR:" output only if verbose if (!((verbose == 0) && strncmp(tPtr->raw, ERR, strlen(ERR)) == 0)) { fprintf(ofilePtr, "%s", tPtr->raw); } } } else { logIT(LOG_ERR, "Index of variable $%s > %d", varname, maxIdx - 1); } } // $Cn else if ((strlen(varname) > 1) && (*varname == 'C') && (idx = atoi(varname + 1))) { // Variable R index then in idx if ((idx - 1) < maxIdx) { tPtr = idxPtr[idx - 1]; logIT(LOG_INFO, "Command: %s", tPtr->cmd); if (tPtr->cmd) { fprintf(ofilePtr, "%s", tPtr->cmd); } } else { logIT(LOG_ERR, "Index of Variable $%s > %d", varname, maxIdx - 1); } } // $En else if ((strlen(varname) > 1) && (*varname == 'E') && (idx = atoi(varname + 1))) { // Variable R index then in idx if ((idx - 1) < maxIdx) { tPtr = idxPtr[idx - 1]; logIT(LOG_INFO, "Error: %s: %s", tPtr->cmd, tPtr->err); if (tPtr->err) { fprintf(ofilePtr, "%s", tPtr->err); } else { fprintf(ofilePtr, "OK"); } } else { logIT(LOG_ERR, "Index of variable $%s > %d", varname, maxIdx - 1); } } // $n else if (isdigit(*varname) && (idx = atoi(varname))) { if ((idx - 1) < maxIdx) { tPtr = idxPtr[idx - 1]; logIT(LOG_INFO, "%s:%f", tPtr->cmd, tPtr->result); //if (tPtr->result) fprintf(ofilePtr, "%f", tPtr->result); } else { logIT(LOG_ERR, "Index of variable $%s > %d", varname, maxIdx - 1); } } else { memset(string, 0, sizeof(string)); strncpy(string, lptr, lEptr - lptr); fprintf(ofilePtr, "%s", string); } lSptr = lEptr; } fprintf(ofilePtr, "%s", lSptr); } fclose(filePtr); if (outfile && *outfile && execMe) { // Make the file executable and start fclose(ofilePtr); memset(string, 0, sizeof(string)); logIT(LOG_INFO, "Executing file %s", outfile); if (chmod(outfile, S_IXUSR | S_IRUSR | S_IWUSR) != 0) { logIT(LOG_ERR, "Error chmod +x %s", outfile); exit(1); } short ret; if ((ret = system(outfile)) == -1) { logIT(LOG_ERR, "Error system(%s)", outfile); exit(1); } logIT(LOG_INFO, "Ret Code: %d", ret); exit(ret); } } else if (munin) { // Output Munin format while (resPtr) { fprintf(ofilePtr, "%s.value ", resPtr->cmd); if (resPtr->err) { fprintf(ofilePtr, "U\n"); resPtr = resPtr->next; continue; } if (resPtr->raw) { fprintf(ofilePtr, "%f\n", resPtr->result); } else { fprintf(ofilePtr, "U\n"); } resPtr = resPtr->next; } } else if (cacti) { // Output Cacti format int index = 1; while (resPtr) { fprintf(ofilePtr, "v%d:", index); if (resPtr->err) { fprintf(ofilePtr, "U "); resPtr = resPtr->next; index++; continue; } if (resPtr->raw) { fprintf(ofilePtr, "%f ", resPtr->result); } else { fprintf(ofilePtr, "U "); } index++; resPtr = resPtr->next; } fprintf(ofilePtr, "\n"); } else if (json_short) { // Output JSON format - object with cmd,value pairs int index = 1; fprintf(ofilePtr, "{"); while (resPtr) { fprintf(ofilePtr, "\"%s\":", resPtr->cmd); fprintf(ofilePtr, "%f", resPtr->result); index++; resPtr = resPtr->next; if (resPtr) { fprintf(ofilePtr, ","); } } fprintf(ofilePtr, "}\n"); } else if (json_long) { // Output JSON format list with with objects in it int index = 1; fprintf(ofilePtr,"["); while (resPtr) { fprintf(ofilePtr, "{", resPtr->cmd); fprintf(ofilePtr, "\"command\":\"%s\",", resPtr->cmd); fprintf(ofilePtr, "\"value\":%f,", resPtr->result); fprintf(ofilePtr, "\"raw\":\"%s\",", resPtr->raw); if (resPtr->err) { fprintf(ofilePtr, "\"error\":\"%s\"", resPtr->err); } else { fprintf(ofilePtr, "\"error\":\"\""); } fprintf(ofilePtr, "}"); index++; resPtr = resPtr->next; if (resPtr) { fprintf(ofilePtr, ","); } } fprintf(ofilePtr, "]\n"); } else { while (resPtr) { fprintf(ofilePtr, "%s:\n", resPtr->cmd); if (resPtr->err) { //fprintf(stderr,"%s",resPtr->err); fprintf(stderr, "server error\n"); resPtr = resPtr->next; continue; } if (resPtr->raw) { fprintf(ofilePtr, "%s\n", resPtr->raw); } resPtr = resPtr->next; } } return 0; } 07070100000038000081A4000028240000003200000001607BF4480000030D000000000000000000000000000000000000003500000000vcontrold-v0.98.10+git20210418.977e6f5/src/vclient.h/* Copyright 2007-2017 Frank Nobis <...> 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 <http://www.gnu.org/licenses/>. */ #ifndef VCLIENT_H #define VCLIENT_H extern int inetversion; #endif // VCLIENT_H 07070100000039000081A4000028240000003200000001607BF44800008503000000000000000000000000000000000000003700000000vcontrold-v0.98.10+git20210418.977e6f5/src/vcontrold.c/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ // Vito control daemon for vito queries #define _GNU_SOURCE #include <stdlib.h> #include <stdio.h> #include <ctype.h> #include <errno.h> #include <signal.h> #include <syslog.h> #include <unistd.h> #include <termios.h> #include <string.h> #include <time.h> #include <getopt.h> #include <grp.h> #include <pwd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/time.h> #include <sys/ioctl.h> #include <arpa/inet.h> #include "io.h" #include "common.h" #include "xmlconfig.h" #include "parser.h" #include "socket.h" #include "prompt.h" #include "semaphore.h" #include "framer.h" #ifdef __CYGWIN__ #define XMLFILE "vcontrold.xml" #define INIOUTFILE "sim-%s.ini" #else #define XMLFILE "/etc/vcontrold/vcontrold.xml" #define INIOUTFILE "/tmp/sim-%s.ini" #endif #include "version.h" // Global variables char *xmlfile = XMLFILE; FILE *iniFD = NULL; int makeDaemon = 1; int inetversion = 0; // Defined in xmlconfig.c extern protocolPtr protoPtr; extern unitPtr uPtr; extern devicePtr devPtr; extern configPtr cfgPtr; // Declarations int readCmdFile(char *filename, char *result, int *resultLen, char *device); int interactive(int socketfd, char *device); void printHelp(int socketfd); int rawModus (int socketfd, char *device); static void sigPipeHandler(int signo); static void sigHupHandler(int signo); int reloadConfig(); void usage() { // 1 10 20 30 40 50 60 70 80 printf("usage: vcontrold [-x|--xmlfile xml-file] [-d|--device <device>]\n"); printf(" [-l|--logfile <logfile>] [-p|--port port] [-s|--syslog]\n"); printf(" [-n|--nodaemon] [-v|--verbose] [-V|--Version]\n"); printf(" [-c|--commandfile <command-file>] [-P|--pidfile <pid-file>]"); printf(" [-U|--username <username>] [-G|--groupname <groupname>]\n"); printf(" [-?|--help] [-i|--vsim] [-g|--debug]\n"); printf(" [-4|--inet4] [-6|--inet6]\n\n"); exit(1); } int reloadConfig() { if (parseXMLFile(xmlfile)) { compileCommand(devPtr, uPtr); logIT(LOG_NOTICE, "XML file %s reloaded", xmlfile); return 1; } else { logIT(LOG_ERR, "Loading of XML file %s failed", xmlfile); return 0; } } int readCmdFile(char *filename, char *result, int *resultLen, char *device) { FILE *cmdPtr; char line[MAXBUF]; char string[256]; char recvBuf[MAXBUF]; char *resultPtr = result; int fd; int count = 0; *resultLen = 0; // nothing received yet :-) // Open the device only if we have something to do vcontrol_semget(); if ((fd = framer_openDevice(device, cfgPtr->devPtr->protoPtr->id)) == -1) { vcontrol_semrelease(); logIT(LOG_ERR, "Error opening %s", device); result = "\0"; *resultLen = 0; return 0; } cmdPtr = fopen(filename, "r"); if (! cmdPtr) { logIT(LOG_ERR, "Could not open cmd file %s", filename); result = "\0"; *resultLen = 0; framer_closeDevice(fd); vcontrol_semrelease(); return 0; } logIT(LOG_INFO, "Reading cmd file %s", filename); // Empty queue tcflush(fd, TCIOFLUSH); while (fgets(line, MAXBUF - 1, cmdPtr)) { // Remove \n line[strlen(line) - 1] = '\0'; memset(recvBuf, 0, sizeof(recvBuf)); count = execCmd(line, fd, recvBuf, sizeof(recvBuf)); int n; char *ptr; ptr = recvBuf; char buffer[MAXBUF]; memset(buffer, 0, sizeof(buffer)); for (n = 0; n < count; n++) { // We received characters *resultPtr++ = *ptr; (*resultLen)++; memset(string, 0, sizeof(string)); unsigned char byte = *ptr++ & 255; snprintf(string, sizeof(string), "%02X ", byte); strcat(buffer, string); if (n >= MAXBUF - 3) { break; } } if (count - 1) { // timeout } if (count) { logIT(LOG_INFO, "Received: %s", buffer); } } framer_closeDevice(fd); vcontrol_semrelease(); fclose(cmdPtr); return 1; } void printHelp(int socketfd) { // 10 20 30 40 50 60 70 80 char string[] = " \ close Close connection to device\n \ commands List all commands for the protocol listed in the XML file\n \ debug on|off Toggle debug information\n \ detail <command> Show detailed information about <command>\n \ device The device set in the XML file\n \ protocol Active protocol\n \ raw Raw mode, commands WAIT,SEND,RECV,PAUSE terminated with END\n \ reload Reload XML configuration\n \ unit on|off Toggle conversion to given unit\n \ version Show the version number\n \ quit Close the session\n"; Writen(socketfd, string, strlen(string)); } int rawModus(int socketfd, char *device) { // Here, we write all incoming commands in a temporary file, which is forwarded to readCmdFile char readBuf[MAXBUF]; char string[256]; // FIXME: I think we should be using some PID or such instead of "XXXXXX". #ifdef __CYGWIN__ char tmpfile[] = "vitotmp-XXXXXX"; #else char tmpfile[] = "/tmp/vitotmp-XXXXXX"; #endif FILE *filePtr; char result[MAXBUF]; int resultLen; if (! mkstemp(tmpfile)) { // Another try if (! mkstemp(tmpfile)) { logIT1(LOG_ERR, "Error creating mkstemp"); return 0; } } filePtr = fopen(tmpfile, "w+"); if (! filePtr) { logIT(LOG_ERR, "Could not create temp file %s", tmpfile); return 0; } logIT(LOG_INFO, "Raw mode: Temp file: %s", tmpfile); while (Readline(socketfd, readBuf, sizeof(readBuf))) { // Here, we parse the particular commands if (strstr(readBuf, "END") == readBuf) { fclose(filePtr); resultLen = sizeof(result); readCmdFile(tmpfile, result, &resultLen, device); if (resultLen) { // Re received characters char buffer[MAXBUF]; memset(buffer, 0, sizeof(buffer)); char2hex(buffer, result, resultLen); snprintf(string, sizeof(string), "Result: %s\n", buffer); Writen(socketfd, string, strlen(string)); } remove(tmpfile); return 1; } logIT(LOG_INFO, "Raw: Read: %s", readBuf); if (fputs(readBuf, filePtr) == EOF) { logIT1(LOG_ERR, "Error writing to temp file"); } else { // debug stuff } } return 0; // is this correct? } int interactive(int socketfd, char *device) { char readBuf[1000]; char *readPtr; char bye[] = BYE; char string[256]; commandPtr cPtr; commandPtr pcPtr; int fd = -1; short count = 0; short rcount = 0; short noUnit = 0; char recvBuf[MAXBUF]; char pRecvBuf[MAXBUF]; char sendBuf[MAXBUF]; char cmd[MAXBUF]; char para[MAXBUF]; char *ptr; short sendLen; char buffer[MAXBUF]; Writen(socketfd, PROMPT, strlen(PROMPT)); memset(readBuf, 0, sizeof(readBuf)); while ((rcount = Readline(socketfd, readBuf, sizeof(readBuf)))) { sendErrMsg(socketfd); // Remove control characters readPtr = readBuf + rcount; while (iscntrl(*readPtr)) { *readPtr-- = '\0'; } logIT(LOG_INFO, "Command: %s", readBuf); // We separate the command and possible options at the first blank memset(cmd, 0, sizeof(cmd)); memset(para, 0, sizeof(para)); if ((ptr = strchr(readBuf, ' '))) { strncpy(cmd, readBuf, ptr - readBuf); strcpy(para, ptr + 1); } else { strcpy(cmd, readBuf); } // Here, the particular commands are parsed if (strstr(readBuf, "help") == readBuf) { printHelp(socketfd); } else if (strstr(readBuf, "quit") == readBuf) { Writen(socketfd, bye, strlen(bye)); framer_closeDevice(fd); vcontrol_semrelease(); return 1; } else if (strstr(readBuf, "debug on") == readBuf) { setDebugFD(socketfd); } else if (strstr(readBuf, "debug off") == readBuf) { setDebugFD(-1); } else if (strstr(readBuf, "unit off") == readBuf) { noUnit = 1; } else if (strstr(readBuf, "unit on") == readBuf) { noUnit = 0; } else if (strstr(readBuf, "reload") == readBuf) { if (reloadConfig()) { memset(string, 0, sizeof(string)); snprintf(string, sizeof(string), "XML file %s reloaded\n", xmlfile); Writen(socketfd, string, strlen(string)); // If we have a parent (daemon mode), it reveives a SIGHUP if (makeDaemon) { kill(getppid(), SIGHUP); } } else { memset(string, 0, sizeof(string)); snprintf(string, sizeof(string), "Loading of XML file %s failed, using old configuration\n", xmlfile); Writen(socketfd, string, strlen(string)); } } else if (strstr(readBuf, "raw") == readBuf) { rawModus(socketfd, device); } else if (strstr(readBuf, "close") == readBuf) { framer_closeDevice(fd); vcontrol_semrelease(); snprintf(string, sizeof(string), "%s closed\n", device); Writen(socketfd, string, strlen(string)); fd = -1; } else if (strstr(readBuf, "commands") == readBuf) { cPtr = cfgPtr->devPtr->cmdPtr; while (cPtr) { if (cPtr->addr) { memset(string, 0, sizeof(string)); snprintf(string, sizeof(string), "%s: %s\n", cPtr->name, cPtr->description); Writen(socketfd, string, strlen(string)); } cPtr = cPtr->next; } } else if (strstr(readBuf, "protocol") == readBuf) { memset(string, 0, sizeof(string)); snprintf(string, sizeof(string), "%s\n", cfgPtr->devPtr->protoPtr->name); Writen(socketfd, string, strlen(string)); } else if (strstr(readBuf, "device") == readBuf) { memset(string, 0, sizeof(string)); snprintf(string, sizeof(string), "%s (ID=%s) (Protocol=%s)\n", cfgPtr->devPtr->name, cfgPtr->devPtr->id, cfgPtr->devPtr->protoPtr->name); Writen(socketfd, string, strlen(string)); } else if (strstr(readBuf, "version") == readBuf) { memset(string, 0, sizeof(string)); snprintf(string, sizeof(string), "Version: %s\n", VERSION); Writen(socketfd, string, strlen(string)); } else if ((cPtr = getCommandNode(cfgPtr->devPtr->cmdPtr, cmd)) && (cPtr->addr)) { // The command is defined in XML, so we take care of it ... memset(string, 0, sizeof(string)); memset(recvBuf, 0, sizeof(recvBuf)); memset(sendBuf, 0, sizeof(sendBuf)); memset(pRecvBuf, 0, sizeof(pRecvBuf)); // If unit off is set or no unit is defined, we pass the parameters in hex memset(sendBuf, 0, sizeof(sendBuf)); if ((noUnit || !cPtr->unit) && *para) { if ((sendLen = string2chr(para, sendBuf, sizeof(sendBuf))) == -1) { logIT(LOG_ERR, "No hex string: %s", para); sendErrMsg(socketfd); if (! Writen(socketfd, PROMPT, strlen(PROMPT))) { sendErrMsg(socketfd); framer_closeDevice(fd); vcontrol_semrelease(); return 0; } continue; } // If sendLen > len of the command, we use len if (sendLen > cPtr->len) { logIT(LOG_WARNING, "Length of the hex string > send length of the command, sending only %d bytes", cPtr->len); sendLen = cPtr->len; } } else if (*para) { // We copy the parameter, execByteCode itself takes care of it strcpy(sendBuf, para); sendLen = strlen(sendBuf); } if (iniFD) { fprintf(iniFD, ";%s\n", readBuf); } // We only open the device if we have something to do. But only if it's not open yet. if (fd < 0) { /* As one vclient call opens the link once, all is seen a transaction * This may cause trouble for telnet sessions, as the whole session is * one link activity, even more commands are given within. * This is related to a accept/close on a server socket */ // everything on link is a transaction - all commands vcontrol_semget(); if ((fd = framer_openDevice(device, cfgPtr->devPtr->protoPtr->id)) == -1) { logIT(LOG_ERR, "Error opening %s", device); sendErrMsg(socketfd); framer_closeDevice(fd); vcontrol_semrelease(); if (!Writen(socketfd, PROMPT, strlen(PROMPT))) { sendErrMsg(socketfd); return 0; } continue; } } // If there's a pre command, we execute this first if (cPtr->precmd && (pcPtr = getCommandNode(cfgPtr->devPtr->cmdPtr, cPtr->precmd))) { logIT(LOG_INFO, "Executing pre command %s", cPtr->precmd); if (execByteCode(pcPtr->cmpPtr, fd, pRecvBuf, sizeof(pRecvBuf), sendBuf, sendLen, 1, pcPtr->bit, pcPtr->retry, pRecvBuf, pcPtr->recvTimeout) == -1) { logIT(LOG_ERR, "Error executing %s", readBuf); sendErrMsg(socketfd); break; } else { memset(buffer, 0, sizeof(buffer)); char2hex(buffer, pRecvBuf, pcPtr->len); logIT(LOG_INFO, "Result of pre command: %s", buffer); } } // We execute the bytecode: // -1: Error // 0: Preformatted string // n: raw bytes count = execByteCode(cPtr->cmpPtr, fd, recvBuf, sizeof(recvBuf), sendBuf, sendLen, noUnit, cPtr->bit, cPtr->retry, pRecvBuf, cPtr->recvTimeout); if (count == -1) { logIT(LOG_ERR, "Error executing %s", readBuf); sendErrMsg(socketfd); } else if (*recvBuf && (count == 0)) { // Unit converted logIT1(LOG_INFO, recvBuf); snprintf(string, sizeof(string), "%s\n", recvBuf); Writen(socketfd, string, strlen(string)); } else { int n; char *ptr; ptr = recvBuf; char buffer[MAXBUF]; memset(buffer, 0, sizeof(buffer)); for (n = 0; n < count; n++) { // We received a character memset(string, 0, sizeof(string)); unsigned char byte = *ptr++ & 255; snprintf(string, sizeof(string), "%02X ", byte); strcat(buffer, string); if (n >= MAXBUF - 3) { break; } } if (count) { snprintf(string, sizeof(string), "%s\n", buffer); Writen(socketfd, string, strlen(string)); logIT(LOG_INFO, "Received: %s", buffer); } } if (iniFD) { fflush(iniFD); } } else if (strstr(readBuf, "detail") == readBuf) { readPtr = readBuf + strlen("detail"); while (isspace(*readPtr)) { readPtr++; } // Is the command defined in the XML? if (readPtr && (cPtr = getCommandNode(cfgPtr->devPtr->cmdPtr, readPtr))) { memset(string, 0, sizeof(string)); snprintf(string, sizeof(string), "%s: %s\n", cPtr->name, cPtr->send); Writen(socketfd, string, strlen(string)); // Error String defined char buf[MAXBUF]; memset(buf, 0, sizeof(buf)); if (cPtr->errStr && char2hex(buf, cPtr->errStr, cPtr->len)) { snprintf(string, sizeof(string), "\tError at (Hex): %s", buf); Writen(socketfd, string, strlen(string)); } // recvTimeout? if (cPtr->recvTimeout) { snprintf(string, sizeof(string), "\tRECV Timeout: %d ms\n", cPtr->recvTimeout); Writen(socketfd, string, strlen(string)); } // Retry defined? if (cPtr->retry) { snprintf(string, sizeof(string), "\tRetry: %d\n", cPtr->retry); Writen(socketfd, string, strlen(string)); } // Is Bit defined? if (cPtr->bit > 0) { snprintf(string, sizeof(string), "\tBit (BP): %d\n", cPtr->bit); Writen(socketfd, string, strlen(string)); } // Pre command defined? if (cPtr->precmd) { snprintf(string, sizeof(string), "\tPre command (P0-P9): %s\n", cPtr->precmd); Writen(socketfd, string, strlen(string)); } // If a unit has been given, we also output it compilePtr cmpPtr; cmpPtr = cPtr->cmpPtr; while (cmpPtr) { if (cmpPtr && cmpPtr->uPtr) { // Unit gefunden char *gcalc; char *scalc; // We differentiate the calculation by get and setaddr if (cmpPtr->uPtr->gCalc && *cmpPtr->uPtr->gCalc) { gcalc = cmpPtr->uPtr->gCalc; } else { gcalc = cmpPtr->uPtr->gICalc; } if (cmpPtr->uPtr->sCalc && *cmpPtr->uPtr->sCalc) { scalc = cmpPtr->uPtr->sCalc; } else { scalc = cmpPtr->uPtr->sICalc; } snprintf(string, sizeof(string), "\tUnit: %s (%s)\n\t Type: %s\n\t Get-Calc: %s\n\t \ Set-Calc: %s\n\t Einheit: %s\n", cmpPtr->uPtr->name, cmpPtr->uPtr->abbrev, cmpPtr->uPtr->type, gcalc, scalc, cmpPtr->uPtr->entity); Writen(socketfd, string, strlen(string)); // If it's an enum, is the more? if (cmpPtr->uPtr->ePtr) { enumPtr ePtr; ePtr = cmpPtr->uPtr->ePtr; char dummy[20]; while (ePtr) { memset(dummy, 0, sizeof(dummy)); if (!ePtr->bytes) { strcpy(dummy, "<default>"); } else { char2hex(dummy, ePtr->bytes, ePtr->len); } snprintf(string, sizeof(string), "\t Enum Bytes: %s Text: %s\n", dummy, ePtr->text); Writen(socketfd, string, strlen(string)); ePtr = ePtr->next; } } } cmpPtr = cmpPtr->next; } } else { memset(string, 0, sizeof(string)); snprintf(string, sizeof(string), "ERR: command %s unknown\n", readPtr); Writen(socketfd, string, strlen(string)); } } else if (*readBuf) { if (!Writen(socketfd, UNKNOWN, strlen(UNKNOWN))) { sendErrMsg(socketfd); framer_closeDevice(fd); vcontrol_semrelease(); return 0; } } sendErrMsg(socketfd); if (!Writen(socketfd, PROMPT, strlen(PROMPT))) { sendErrMsg(socketfd); framer_closeDevice(fd); vcontrol_semrelease(); return 0; } memset(readBuf, 0, sizeof(readBuf)); } sendErrMsg(socketfd); framer_closeDevice(fd); vcontrol_semrelease(); return 0; } static void sigPipeHandler(int signo) { logIT1(LOG_ERR, "Received SIGPIPE"); // FIXME: And we do nothing here? Why do we handle it then? } static void sigHupHandler(int signo) { logIT1(LOG_NOTICE, "Received SIGHUP"); reloadConfig(); } char *pidFile = NULL; static void sigTermHandler(int signo) { if (signo == SIGTERM) { logIT1(LOG_NOTICE, "Received SIGTERM"); } else if (signo == SIGINT) { logIT1(LOG_NOTICE, "Received SIGINT"); } else if (signo == SIGQUIT) { logIT1(LOG_NOTICE, "Received SIGQUIT"); } else { logIT(LOG_NOTICE, "Received signal %d", signo); } vcontrol_semfree(); if (pidFile) { unlink(pidFile); } exit(1); } // Here we go int main(int argc, char *argv[]) { // Parse the command line options char *device = NULL; char *cmdfile = NULL; char *logfile = NULL; char *username = NULL; char *groupname = NULL; static int useSyslog = 0; static int debug = 0; static int verbose = 0; int tcpport = 0; static int simuOut = 0; int opt; while (1) { static struct option long_options[] = { {"commandfile", required_argument, 0, 'c'}, {"device", required_argument, 0, 'd'}, {"debug", no_argument, &debug, 1 }, {"vsim", no_argument, &simuOut, 1 }, {"logfile", required_argument, 0, 'l'}, {"pidfile", required_argument, 0, 'P'}, {"username", required_argument, 0, 'U'}, {"groupname", required_argument, 0, 'G'}, {"nodaemon", no_argument, &makeDaemon, 0 }, {"port", required_argument, 0, 'p'}, {"syslog", no_argument, &useSyslog, 1 }, {"xmlfile", required_argument, 0, 'x'}, {"verbose", no_argument, &verbose, 1 }, {"Version", no_argument, 0, 0 }, {"inet4", no_argument, &inetversion, 4 }, {"inet6", no_argument, &inetversion, 6 }, {"help", no_argument, 0, 0 }, {0, 0, 0, 0 } }; // getopt_long stores the option index here. int option_index = 0; opt = getopt_long (argc, argv, "c:d:gil:P:U:G:np:sx:vV46", long_options, &option_index); // Detect the end of the options. if (opt == -1) { break; } switch (opt) { case 0: // If this option sets a flag, we do nothing for now if (long_options[option_index].flag != 0) { break; } if (verbose) { printf("option %s", long_options[option_index].name); if (optarg) { printf(" with arg %s", optarg); } printf("\n"); } if (strcmp("help", long_options[option_index].name) == 0) { usage(); } break; case '4': inetversion = 4; break; case '6': inetversion = 6; break; case 'c': cmdfile = optarg; break; case 'd': device = optarg; break; case 'g': debug = 1; break; case 'i': simuOut = 1; break; case 'l': logfile = optarg; break; case 'P': pidFile = optarg; break; case 'U': username = optarg; break; case 'G': groupname = optarg; break; case 'n': makeDaemon = 0; break; case 'p': tcpport = atoi(optarg); break; case 's': useSyslog = 1; break; case 'v': puts ("option -v\n"); verbose = 1; break; case 'V': printf("vcontrold version %s\n", VERSION); exit(1); break; case 'x': xmlfile = optarg; break; case '?': // getopt_long already printed an error message. usage(); break; default: abort(); } } initLog(useSyslog, logfile, debug); logIT(LOG_NOTICE, "started vcontrold version %s", VERSION); if (!parseXMLFile(xmlfile)) { fprintf(stderr, "Error loading %s, terminating\n", xmlfile); exit(1); } // The global variables cfgPtr and protoPtr have been filled if (cfgPtr) { if (! tcpport) { tcpport = cfgPtr->port; } if (! device) { device = cfgPtr->tty; } if (! logfile) { logfile = cfgPtr->logfile; } if (! pidFile) { pidFile = cfgPtr->pidfile; } if (! username) { username = cfgPtr->username; } if (! groupname) { groupname = cfgPtr->groupname; } if (! useSyslog) { useSyslog = cfgPtr->syslog; } if (! debug) { debug = cfgPtr->debug; } } if (!initLog(useSyslog, logfile, debug)) { exit(1); } if (signal(SIGHUP, sigHupHandler) == SIG_ERR) { logIT1(LOG_ERR, "Error handling SIGHUP"); exit(1); } if (signal(SIGQUIT, sigTermHandler) == SIG_ERR) { logIT(LOG_ERR, "Error handling SIGQUIT: %s", strerror(errno)); exit(1); } if (signal(SIGINT, sigTermHandler) == SIG_ERR) { logIT(LOG_ERR, "Error handling SIGINT: %s", strerror(errno)); exit(1); } if (signal(SIGTERM, sigTermHandler) == SIG_ERR) { logIT(LOG_ERR, "Error handling SIGTERM: %s", strerror(errno)); exit(1); } // If -i has been given, we log the commands in Simulator INI format if (simuOut) { char file[100]; snprintf(file, sizeof(file), INIOUTFILE, cfgPtr->devID); if (! (iniFD = fopen(file, "w"))) { logIT(LOG_ERR, "Could not create simulator INI file %s", file); } fprintf(iniFD, "[DATA]\n"); } // The macros are replaced and the strings to send are converted to bytecode compileCommand(devPtr, uPtr); int fd = 0; char result[MAXBUF]; int resultLen = sizeof(result); int sid; int pidFD = 0; char str[10]; if (tcpport) { if (makeDaemon) { int pid; // Some siganl handling if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) { logIT1(LOG_ERR, "Error handling SIGCHLD"); } pid = fork(); if (pid < 0) { logIT(LOG_ERR, "fork failed (%d)", pid); exit(1); } if (pid > 0) { exit(0); // Parent is terminated, child runs on } // From here, only the child is running // Close FD close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); umask(0); sid = setsid(); if (sid < 0) { logIT1(LOG_ERR, "setsid failed"); exit(1); } if (chdir("/") < 0) { logIT1(LOG_ERR, "chdir / failed"); exit(1); } if (pidFile) { pidFD = open(pidFile, O_RDWR | O_CREAT, 0600); if (pidFD == -1) { logIT(LOG_ERR, "Could not open PID lock file %s, exiting", pidFile); exit(1); } if (lockf(pidFD, F_TLOCK, 0) == -1) { logIT(LOG_ERR, "Could not lock PID lock file %s, exiting", pidFile); exit(1); } sprintf(str, "%d\n", getpid()); write(pidFD, str, strlen(str)); } } int sockfd = -1; int listenfd = openSocket(tcpport); // Drop privileges after binding if (0 == getuid()) { struct passwd *pw; struct group *grp; struct stat stb; if (username == NULL) { username = strdup("nobody"); } pw = getpwnam(username); if (pw == NULL) { int errsv = errno; logIT(LOG_ERR, "Error while dropping privileges: calling getpwnam(\"%s\") failed with errno %d", username, errsv); exit(1); } if (groupname == NULL) { groupname = strdup("dialout"); } grp = getgrnam(groupname); if (grp == NULL) { int errsv = errno; logIT(LOG_ERR, "Error while dropping privileges: calling getgrnam(\"%s\") failed with errno %d", groupname, errsv); exit(1); } // Make logfile accessible to the anticipated user/group if (stat(logfile, &stb) == 0) { chmod(logfile, stb.st_mode | S_IRGRP | S_IWGRP); chown(logfile, pw->pw_uid, grp->gr_gid); } // Make lock file accessible to the anticipated user/group if (stat(tmpfilename, &stb) == 0) { chmod(tmpfilename, stb.st_mode | S_IRGRP | S_IWGRP); chown(tmpfilename, pw->pw_uid, grp->gr_gid); } if (setgroups(0, NULL) != 0) { int errsv = errno; logIT(LOG_ERR, "Error while dropping privileges: calling setgroups(0, NULL) failed with errno %d", errsv); exit(1); } if (setgid(grp->gr_gid) != 0) { int errsv = errno; logIT(LOG_ERR, "Error while dropping privileges: calling setgid(%d) failed with errno %d", grp->gr_gid, errsv); exit(1); } if (setuid(pw->pw_uid) != 0) { int errsv = errno; logIT(LOG_ERR, "Error while dropping privileges: calling setuid(%d) failed with errno %d", pw->pw_uid, errsv); exit(1); } logIT(LOG_INFO, "Dropped privileges, now running with effective user ID %d, group ID %d", geteuid(), getegid()); } else { if (username || groupname) { logIT1(LOG_INFO, "Not started as root, username/groupname settings ignored"); } } vcontrol_seminit(); while (1) { sockfd = listenToSocket(listenfd, makeDaemon); if (signal(SIGPIPE, sigPipeHandler) == SIG_ERR) { logIT1(LOG_ERR, "Signal error"); exit(1); } if (sockfd >= 0) { // Socket returned fd, the rest is done interactively interactive(sockfd, device); closeSocket(sockfd); setDebugFD(-1); if (makeDaemon) { logIT(LOG_INFO, "Child process with PID %d terminated", getpid()); exit(0); // The child bids boodbye } } else { logIT1(LOG_ERR, "Error connecting"); } } } else { vcontrol_seminit(); } if (*cmdfile) { readCmdFile(cmdfile, result, &resultLen, device); } vcontrol_semfree(); close(fd); if (pidFile) { close(pidFD); unlink(pidFile); }; logIT1(LOG_LOCAL0, "vcontrold terminated"); return 0; } 0707010000003A000081A4000028240000003200000001607BF4480000031A000000000000000000000000000000000000003800000000vcontrold-v0.98.10+git20210418.977e6f5/src/version.h.in/* Copyright (c) 2017 Tobias Leupold <tobias.leupold@gmx.de> 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 <http://www.gnu.org/licenses/>. */ #ifndef VERSION_H #define VERSION_H #define VERSION "@VERSION@" #endif // VERSION_H 0707010000003B000081A4000028240000003200000001607BF4480000132E000000000000000000000000000000000000003200000000vcontrold-v0.98.10+git20210418.977e6f5/src/vsim.c/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ #define _GNU_SOURCE #include <stdlib.h> #include <stdio.h> #include <ctype.h> #include <errno.h> #include <signal.h> #include <syslog.h> #include <unistd.h> #include <termios.h> #include <string.h> #include <time.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/time.h> #include <sys/ioctl.h> #include <arpa/inet.h> #include <stdarg.h> #include "socket.h" #include "vclient.h" #define SERVERPORT 6578 int makeDaemon = 0; int inetversion = 0; int readCmdFile(char *filename, char *result, int *resultLen, char *device ); int interactive(int socketfd, char *device); void printHelp(int socketfd); int rawModus (int socketfd, char *device); static void sigPipeHandler(int signo); void logIT (int class, char *string, ...) { va_list arguments; char *print_buffer; va_start(arguments, string); vasprintf(&print_buffer, string, arguments); va_end(arguments); printf("%s\n", print_buffer); free(print_buffer); } static void sigPipeHandler(int signo) { logIT(LOG_ERR, "Received SIGPIPE"); } static void dump(char *buf, int len, char *txt) { int i = 0; printf("%s:\n", txt); for (i = 0; i < len; i++) { printf(" %02x", (unsigned char)buf[i]); } printf("\n"); } typedef struct { int cmdlen; char cmd[20]; int rsplen; char rsp[20]; } ctable; int cmdc = 9; ctable cmds[] = { { 1, { 0x04 }, 1, { 0x05 } }, { 3, { 0x16, 0x00, 0x00 }, 1, { 0x06 } }, { 5, { 0x01, 0xf7, 0xcb, 0x70, 01 }, 2, {0x30, 0x00 } }, { 8, { 0x41, 0x05, 0x00, 0x01, 0x55, 0x25, 0x02, 0x82 }, 11, { 0x06, 0x41, 0x07, 0x01, 0x01, 0x55, 0x25, 0x02, 0x07, 0x01, 0x8D } }, { 8, { 0x41, 0x05, 0x00, 0x01, 0x08, 0x00, 0x02, 0x10 }, 11, { 0x06, 0x41, 0x07, 0x01, 0x01, 0x08, 0x00, 0x02, 0x07, 0x01, 0x1B } }, { 8, { 0x41, 0x05, 0x00, 0x01, 0x21, 0x10, 0x08, 0x3F }, 16, { 0x06, 0x41, 0x0D, 0x01, 0x01, 0x21, 0x10, 0x08, 0x28, 0xB0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }, { 5, { 0x01, 0xf7, 0x08, 0x00, 0x02 }, 2, { 0x07, 0x01 } }, { 8, { 0x41, 0x05, 0x00, 0x01, 0x08, 0x04, 0x02, 0x14 }, 11, { 0x06, 0x41, 0x07, 0x01, 0x01, 0x08, 0x04, 0x02, 0x00, 0x00, 0x17 } }, }; char input[100]; char inpidx = 0; static void handle(int fd) { char buf[1] = "\0"; ssize_t len; while ( 1 ) { len = readn(fd, buf, 1); if (len < 0) { perror("read eror\n"); exit(-1); } else if (len == 0) { printf("eof read\n"); return; } else { int i = 0; int j = 0; while ( i < len ) { input[inpidx] = buf[i]; dump(&input[inpidx], 1, "received char:"); inpidx++; for ( j = 0 ; j < cmdc; j++) { if ( cmds[j].cmd[0] == input[0] ) { if (( cmds[j].cmdlen == inpidx) && (!memcmp(cmds[j].cmd, input, inpidx))) { dump(input, inpidx, "received cmd:"); dump(cmds[j].rsp, cmds[j].rsplen, "answer:"); if (writen(fd, cmds[j].rsp, cmds[j].rsplen) != cmds[j].rsplen) { printf("not completely written\n"); } inpidx = 0; } } } i++; } } } } int main(int argc, char *argv[]) { int sockfd = -1; int listenfd = -1; listenfd = openSocket(SERVERPORT); while (1) { sockfd = listenToSocket(listenfd, makeDaemon); if (signal(SIGPIPE, sigPipeHandler) == SIG_ERR) { logIT(LOG_ERR, "Signal error"); exit(1); } if (sockfd >= 0) { // Socket returned fd, the rest is done interactively logIT(LOG_INFO, "\nvcontrold connected"); handle(sockfd); logIT(LOG_INFO, "\nvcontrold disconnected"); closeSocket(sockfd); } else { logIT(LOG_ERR, "Error during connection setup"); } } } 0707010000003C000081A4000028240000003200000001607BF4480000BBD6000000000000000000000000000000000000003700000000vcontrold-v0.98.10+git20210418.977e6f5/src/xmlconfig.c/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ // Routines for reading XML files #include <stdlib.h> #include <stdio.h> #include <string.h> #include <syslog.h> #include <libxml/parser.h> #include <libxml/xinclude.h> #include <arpa/inet.h> #include "xmlconfig.h" #include "common.h" #include "parser.h" #if defined(__FreeBSD__) #include <netinet/in.h> #endif // Declarations protocolPtr newProtocolNode(protocolPtr ptr); char *getPropertyNode(xmlAttrPtr cur, xmlChar *name); enumPtr newEnumNode(enumPtr ptr); void removeProtocolList(protocolPtr ptr); void removeUnitList(unitPtr ptr); void removeMacroList(macroPtr ptr); void removeCommandList(commandPtr ptr); void removeDeviceList(devicePtr ptr); void removeIcmdList(icmdPtr ptr); void removeEnumList(enumPtr ptr); void freeAllLists(); // Globale variables protocolPtr protoPtr = NULL; unitPtr uPtr = NULL; devicePtr devPtr = NULL; configPtr cfgPtr = NULL; commandPtr cmdPtr = NULL; protocolPtr newProtocolNode(protocolPtr ptr) { protocolPtr nptr; if (ptr && ptr->next) { return newProtocolNode(ptr->next); } nptr = calloc(1, sizeof(Protocol)); if (! nptr) { fprintf(stderr, "malloc failed\n"); exit(1); } if (ptr) { ptr->next = nptr; } nptr->next = NULL; nptr->icPtr = NULL; nptr->id = 0; return nptr; } protocolPtr getProtocolNode(protocolPtr ptr, const char *name) { if (! ptr) { return NULL; } if (strcmp(ptr->name, name) != 0) { return getProtocolNode(ptr->next, name); } return ptr; } void removeProtocolList(protocolPtr ptr) { if (ptr && ptr->next) { removeProtocolList(ptr->next); } if (ptr) { removeMacroList(ptr->mPtr); removeIcmdList(ptr->icPtr); free(ptr->name); free(ptr); } } unitPtr newUnitNode(unitPtr ptr) { unitPtr nptr; if (ptr && ptr->next) { return newUnitNode(ptr->next); } nptr = calloc(1, sizeof(Unit)); if (! nptr) { fprintf(stderr, "malloc failed\n"); exit(1); } if (ptr) { ptr->next = nptr; } nptr->next = NULL; return nptr; } unitPtr getUnitNode(unitPtr ptr, const char *name) { if (! ptr) { return NULL; } if (ptr->abbrev && (strcmp(ptr->abbrev, name) != 0)) { return getUnitNode(ptr->next, name); } return ptr; } void removeUnitList(unitPtr ptr) { if (ptr && ptr->next) { removeUnitList(ptr->next); } if (ptr) { removeEnumList(ptr->ePtr); free(ptr->name); free(ptr->abbrev); free(ptr->gCalc); free(ptr->sCalc); free(ptr->gICalc); free(ptr->sICalc); free(ptr->entity); free(ptr->type); free(ptr); } } macroPtr newMacroNode(macroPtr ptr) { macroPtr nptr; if (ptr && ptr->next) { return newMacroNode(ptr->next); } nptr = calloc(1, sizeof(Macro)); if (! nptr) { fprintf(stderr, "malloc failed\n"); exit(1); } if (ptr) { ptr->next = nptr; } nptr->next = NULL; return nptr; } macroPtr getMacroNode(macroPtr ptr, const char *name) { if (! ptr) { return NULL; } if (ptr->name && strcmp(ptr->name, name) != 0) { //if (*name && !(strstr(ptr->name,name)==ptr->name)) return getMacroNode(ptr->next, name); } return ptr; } void removeMacroList(macroPtr ptr) { if (ptr && ptr->next) { removeMacroList(ptr->next); } if (ptr) { free(ptr->name); free(ptr->command); free(ptr); } } commandPtr newCommandNode(commandPtr ptr) { commandPtr nptr; if (ptr && ptr->next) { return newCommandNode(ptr->next); } nptr = calloc(1, sizeof(Command)); if (! nptr) { fprintf(stderr, "malloc failed\n"); exit(1); } if (ptr) { ptr->next = nptr; } nptr->next = NULL; nptr->cmpPtr = NULL; nptr->bit = -1; return nptr; } void addCommandNode(commandPtr ptr, commandPtr nptr) { if (! ptr) { return; } else if (ptr->next) { addCommandNode(ptr->next, nptr); } else { ptr->next = nptr; } } commandPtr getCommandNode(commandPtr ptr, const char *name) { if (! ptr) { return NULL; } if (ptr->name && name && (strcmp(ptr->name, name) != 0)) { return getCommandNode(ptr->next, name); } return ptr; } void removeCommandList(commandPtr ptr) { if (ptr && ptr->next) { removeCommandList(ptr->next); } if (ptr) { removeCompileList(ptr->cmpPtr); free(ptr->send); if (ptr->nodeType > 0) { // Has been read from the XML file if (ptr->addr) { free(ptr->addr); } if (ptr->precmd) { free(ptr->precmd); } if (ptr->unit) { free(ptr->unit); } if (ptr->pcmd) { free(ptr->pcmd); } if (ptr->errStr) { free(ptr->errStr); } if (ptr->nodeType == 1) { // Originalknoten if (ptr->name) { free(ptr->name); } if (ptr->description) { free(ptr->description); } } } free(ptr); } } devicePtr newDeviceNode(devicePtr ptr) { devicePtr nptr; if (ptr && ptr->next) { return newDeviceNode(ptr->next); } nptr = calloc(1, sizeof(Device)); if (! nptr) { fprintf(stderr, "malloc failed\n"); exit(1); } if (ptr) { ptr->next = nptr; } nptr->next = NULL; return nptr; } devicePtr getDeviceNode(devicePtr ptr, char *id) { if (! ptr) { return NULL; } if (strcmp(ptr->id, id) != 0) { return getDeviceNode(ptr->next, id); } return ptr; } void removeDeviceList(devicePtr ptr) { if (ptr && ptr->next) { removeDeviceList(ptr->next); } if (ptr) { removeCommandList(ptr->cmdPtr); free(ptr->name); free(ptr->id); free(ptr); } } icmdPtr newIcmdNode(icmdPtr ptr) { icmdPtr nptr; if (ptr && ptr->next) { return newIcmdNode(ptr->next); } nptr = calloc(1, sizeof(iCmd)); if (! nptr) { fprintf(stderr, "malloc failed\n"); exit(1); } if (ptr) { ptr->next = nptr; } nptr->next = NULL; return nptr; } icmdPtr getIcmdNode(icmdPtr ptr, const char *name) { if (! ptr) { return NULL; } if (ptr->name && (strcmp(ptr->name, name) != 0)) { return getIcmdNode(ptr->next, name); } return ptr; } void removeIcmdList(icmdPtr ptr) { if (ptr && ptr->next) { removeIcmdList(ptr->next); } if (ptr) { free(ptr->name); free(ptr->send); free(ptr); } } enumPtr newEnumNode(enumPtr ptr) { enumPtr nptr; if (ptr && ptr->next) { return newEnumNode(ptr->next); } nptr = calloc(1, sizeof(Enumerate)); if (! nptr) { fprintf(stderr, "malloc failed\n"); exit(1); } if (ptr) { ptr->next = nptr; } return nptr; } enumPtr getEnumNode(enumPtr ptr, char *search, int len) { if (! ptr) { return NULL; } if ((len > 0) && ptr->bytes && (memcmp(ptr->bytes, search, len) == 0)) { // len given, we search for bytes return ptr; } else if (!len && ptr->text && (strcmp(ptr->text, search) == 0)) { // len == 0 --> string comparison return ptr; } else if ((len < 0) && (ptr->bytes == NULL)) { // len == -1 --> default value return ptr; } else { return getEnumNode(ptr->next, search, len); } } void removeEnumList(enumPtr ptr) { if (ptr && ptr->next) { removeEnumList(ptr->next); } if (ptr) { free(ptr->text); free(ptr->bytes); free(ptr); } } void printNode(xmlNodePtr ptr) { static int blanks = 0; int n; if (! ptr) { return; } for (n = 0; n <= blanks; n++) { printf(" "); } if ((ptr->type == XML_ELEMENT_NODE) || (ptr->type == XML_TEXT_NODE)) { printf("(%d) Node::Name=%s Type:%d Content=%s\n", ptr->line, ptr->name, ptr->type, ptr->content); } else { printf("Node::Name=%s\n", ptr->name); } if ((ptr->type == XML_ELEMENT_NODE) && ptr->properties) { blanks++; printNode((xmlNodePtr) ptr->properties); blanks--; } if (ptr->children) { blanks++; printNode(ptr->children); blanks--; } if ( ptr->next) { printNode(ptr->next); } } char *getTextNode(xmlNodePtr cur) { if ((cur->children) && (cur->children->type == XML_TEXT_NODE)) { return (char *)cur->children->content; } else { return NULL; } } char *getPropertyNode(xmlAttrPtr cur, xmlChar *name) { if ((cur) && (cur->type == XML_ATTRIBUTE_NODE) && strstr((char *)cur->name, (char *)name)) { return (char *)getTextNode((xmlNodePtr) cur); } else if (cur && cur->next) { return (char *)getPropertyNode(cur->next, name); } else { return NULL; } } void nullIT(char **ptr) { *ptr = calloc(1, sizeof(char)); **ptr = '\0'; } configPtr parseConfig(xmlNodePtr cur) { int serialFound = 0; int netFound = 0; int logFound = 0; configPtr cfgPtr; char *chrPtr; xmlNodePtr prevPtr; //char string[256]; char ip[16]; cfgPtr = calloc(1, sizeof(Config)); cfgPtr->port = 0; cfgPtr->syslog = 0; cfgPtr->debug = 0; while (cur) { logIT(LOG_INFO, "CONFIG:(%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, cur->content); if (strstr((char *)cur->name, "serial")) { serialFound = 1; prevPtr = cur; cur = cur->children; } else if (strstr((char *)cur->name, "net")) { netFound = 1; prevPtr = cur; cur = cur->children; } else if (strstr((char *)cur->name, "logging")) { logFound = 1; prevPtr = cur; cur = cur->children; } else if (strstr((char *)cur->name, "pidfile")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { cfgPtr->pidfile = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(cfgPtr->pidfile, chrPtr); } else { nullIT(&cfgPtr->pidfile); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (strstr((char *)cur->name, "username")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { cfgPtr->username= calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(cfgPtr->username, chrPtr); } else { nullIT(&cfgPtr->username); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (strstr((char *)cur->name, "groupname")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { cfgPtr->groupname= calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(cfgPtr->groupname, chrPtr); } else { nullIT(&cfgPtr->groupname); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (strstr((char *)cur->name, "device")) { chrPtr = getPropertyNode(cur->properties, (xmlChar *)"ID"); logIT(LOG_INFO, " Device ID=%s", chrPtr); if (chrPtr) { cfgPtr->devID = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(cfgPtr->devID, chrPtr); } else { nullIT(&cfgPtr->devID); } cur = cur->next; } else if (serialFound && strstr((char *)cur->name, "tty")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { cfgPtr->tty = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(cfgPtr->tty, chrPtr); } else { nullIT(&cfgPtr->tty); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (netFound && strstr((char *)cur->name, "port")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { cfgPtr->port = atoi(chrPtr); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (logFound && strstr((char *)cur->name, "file")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { cfgPtr->logfile = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(cfgPtr->logfile, chrPtr); } else { nullIT(&cfgPtr->logfile); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (logFound && strstr((char *)cur->name, "syslog")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); ((*chrPtr == 'y') || (*chrPtr == '1')) ? (cfgPtr->syslog = 1) : (cfgPtr->syslog = 0); (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (logFound && strstr((char *)cur->name, "debug")) { chrPtr = getTextNode(cur); ((*chrPtr == 'y') || (*chrPtr == '1')) ? (cfgPtr->debug = 1) : (cfgPtr->debug = 0); (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else { (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } } return cfgPtr; } unitPtr parseUnit(xmlNodePtr cur) { unitPtr uPtr; unitPtr uStartPtr = NULL; char *unit; char *chrPtr; int unitFound = 0; xmlNodePtr prevPtr; char string[256]; enumPtr ePtr; while (cur) { logIT(LOG_INFO, "UNIT: (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, cur->content); if (cur->type == XML_TEXT_NODE) { cur = cur->next; continue; } if (strstr((char *)cur->name, "unit")) { unit = getPropertyNode(cur->properties, (xmlChar *)"name"); if (unit) { // read new unit logIT(LOG_INFO, "New unit: %s", unit); uPtr = newUnitNode(uStartPtr); if (! uStartPtr) { uStartPtr = uPtr; } uPtr->name = calloc(strlen(unit) + 1, sizeof(char)); strcpy(uPtr->name, unit); unitFound = 1; prevPtr = cur; cur = cur->children; continue; } } else if (unitFound && strstr((char *)cur->name, "enum")) { chrPtr = getPropertyNode(cur->properties, (xmlChar *)"text"); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s (text)", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { ePtr = newEnumNode(uPtr->ePtr); if (! uPtr->ePtr) { uPtr->ePtr = ePtr; } ePtr->text = calloc(strlen(chrPtr) + 1, sizeof(char)); strncpy(ePtr->text, chrPtr, strlen(chrPtr)); chrPtr = getPropertyNode(cur->properties, (xmlChar *)"bytes"); if (chrPtr) { logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s (bytes)", cur->line, cur->name, cur->type, chrPtr); memset(string, 0, sizeof(string)); ePtr->len = string2chr(chrPtr, string, sizeof(string)); ePtr->bytes = calloc(ePtr->len, sizeof(char)); memcpy(ePtr->bytes, string, ePtr->len); } } else { logIT(LOG_ERR, "Property node without text="); return NULL; } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (unitFound && strstr((char *)cur->name, "abbrev")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { uPtr->abbrev = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(uPtr->abbrev, chrPtr); } else { nullIT(&uPtr->abbrev); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (unitFound && (strcmp((char *)cur->name, "calc") == 0)) { chrPtr = getPropertyNode(cur->properties, (xmlChar *)"get"); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s (get)", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { uPtr->gCalc = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(uPtr->gCalc, chrPtr); } else { nullIT(&uPtr->gCalc); } chrPtr = getPropertyNode(cur->properties, (xmlChar *)"set"); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s (set)", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { uPtr->sCalc = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(uPtr->sCalc, chrPtr); } else { nullIT(&uPtr->sCalc); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (unitFound && (strcmp((char *)cur->name, "icalc") == 0)) { chrPtr = getPropertyNode(cur->properties, (xmlChar *)"get"); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s (get)", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { uPtr->gICalc = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(uPtr->gICalc, chrPtr); } else { nullIT(&uPtr->gICalc); } chrPtr = getPropertyNode(cur->properties, (xmlChar *)"set"); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s (set)", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { uPtr->sICalc = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(uPtr->sICalc, chrPtr); } else { nullIT(&uPtr->sICalc); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (unitFound && strstr((char *)cur->name, "type")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { uPtr->type = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(uPtr->type, chrPtr); } else { nullIT(&uPtr->type); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (unitFound && strstr((char *)cur->name, "entity")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { uPtr->entity = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(uPtr->entity, chrPtr); } else { nullIT(&uPtr->entity); } //(cur->next && cur->next->next) ? (cur=cur->next) : (cur=prevPtr->next); (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else { logIT(LOG_ERR, "Error parsing unit"); return NULL; } } return uStartPtr; } macroPtr parseMacro(xmlNodePtr cur) { macroPtr mPtr; macroPtr mStartPtr = NULL; char *macro; char *chrPtr; int macroFound = 0; xmlNodePtr prevPtr; while (cur) { logIT(LOG_INFO, "MACRO: (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, cur->content); if (cur->type == XML_TEXT_NODE) { cur = cur->next; continue; } if (strstr((char *)cur->name, "macro")) { macro = getPropertyNode(cur->properties, (xmlChar *)"name"); if (macro) { // Read new macro logIT(LOG_INFO, "New macro: %s", macro); mPtr = newMacroNode(mStartPtr); if (! mStartPtr) { mStartPtr = mPtr; } mPtr->name = calloc(strlen(macro) + 1, sizeof(char)); strcpy(mPtr->name, macro); macroFound = 1; prevPtr = cur; cur = cur->children; continue; } } else if (macroFound && strstr((char *)cur->name, "command")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { mPtr->command = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(mPtr->command, chrPtr); } else { nullIT(&mPtr->command); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else { logIT(LOG_INFO, "Error parsing macro"); return NULL; } } return mStartPtr; } commandPtr parseCommand(xmlNodePtr cur, commandPtr cPtr, devicePtr dePtr) { commandPtr cStartPtr = NULL; devicePtr dPtr; char *command; char *protocmd; char *chrPtr; xmlNodePtr prevPtr; char string[256]; // TODO: get rid of that one char *id; int commandFound; commandPtr ncPtr; short count; // We look for a recursive call (then, cPtr is set) if (! cPtr) { commandFound = 0; } else { commandFound = 1; prevPtr = NULL; } while (cur) { logIT(LOG_INFO, "COMMAND: (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, cur->content); if (xmlIsBlankNode(cur)) { cur = cur->next; continue; } if (strcmp((char *)cur->name, "command") == 0) { command = getPropertyNode(cur->properties, (xmlChar *)"name"); protocmd = getPropertyNode(cur->properties, (xmlChar *)"protocmd"); if (command) { // Read new command logIT(LOG_INFO, "New command: %s", command); cPtr = newCommandNode(cStartPtr); if (! cStartPtr) { cStartPtr = cPtr; } cPtr->nodeType = 1; // No copy, we need this for deleting if (command) { cPtr->name = calloc(strlen(command) + 1, sizeof(char)); strcpy(cPtr->name, command); } else { nullIT(&cPtr->name); } if (protocmd) { cPtr->pcmd = calloc(strlen(protocmd) + 1, sizeof(char)); strcpy(cPtr->pcmd, protocmd); } else { nullIT(&cPtr->pcmd); } commandFound = 1; prevPtr = cur; cur = cur->children; continue; } } else if (commandFound && strstr((char *)cur->name, "device")) { id = getPropertyNode(cur->properties, (xmlChar *)"ID"); protocmd = getPropertyNode(cur->properties, (xmlChar *)"protocmd"); if (id) { // Read new device below command logIT(LOG_INFO, " New device command: %s", id); // Search device from the list if (! (dPtr = getDeviceNode(dePtr, id))) { logIT(LOG_ERR, "Device %s is not defined (%d)", id, cur->line); return NULL; } // We take the description from the command entry strncpy(string, cPtr->description, sizeof(string)); // Now again recursively parseCommand for all children ncPtr = newCommandNode(NULL); parseCommand(cur->children, ncPtr, dePtr); if (! dPtr->cmdPtr) { dPtr->cmdPtr = ncPtr; } else { addCommandNode(dPtr->cmdPtr, ncPtr); } // Refer to description in new accounts ncPtr->description = cPtr->description; ncPtr->name = cPtr->name; // If no unit has been given, we copy it if (! ncPtr->unit && cPtr->unit) { ncPtr->unit = calloc(strlen(cPtr->unit) + 1, sizeof(char)); strcpy(ncPtr->unit, cPtr->unit); } // Same for the protocol command if (protocmd) { ncPtr->pcmd = calloc(strlen(protocmd) + 1, sizeof(char)); strcpy(ncPtr->pcmd, protocmd); } else { ncPtr->pcmd = calloc(strlen(cPtr->pcmd) + 1, sizeof(char)); strcpy(ncPtr->pcmd, cPtr->pcmd); } ncPtr->nodeType = 2; // 2 == decription, name has been copied if (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) { cur = cur->next; } else if (prevPtr) { cur = prevPtr->next; } else { cur = NULL; } } } else if (commandFound && strstr((char *)cur->name, "addr")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { cPtr->addr = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(cPtr->addr, chrPtr); } else { nullIT(&cPtr->addr); } if (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) { cur = cur->next; } else if (prevPtr) { cur = prevPtr->next; } else { cur = NULL; } } else if (commandFound && strstr((char *)cur->name, "error")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { memset(string, 0, sizeof(string)); if ((count = string2chr(chrPtr, string, sizeof(string)))) { cPtr->errStr = calloc(count, sizeof(char)); memcpy(cPtr->errStr, string, count); } } else { nullIT(&cPtr->errStr); } if (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) { cur = cur->next; } else if (prevPtr) { cur = prevPtr->next; } else { cur = NULL; } } else if (commandFound && strstr((char *)cur->name, "unit")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { cPtr->unit = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(cPtr->unit, chrPtr); } else { nullIT(&cPtr->unit); } if (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) { cur = cur->next; } else if (prevPtr) { cur = prevPtr->next; } else { cur = NULL; } } else if (commandFound && (strcmp((char *)cur->name, "precommand") == 0)) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { cPtr->precmd = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(cPtr->precmd, chrPtr); } else { nullIT(&cPtr->precmd); } if (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) { cur = cur->next; } else if (prevPtr) { cur = prevPtr->next; } else { cur = NULL; } } else if (commandFound && strstr((char *)cur->name, "description")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { cPtr->description = calloc(strlen(chrPtr) + 1, sizeof(char)); strcpy(cPtr->description, chrPtr); } else { nullIT(&cPtr->description); } if (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) { cur = cur->next; } else if (prevPtr) { cur = prevPtr->next; } else { cur = NULL; } } else if (commandFound && strstr((char *)cur->name, "len")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { cPtr->len = atoi(chrPtr); } if (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) { cur = cur->next; } else if (prevPtr) { cur = prevPtr->next; } else { cur = NULL; } } else if (commandFound && strstr((char *)cur->name, "bit")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { cPtr->bit = atoi(chrPtr); } if (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) { cur = cur->next; } else if (prevPtr) { cur = prevPtr->next; } else { cur = NULL; } } else { logIT(LOG_ERR, "Error parsing command"); return NULL; } } return cStartPtr; } icmdPtr parseICmd(xmlNodePtr cur) { icmdPtr icPtr; icmdPtr icStartPtr = NULL; char *command; char *chrPtr; int commandFound = 0; xmlNodePtr prevPtr; while (cur) { logIT(LOG_INFO, "ICMD: (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, cur->content); if (xmlIsBlankNode(cur)) { //if (cur->type == XML_TEXT_NODE) { cur = cur->next; continue; } if (strstr((char *)cur->name, "command")) { command = getPropertyNode(cur->properties, (xmlChar *)"name"); if (command) { // Read new command logIT(LOG_INFO, "New iCommand: %s", command); icPtr = newIcmdNode(icStartPtr); if (! icStartPtr) { icStartPtr = icPtr; } icPtr->name = calloc(strlen(command) + 1, sizeof(char)); strcpy(icPtr->name, command); commandFound = 1; prevPtr = cur; cur = cur->children; continue; } } else if (commandFound && strstr((char *)cur->name, "send")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { icPtr->send = calloc(strlen(chrPtr) + 2, sizeof(char)); strcpy(icPtr->send, chrPtr); } else { nullIT(&icPtr->send); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (commandFound && strstr((char *)cur->name, "retry")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { icPtr->retry = atoi(chrPtr); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (commandFound && strstr((char *)cur->name, "recvTimeout")) { chrPtr = getTextNode(cur); logIT(LOG_INFO, " (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, chrPtr); if (chrPtr) { icPtr->recvTimeout = atoi(chrPtr); } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else { logIT(LOG_ERR, "Error parsing command"); return NULL; } } return icStartPtr; } devicePtr parseDevice(xmlNodePtr cur, protocolPtr pPtr) { devicePtr dPtr; devicePtr dStartPtr = NULL; char *proto; char *name; char *id; xmlNodePtr prevPtr; while (cur) { logIT(LOG_INFO, "DEVICE: (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, cur->content); if (cur->type == XML_TEXT_NODE) { cur = cur->next; continue; } if (strstr((char *)cur->name, "device")) { name = getPropertyNode(cur->properties, (xmlChar *)"name"); id = getPropertyNode(cur->properties, (xmlChar *)"ID"); proto = getPropertyNode(cur->properties, (xmlChar *)"protocol"); if (proto) { // Read new protocol logIT(LOG_INFO, " Neues Device: name=%s ID=%s proto=%s", name, id, proto); dPtr = newDeviceNode(dStartPtr); if (! dStartPtr) { dStartPtr = dPtr; } // Remember anchor if (name) { dPtr->name = calloc(strlen(name) + 1, sizeof(char)); strcpy(dPtr->name, name); } else { nullIT(&dPtr->name); } if (id) { dPtr->id = calloc(strlen(id) + 1, sizeof(char)); strcpy(dPtr->id, id); } else { nullIT(&dPtr->id); } if (! (dPtr->protoPtr = getProtocolNode(pPtr, proto))) { logIT(LOG_ERR, "Protocol %s not defined", proto); return NULL; } } else { logIT(LOG_ERR, "Error parsing device"); return NULL; } prevPtr = cur; cur = cur->next; } else { (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } } return dStartPtr; } protocolPtr parseProtocol(xmlNodePtr cur) { int protoFound = 0; protocolPtr protoPtr; protocolPtr protoStartPtr = NULL; macroPtr mPtr; icmdPtr icPtr; char *proto; char *chrPtr; xmlNodePtr prevPtr; while (cur) { logIT(LOG_INFO, "PROT: (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, cur->content); if (cur->type == XML_TEXT_NODE) { cur = cur->next; continue; } if (strstr((char *)cur->name, "protocol")) { proto = getPropertyNode(cur->properties, (xmlChar *)"name"); if (proto) { // Read new protocol logIT(LOG_INFO, "New protocol %s", proto); protoPtr = newProtocolNode(protoStartPtr); if (! protoStartPtr) { protoStartPtr = protoPtr; } // Remember anchor if (proto) { protoPtr->name = calloc(strlen(proto) + 1, sizeof(char)); strcpy(protoPtr->name, proto); } else { nullIT(&protoPtr->name); } } else { logIT(LOG_ERR, "Error parsing protocol"); return NULL; } protoFound = 1; prevPtr = cur; cur = cur->children; } else if (protoFound && strstr((char *)cur->name, "pid")) { chrPtr = getTextNode(cur); protoPtr->id = hex2chr(chrPtr); (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (protoFound && strstr((const char *)cur->name, "macros")) { mPtr = parseMacro(cur->children); if (mPtr) { protoPtr->mPtr = mPtr; } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else if (protoFound && strstr((char *)cur->name, "commands")) { icPtr = parseICmd(cur->children); if (icPtr) { protoPtr->icPtr = icPtr; } (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } else { (cur->next && (! (cur->next->type == XML_TEXT_NODE) || cur->next->next)) ? (cur = cur->next) : (cur = prevPtr->next); } } return protoStartPtr; } void removeComments(xmlNodePtr node) { while (node) { //printf("type:%d name=%s\n",node->type, node->name); if (node->children) { // if the node has children, process the children removeComments(node->children); } if (node->type == XML_COMMENT_NODE) { // if the node is a comment? //printf("found comment\n"); if (node->next) { removeComments(node->next); } xmlUnlinkNode(node); // unlink xmlFreeNode(node); // and free the node } node = node->next; } } int parseXMLFile(char *filename) { xmlDocPtr doc; xmlNodePtr cur, curStart; xmlNodePtr prevPtr; xmlNsPtr ns; //char string[256]; devicePtr dPtr; commandPtr cPtr, ncPtr; protocolPtr TprotoPtr = NULL; unitPtr TuPtr = NULL; devicePtr TdevPtr = NULL; commandPtr TcmdPtr = NULL; configPtr TcfgPtr = NULL; xmlKeepBlanksDefault(0); doc = xmlParseFile(filename); if (doc == NULL) { return 0; } curStart = xmlDocGetRootElement(doc); cur = curStart; if (cur == NULL) { logIT(LOG_ERR, "empty document\n"); xmlFreeDoc(doc); return 0; } ns = xmlSearchNsByHref(doc, cur, (const xmlChar *) "http://www.openv.de/vcontrol"); if (ns == NULL) { logIT(LOG_ERR, "document of the wrong type, vcontrol Namespace not found"); xmlFreeDoc(doc); return 0; } if (xmlStrcmp(cur->name, (const xmlChar *) "V-Control")) { logIT(LOG_ERR, "document of the wrong type, root node != V-Control"); xmlFreeDoc(doc); return 0; } // Run XInclude short xc = 0; if ((xc = xmlXIncludeProcessFlags(doc, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE)) == 0) { logIT(LOG_WARNING, "Didn't perform XInclude"); } else if (xc < 0) { logIT(LOG_ERR, "Error during XInclude"); return 0; } else { logIT(LOG_INFO, "%d XInclude performed", xc); } removeComments(cur); // now the xml tree is complete --> remove all comments int unixFound = 0; int protocolsFound = 0; cur = cur->children; while (cur) { logIT(LOG_INFO, "XML: (%d) Node::Name=%s Type:%d Content=%s", cur->line, cur->name, cur->type, cur->content); if (xmlIsBlankNode(cur)) { cur = cur->next; continue; } if (strstr((char *)cur->name, "unix")) { if (unixFound) { // We must not reach here, second pass logIT(LOG_ERR, "Error in XML config"); return 0; } prevPtr = cur; unixFound = 1; cur = cur->children; // On Unix, config follows. Thus children. continue; } if (strstr((char *)cur->name, "extern")) { cur = cur->children; if (cur && strstr((char *)cur->name, "vito")) { prevPtr = cur; cur = cur->children; // The xinclude stuff can be found at <extern><vito> continue; } else { cur = prevPtr->next; } } else if (strstr((char *)cur->name, "protocols")) { if (protocolsFound) { // We must not reach here, second pass logIT(LOG_ERR, "Error in XML config"); return 0; } protocolsFound = 1; if (! (TprotoPtr = parseProtocol(cur->children))) { return 0; } cur = cur->next; // Same level as Unix, proceed continue; } else if (strstr((char *)cur->name, "units")) { if (! (TuPtr = parseUnit(cur->children))) { return 0; } cur = cur->next; // Same level as Unix, proceed continue; } else if (strstr((char *)cur->name, "commands")) { if (! (TcmdPtr = parseCommand(cur->children, NULL, TdevPtr))) { return 0; } //(cur->next && cur->next->next) ? (cur=cur->next) : (cur=prevPtr->next); (cur->next) ? (cur = cur->next) : (cur = prevPtr->next); continue; } else if (strstr((char *)cur->name, "devices")) { if (! (TdevPtr = parseDevice(cur->children, TprotoPtr))) { return 0; } (cur->next) ? (cur = cur->next) : (cur = prevPtr->next); continue; } else if (strstr((char *)cur->name, "config")) { if (! (TcfgPtr = parseConfig(cur->children))) { return 0; } (cur->next && cur->next->next) ? (cur = cur->next) : (cur = prevPtr->next); } else { cur = cur->next; } } // For all commands that have default definitions, // we roam all devices and add the particular commands. cPtr = TcmdPtr; while (cPtr) { dPtr = TdevPtr; while (dPtr) { if (! getCommandNode(dPtr->cmdPtr, cPtr->name)) { // We don't know this one and copy the commands logIT(LOG_INFO, "Copying command %s to device %s", cPtr->name, dPtr->id); ncPtr = newCommandNode(dPtr->cmdPtr); if (! dPtr->cmdPtr) { dPtr->cmdPtr = ncPtr; } ncPtr->name = cPtr->name; ncPtr->pcmd = cPtr->pcmd; ncPtr->addr = cPtr->addr; ncPtr->unit = cPtr->unit; ncPtr->bit = cPtr->bit; ncPtr->errStr = cPtr->errStr; ncPtr->precmd = cPtr->precmd; ncPtr->description = cPtr->description; ncPtr->len = cPtr->len; } dPtr = dPtr->next; } cPtr = cPtr->next; } // We search the default device if (! (TcfgPtr->devPtr = getDeviceNode(TdevPtr, TcfgPtr->devID))) { logIT(LOG_ERR, "Device %s is not defined\n", TcfgPtr->devID); return 0; } // If we reach here, the loading has been successful. // Now we free the old lists and allocate the new ones. // If we're called repetitive (SIGHUP), everything should be freed. freeAllLists(); protoPtr = TprotoPtr; uPtr = TuPtr; devPtr = TdevPtr; cmdPtr = TcmdPtr; cfgPtr = TcfgPtr; xmlFreeDoc(doc); return 1; } void freeAllLists() { removeProtocolList(protoPtr); removeUnitList(uPtr); removeDeviceList(devPtr); removeCommandList(cmdPtr); protoPtr = NULL; uPtr = NULL; devPtr = NULL; cmdPtr = NULL; if (cfgPtr) { free(cfgPtr->tty); free(cfgPtr->logfile); free(cfgPtr->devID); free(cfgPtr); cfgPtr = NULL; } } 0707010000003D000081A4000028240000003200000001607BF44800000B85000000000000000000000000000000000000003700000000vcontrold-v0.98.10+git20210418.977e6f5/src/xmlconfig.h/* Copyright 2007-2017 the original vcontrold development team 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 <http://www.gnu.org/licenses/>. */ #ifndef XMLCONFIG_H #define XMLCONFIG_H #include <arpa/inet.h> typedef struct config *configPtr; typedef struct protocol *protocolPtr; typedef struct unit *unitPtr; typedef struct macro *macroPtr; typedef struct command *commandPtr; typedef struct compile *compilePtr; typedef struct device *devicePtr; typedef struct icmd *icmdPtr; typedef struct allow *allowPtr; typedef struct enumerate *enumPtr; int parseXMLFile(char *filename); macroPtr getMacroNode(macroPtr ptr, const char *name); unitPtr getUnitNode(unitPtr ptr, const char *name); commandPtr getCommandNode(commandPtr ptr, const char *name); enumPtr getEnumNode(enumPtr prt, char *search, int len); icmdPtr getIcmdNode(icmdPtr ptr, const char *name); struct compile { int token; char *send; int len; unitPtr uPtr; char *errStr; compilePtr next; } Compile; struct config { char *tty; int port; char *logfile; char *pidfile; char *username; char *groupname; char *devID; devicePtr devPtr; int syslog; int debug; } Config; struct protocol { char *name; char id; macroPtr mPtr; icmdPtr icPtr; protocolPtr next; } Protocol; struct device { char *name; char *id; commandPtr cmdPtr; protocolPtr protoPtr; devicePtr next; } Device; struct unit { char *name; char *abbrev; char *gCalc; char *sCalc; char *gICalc; char *sICalc; char *entity; char *type; enumPtr ePtr; unitPtr next; } Unit; struct macro { char *name; char *command; macroPtr next; } Macro; struct command { char *name; char *pcmd; char *send; char *addr; char *unit; char *errStr; char *precmd; unsigned char len; int retry; unsigned short recvTimeout; char bit; char nodeType; // 0: everything copied // 1: everything orig // 2: only address, unit len orig compilePtr cmpPtr; char *description; commandPtr next; } Command; struct icmd { char *name; char *send; unsigned char retry; unsigned short recvTimeout; icmdPtr next; } iCmd; struct enumerate { char *bytes; int len; char *text; enumPtr next; } Enumerate; #endif // XMLCONFIG_H 0707010000003E000041ED000028240000003200000004607BF44800000000000000000000000000000000000000000000002B00000000vcontrold-v0.98.10+git20210418.977e6f5/xml0707010000003F000041ED000028240000003200000002607BF44800000000000000000000000000000000000000000000002F00000000vcontrold-v0.98.10+git20210418.977e6f5/xml/30007070100000040000081A4000028240000003200000001607BF44800004263000000000000000000000000000000000000003D00000000vcontrold-v0.98.10+git20210418.977e6f5/xml/300/vcontrold.xml<?xml version="1.0"?> <V-Control xmlns:vcontrol="http://www.openv.de/vcontrol"> <unix> <config> <!-- These are the default settings vcontrold drops privileges to when started as root. Be sure to have the respective user and group. If you use a serial device, be sure to have read and write permissions on the corresponding device file for the user/group --> <username>nobody</username> <groupname>dialout</groupname> <serial> <tty>/dev/ttySAC1</tty> </serial> <net> <port>3002</port> </net> <logging> <file>vcontrold.log</file> <syslog>n</syslog> <debug>n</debug> </logging> <device ID="20CB"/> </config> </unix> <units> <unit name="Temperatur"> <abbrev>UT</abbrev> <calc get="V/10" set="V*10"/> <type>short</type> <entity>Grad Celsius</entity> </unit> <unit name="Temperatur100"> <abbrev>UTH</abbrev> <calc get="V/100" set="V*100"/> <type>short</type> <entity>Grad Celsius</entity> </unit> <unit name="Neigung"> <abbrev>UN</abbrev> <calc get="V/10" set="V*10"/> <type>short</type> <entity/> </unit> <unit name="Temperatur 1Byte"> <abbrev>UT1</abbrev> <calc get="V/2" set="V*2"/> <type>char</type> <entity>Grad Celsius</entity> </unit> <unit name="Temperatur 1Byte unsigned"> <abbrev>UT1U</abbrev> <calc get="V/2" set="V*2"/> <type>uchar</type> <entity>Grad Celsius</entity> </unit> <unit name="Temperatur 1Byte ganzzahlig"> <abbrev>UTI</abbrev> <calc get="V" set="V"/> <type>uchar</type> <entity>Grad Celsius</entity> </unit> <unit name="Status"> <abbrev>ST</abbrev> <calc get="V" set="V"/> <type>char</type> <entity/> </unit> <unit name="Counter"> <abbrev>CO</abbrev> <calc get="V" set="V"/> <type>int</type> <entity/> </unit> <unit name="Volumenstrom"> <abbrev>VS</abbrev> <calc get="V" set="V"/> <type>ushort</type> <entity>l/h</entity> </unit> <unit name="Counter liter"> <abbrev>COL</abbrev> <calc get="V/1000" set="V*1000"/> <type>int</type> <entity/> </unit> <unit name="Prozent"> <abbrev>PR</abbrev> <calc get="V/2" set="V*2"/> <type>short</type> <entity>%</entity> </unit> <unit name="Prozent 1 Byte ganzzahlig"> <abbrev>PR1</abbrev> <calc get="V" set="V"/> <type>uchar</type> <entity>%</entity> </unit> <unit name="Prozent zweites Byte ganzzahlig (Pumpe)"> <abbrev>PR2</abbrev> <calc get="B1" set="B1"/> <type>uchar</type> <entity>%</entity> </unit> <unit name="Prozent erstes Byte"> <abbrev>PR3</abbrev> <calc get="V/2" set="V*2"/> <type>uchar</type> <entity>%</entity> </unit> <unit name="CounterS"> <abbrev>CS</abbrev> <calc get="V/3600" set="V*3600"/> <type>uint</type> <entity>Stunden</entity> </unit> <unit name="CycleTime"> <abbrev>CT</abbrev> <type>cycletime</type> </unit> <unit name="ReturnStatus"> <abbrev>RT</abbrev> <type>enum</type> <enum bytes="00" text="0"/> <enum bytes="01" text="1"/> <!-- At least for device 20CB the heating circuit pump returns status 03 when it's on and the heating runs in in night mode --> <enum bytes='03' text='2'/> <enum text="NOT OK"/> </unit> <unit name="BetriebsArt"> <abbrev>BA</abbrev> <type>enum</type> <enum bytes="00" text="WW"/> <enum bytes="01" text="RED"/> <enum bytes="02" text="NORM"/> <enum bytes="04" text="H+WW FS"/> <enum bytes="03" text="H+WW"/> <enum bytes="05" text="ABSCHALT"/> <enum text="UNKNOWN"/> </unit> <unit name="SetReturnStatus"> <abbrev>SR</abbrev> <type>enum</type> <enum bytes="00" text="OK"/> <enum bytes="05" text="SYNC (NOT OK)"/> <enum text="NOT OK"/> </unit> <unit name="SystemTime"> <abbrev>TI</abbrev> <type>systime</type> </unit> <unit name="ErrorState"> <abbrev>ES</abbrev> <type>errstate</type> <enum bytes="00" text="Regelbetrieb (kein Fehler)"/> <enum bytes="0F" text="Wartung (fuer Reset Codieradresse 24 auf 0 stellen)"/> <enum bytes="10" text="Kurzschluss Aussentemperatursensor"/> <enum bytes="18" text="Unterbrechung Aussentemperatursensor"/> <enum bytes="20" text="Kurzschluss Vorlauftemperatursensor"/> <enum bytes="21" text="Kurzschluss Ruecklauftemperatursensor"/> <enum bytes="28" text="Unterbrechung Aussentemperatursensor"/> <enum bytes="29" text="Unterbrechung Ruecklauftemperatursensor"/> <enum bytes="30" text="Kurzschluss Kesseltemperatursensor"/> <enum bytes="38" text="Unterbrechung Kesseltemperatursensor"/> <enum bytes="40" text="Kurzschluss Vorlauftemperatursensor M2"/> <enum bytes="42" text="Unterbrechung Vorlauftemperatursensor M2"/> <enum bytes="50" text="Kurzschluss Speichertemperatursensor"/> <enum bytes="58" text="Unterbrechung Speichertemperatursensor"/> <enum bytes="92" text="Solar: Kurzschluss Kollektortemperatursensor"/> <enum bytes="93" text="Solar: Kurzschluss Sensor S3"/> <enum bytes="94" text="Solar: Kurzschluss Speichertemperatursensor"/> <enum bytes="9A" text="Solar: Unterbrechung Kollektortemperatursensor"/> <enum bytes="9B" text="Solar: Unterbrechung Sensor S3"/> <enum bytes="9C" text="Solar: Unterbrechung Speichertemperatursensor"/> <enum bytes='9E' text='Solar: Zu geringer/kein Volumenstrom oder Temperaturwächter ausgelöst'/> <enum bytes="9F" text="Solar: Fehlermeldung Solarteil (siehe Solarregler)"/> <enum bytes="A7" text="Bedienteil defekt"/> <enum bytes="B0" text="Kurzschluss Abgastemperatursensor"/> <enum bytes="B1" text="Kommunikationsfehler Bedieneinheit"/> <enum bytes="B4" text="Interner Fehler (Elektronik)"/> <enum bytes="B5" text="Interner Fehler (Elektronik)"/> <enum bytes="B6" text="Ungueltige Hardwarekennung (Elektronik)"/> <enum bytes="B7" text="Interner Fehler (Kesselkodierstecker)"/> <enum bytes="B8" text="Unterbrechung Abgastemperatursensor"/> <enum bytes="B9" text="Interner Fehler (Dateneingabe wiederholen)"/> <enum bytes="BA" text="Kommunikationsfehler Erweiterungssatz fuer Mischerkreis M2"/> <enum bytes="BC" text="Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M1"/> <enum bytes="BD" text="Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M2"/> <enum bytes="BE" text="Falsche Codierung Fernbedienung Vitorol"/> <enum bytes="C1" text="Externe Sicherheitseinrichtung (Kessel kuehlt aus)"/> <enum bytes="C2" text="Kommunikationsfehler Solarregelung"/> <enum bytes="C5" text="Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M1"/> <enum bytes="C6" text="Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M2"/> <enum bytes="C7" text="Falsche Codierung der Heizkreispumpe"/> <enum bytes="C9" text="Stoermeldeeingang am Schaltmodul-V aktiv"/> <enum bytes="CD" text="Kommunikationsfehler Vitocom 100 (KM-BUS)"/> <enum bytes="CE" text="Kommunikationsfehler Schaltmodul-V"/> <enum bytes="CF" text="Kommunikationsfehler LON Modul"/> <enum bytes="D1" text="Brennerstoerung"/> <enum bytes="D4" text="Sicherheitstemperaturbegrenzer hat ausgeloest oder Stoermeldemodul nicht richtig gesteckt"/> <enum bytes="DA" text="Kurzschluss Raumtemperatursensor, Heizkreis M1"/> <enum bytes="DB" text="Kurzschluss Raumtemperatursensor, Heizkreis M2"/> <enum bytes="DD" text="Unterbrechung Raumtemperatursensor, Heizkreis M1"/> <enum bytes="DE" text="Unterbrechung Raumtemperatursensor, Heizkreis M2"/> <enum bytes="E4" text="Fehler Versorgungsspannung"/> <enum bytes="E5" text="Interner Fehler (Ionisationselektrode)"/> <enum bytes="E6" text="Abgas- / Zuluftsystem verstopft"/> <enum bytes="F0" text="Interner Fehler (Regelung tauschen)"/> <enum bytes="F1" text="Abgastemperaturbegrenzer ausgeloest"/> <enum bytes="F2" text="Temperaturbegrenzer ausgeloest"/> <enum bytes="F3" text="Flammensigal beim Brennerstart bereits vorhanden"/> <enum bytes="F4" text="Flammensigal nicht vorhanden"/> <enum bytes="F7" text="Differenzdrucksensor defekt"/> <enum bytes="F8" text="Brennstoffventil schliesst zu spaet"/> <enum bytes="F9" text="Geblaesedrehzahl beim Brennerstart zu niedrig"/> <enum bytes="FA" text="Geblaesestillstand nicht erreicht"/> <enum bytes="FD" text="Fehler Gasfeuerungsautomat"/> <enum bytes="FE" text="Starkes Stoerfeld (EMV) in der Naehe oder Elektronik defekt"/> <enum bytes="FF" text="Starkes Stoerfeld (EMV) in der Naehe oder interner Fehler"/> <enum text="UNKNOWN"/> </unit> <unit name="DeviceType"> <abbrev>DT</abbrev> <type>enum</type> <enum bytes="20 53 01 2B" text="V200WB2 ID=2053 Protokoll:GWG_VBEM"/> <enum bytes="20 98" text="V200KW2 ID=2098 Protokoll:KW"/> <enum bytes="20 CB 03 4A 00 00 01 0A" text="VScotHO1 ID=20CB Protokoll:KW,300"/> <enum bytes="20 94" text="V200KW1 ID=2094 Protokoll:KW"/> <enum text="UNKNOWN"/> </unit> <unit name="Sachnummer"> <abbrev>SN</abbrev> <type>uint</type> <icalc get="((((((((((((B0-48)*10)+(B1-48))*10)+(B2-48))*10)+(B3-48))*10)+(B4-48))*10)+(B5-48))*10)+B6-48"/> </unit> <unit name="Brenner Stunden"> <abbrev>BH</abbrev> <type>uchar</type> <calc get="(B1 * 100)+B0"/> <entity>h</entity> </unit> <unit name="ErrorStateGWG"> <abbrev>ESG</abbrev> <type>enum</type> <enum bytes="00" text="Keine Stoerung"/> <enum bytes="02" text="Fehler Sicherheitskette"/> <enum bytes="04" text="Brennerstoerung 04"/> <enum bytes="05" text="Brennerstoerung 05"/> <enum bytes="07" text="Brennerstoerung 07"/> <enum bytes="08" text="Brennerstoerung 09"/> <enum bytes="08" text="Brennerstoerung 09"/> <enum bytes="0A" text="Brennerstoerung 10"/> <enum text="UNKNOWN"/> </unit> <unit name="Bitstatus"> <abbrev>BST</abbrev> <type>uchar</type> <icalc get="(B0 & (0x01<<BP))>> BP"/> <enum bytes="00" text="0"/> <enum bytes="01" text="1"/> <enum text="UNKNOWN"/> </unit> <unit name="HKP Pumpentyp"> <abbrev>HKT</abbrev> <type>uchar</type> <icalc get="(B0 & (0x01<<BP))>> BP"/> <enum bytes="00" text="stufig"/> <enum bytes="01" text="drehzahlgeregelt"/> <enum text="UNKNOWN"/> </unit> <unit name="Umschaltventil Stellung"> <abbrev>USV</abbrev> <type>enum</type> <enum bytes="00" text="UNDEV"/> <enum bytes="01" text="Heizen"/> <enum bytes="02" text="Mittelstellung"/> <enum bytes="03" text="Warmwasser"/> <enum text="UNKNOWN"/> </unit> </units> <protocols> <protocol name="P300"> <pid>41</pid> <macros> <macro name="GETADDR"> <command>SEND 00 01</command> </macro> <macro name="SETADDR"> <command>SEND 00 02</command> </macro> </macros> <commands> <command name="getaddr"> <send>GETADDR $addr $hexlen;RECV $len $unit</send> </command> <command name="setaddr"> <send>SETADDR $addr $hexlen;SEND BYTES $unit;RECV 1 SR</send> </command> <command name="gettestaddr"> <send/> </command> </commands> </protocol> <protocol name="KW2"> <macros> <macro name="SYNC"> <command>SEND 04;WAIT 05</command> </macro> <macro name="GETADDR"> <command>SEND 01 F7</command> </macro> <macro name="SETADDR"> <command>SEND 01 F4</command> </macro> </macros> <commands> <command name="getaddr"> <retry>3</retry> <recvTimeout>4000</recvTimeout> <send>SYNC;GETADDR $addr $hexlen;RECV $len $unit</send> </command> <command name="setaddr"> <send>SYNC;SETADDR $addr $hexlen;SEND BYTES $unit;RECV 1 SR</send> </command> <command name="gettestaddr"> <retry>3</retry> <recvTimeout>1500</recvTimeout> <send>SYNC;GETADDR;SEND BYTES;SEND 02;RECV 02</send> </command> </commands> </protocol> <protocol name="GWG"> <macros> <macro name="SYNC"> <command>SEND 04;WAIT 05</command> </macro> <macro name="GETADDR"> <command>SEND 01 CB</command> </macro> <macro name="GETBADDR"> <command>SEND 01 9E</command> </macro> <macro name="GETVADDR"> <command>SEND 01 C7</command> </macro> <macro name="GETPADDR"> <command>SEND 01 6E</command> </macro> <macro name="GETEADDR"> <command>SEND 01 AE</command> </macro> <macro name="GETXADDR"> <command>SEND 01 C5</command> </macro> <macro name="GETKMADDR"> <command>SEND 01 43</command> </macro> </macros> <commands> <command name="enable"> <send/> </command> <command name="disable"> <send/> </command> <command name="getaddr"> <retry>3</retry> <recvTimeout>4000</recvTimeout> <send>SYNC;GETADDR $addr $hexlen 04;RECV $len $unit</send> </command> <command name="gettestaddr"> <retry>3</retry> <recvTimeout>4000</recvTimeout> <send>SYNC;GETADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="getbaddr"> <retry>3</retry> <recvTimeout>4000</recvTimeout> <send>SYNC;GETBADDR $addr $hexlen 04;RECV $len $unit</send> </command> <command name="getbtestaddr"> <retry>3</retry> <recvTimeout>4000</recvTimeout> <send>SYNC;GETBADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="getpaddr"> <retry>3</retry> <recvTimeout>4000</recvTimeout> <send>SYNC;GETPADDR $addr $hexlen 04;RECV $len $unit</send> </command> <command name="getptestaddr"> <retry>3</retry> <recvTimeout>4000</recvTimeout> <send>SYNC;GETPADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="getvaddr"> <retry>3</retry> <recvTimeout>4000</recvTimeout> <send>SYNC;GETVADDR $addr $hexlen 04;RECV $len $unit</send> </command> <command name="getvtestaddr"> <retry>3</retry> <recvTimeout>4000</recvTimeout> <send>SYNC;GETVADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="geteaddr"> <retry>3</retry> <recvTimeout>4000</recvTimeout> <send>SYNC;GETEADDR $addr $hexlen 04;RECV $len $unit</send> </command> <command name="getetestaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETEADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="getxaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETXADDR $addr $hexlen 04;RECV $len $unit</send> </command> <command name="getxtestaddr"> <retry>3</retry> <recvTimeout>4000</recvTimeout> <send>SYNC;GETXADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="getkmaddr"> <send>SYNC;GETKMDDR $addr $hexlen 04;RECV $len $unit</send> <retry>3</retry> <recvTimeout>4000</recvTimeout> </command> <command name="getkmtestaddr"> <retry>3</retry> <recvTimeout>4000</recvTimeout> <send>SYNC;GETKMADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="init"> <send>SEND 16 00 00;PAUSE 100;SEND 16 00 00;PAUSE 100;SEND 16 00 00;PAUSE 100;SEND 16 00 00;PAUSE 100;SEND 16 00 00;PAUSE 100;SEND 16 00 00;PAUSE 100;SEND 16 00 00;PAUSE 100;SEND 16 00 00;PAUSE 100</send> <retry>3</retry> </command> <command name="setaddr"> <send>SYNC;SETADDR $addr $hexlen;SEND BYTES $unit;RECV 1 SR</send> </command> </commands> </protocol> </protocols> <extern xmlns:xi="http://www.w3.org/2003/XInclude"> <xi:include href="vito.xml" parse="xml"/> </extern> </V-Control> 07070100000041000081A4000028240000003200000001607BF4480000DB13000000000000000000000000000000000000003800000000vcontrold-v0.98.10+git20210418.977e6f5/xml/300/vito.xml<?xml version="1.0"?> <vito> <devices> <device ID="2098" name="V200KW2" protocol="KW2"/> <device ID="2053" name="GWG_VBEM" protocol="GWG"/> <device ID="20CB" name="VScotHO1" protocol="P300"/> <device ID="2094" name="V200KW1" protocol="KW2"/> </devices> <commands> <!-- Gerätedaten --> <!-- AUSSENTEMPERATUR --> <command name="getTempA" protocmd="getaddr"> <addr>0800</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Aussentemperatur in Grad C</description> <device ID="2053"> <addr>6F</addr> <unit>UT1</unit> <len>1</len> </device> </command> <command name="getTempAtp" protocmd="getaddr"> <addr>5525</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Aussentemperatur in Grad C (Tiefpass)</description> <device ID="2053"/> </command> <command name="getTempAged" protocmd="getaddr"> <addr>5527</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Aussentemperatur in Grad C (Gedaempft)</description> <device ID="2053"/> </command> <!-- WARMWASSER --> <command name="getTempWWist" protocmd="getaddr"> <addr>0804</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Warmwassertemperatur in Grad C</description> </command> <command name="getTempWWsoll" protocmd="getaddr"> <addr>6300</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle die Warmwassersolltemperatur in Grad C</description> </command> <command name="setTempWWsoll" protocmd="setaddr"> <addr>6300</addr> <len>2</len> <unit>UTI</unit> <description>Setze die Warmwassersolltemperatur in Grad C</description> </command> <command name="getTempStp2" protocmd="getaddr"> <addr>0814</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die WW Auslauftemperatur in Grad C (Tiefpass)</description> <device ID="2053"/> <device ID="2098"/> </command> <command name="getWWUWPNachlauf" protocmd="getaddr"> <addr>6762</addr> <len>2</len> <unit>CO</unit> <description>Ermittle Warmwasserpumpennachlauf </description> </command> <command name="setWWUWPNachlauf" protocmd="setaddr"> <addr>6762</addr> <len>2</len> <unit>CO</unit> <description>Setze Warmwasserpumpennachlauf</description> </command> <command name="getSpeichervorrang" protocmd="getaddr"> <addr>27A2</addr> <len>1</len> <unit>ST</unit> <description>Ermittle den Status Speichervorrang Heizkreis ohne Mischer A1 bzw. mit Mischer M1</description> </command> <command name="setSpeichervorrang" protocmd="setaddr"> <addr>27A2</addr> <len>1</len> <unit>ST</unit> <description>Setze den Status Speichervorrang Heizkreis ohne Mischer A1 bzw. mit Mischer M1</description> </command> <command name="getSpeichervorrangM2" protocmd="getaddr"> <addr>37A2</addr> <len>1</len> <unit>ST</unit> <description>Ermittle den Status Speichervorrang Heizkreis mit Mischer M2</description> </command> <command name="setSpeichervorrangM2" protocmd="setaddr"> <addr>37A2</addr> <len>1</len> <unit>ST</unit> <description>Setze den Status Speichervorrang Heizkreis mit Mischer M2</description> </command> <command name="getSpeichervorrangM3" protocmd="getaddr"> <addr>47A2</addr> <len>1</len> <unit>ST</unit> <description>Ermittle den Status Speichervorrang Heizkreis mit Mischer M3</description> </command> <command name="setSpeichervorrangM3" protocmd="setaddr"> <addr>47A2</addr> <len>1</len> <unit>ST</unit> <description>Setze den Status Speichervorrang Heizkreis mit Mischer M3</description> </command> <!-- KESSEL --> <!-- Differenztemperatur Kesselkreis zu HKM(2) --> <command name="getTempKOffset" protocmd="getaddr"> <addr>6760</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle Kesseloffset KT ueber WWsoll in Grad C</description> </command> <!-- Differenztemperatur Kesselkreis zu HKM(2) --> <command name="setTempKOffset" protocmd="setaddr"> <addr>6760</addr> <len>1</len> <unit>UTI</unit> <description>Setze Kesseloffset KT ueber WWsoll in Grad C</description> </command> <command name="getTempKist" protocmd="getaddr"> <addr>0802</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Kesseltemperatur in Grad C</description> <device ID="2053"> <addr>70</addr> <unit>UT1</unit> <len>1</len> </device> </command> <command name="getTempAbgas" protocmd="getaddr"> <addr>0808</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Abgastemperatur in Grad C</description> <device ID="20CB"> <addr>0808</addr> <unit>UT</unit> <len>2</len> </device> </command> <command name="getTempKtp" protocmd="getaddr"> <addr>0810</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Kesseltemperatur in Grad C (Tiefpass)</description> <device ID="2053"/> </command> <command name="getTempKsoll" protocmd="getaddr"> <addr>5502</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Kesselsolltemperatur in Grad C</description> <device ID="2053"> <addr>71</addr> <unit>UT1</unit> <len>1</len> </device> <device ID="20CB"> <addr>555A</addr> <unit>UT</unit> <len>2</len> </device> </command> <command name="getVolStrom" protocmd="getaddr"> <addr>0C24</addr> <len>2</len> <unit>VS</unit> <description>Ermittle den Volumenstrom l/h des Heizkreises</description> </command> <command name="getBetriebszeitStandby" protocmd="getaddr"> <addr>08B8</addr> <len>4</len> <unit>CS</unit> <description>Ermittle die NRF_BetriebszeitStandby</description> <device ID="2053" protocmd="geteaddr"> <addr>17</addr> <len>2</len> <unit>BH</unit> </device> </command> <!-- BRENNER --> <command name="getBrennerStatus" protocmd="getaddr"> <addr>55D3</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Brennerstatus</description> <device ID="2053"> <addr>22</addr> <len>1</len> <bit>1</bit> <unit>BST</unit> </device> <device ID="2094"> <addr>0842</addr> <len>1</len> <unit>ST</unit> </device> <device ID="20CB"> <addr>55D3</addr> <len>1</len> <unit>PR1</unit> </device> </command> <command name="getBrennerStatus2" protocmd="getaddr"> <addr>0849</addr> <len>1</len> <unit>ST</unit> <description>Ermittle den Brennerstatus Stufe 2</description> <device ID="2094"> <addr>0849</addr> <len>1</len> <unit>ST</unit> </device> </command> <command name="getBrennerStufe" protocmd="getaddr"> <addr>551E</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Brennerstatus aktuelle Stufe</description> <device ID="2053"> <addr>22</addr> <len>1</len> <bit>1</bit> <unit>BST</unit> </device> </command> <command name="getBrennerStarts" protocmd="getaddr"> <addr>088A</addr> <len>4</len> <unit>CO</unit> <description>Ermittle die Brennerstarts</description> <device ID="2053"/> </command> <command name="setBrennerStarts" protocmd="setaddr"> <addr>088A</addr> <len>2</len> <unit>CO</unit> <description>Setze die Brennerstarts</description> <device ID="2053"/> </command> <command name="getBrennerStunden1" protocmd="getaddr"> <addr>08A7</addr> <len>4</len> <unit>CS</unit> <description>Ermittle die Brennerstunden Stufe 1</description> <device ID="2053" protocmd="geteaddr"> <addr>17</addr> <len>2</len> <unit>BH</unit> </device> </command> <command name="setBrennerStunden1" protocmd="setaddr"> <addr>08A7</addr> <len>4</len> <unit>CO</unit> <description>Setze die Brennerstunden Stufe 1</description> <device ID="2053" protocmd="setaddr"> <addr>17</addr> <len>2</len> <unit>BH</unit> </device> </command> <command name="getBrennerStunden2" protocmd="getaddr"> <addr>08AB</addr> <len>4</len> <unit>CS</unit> <description>Ermittle die Brennerstunden Stufe 2</description> <device ID="2053"/> </command> <command name="getLeistungIst" protocmd="getaddr"> <addr>A38F</addr> <len>2</len> <unit>PR3</unit> <description>Ermittle Anlagen Ist-Leistung</description> <device ID="2053"/> </command> <command name="getOeldurchsatz" protocmd="getaddr"> <addr>5726</addr> <len>4</len> <unit>CO</unit> <description>Eingestellter Oeldurchsatz Brenner in Dezi-Liter pro Stunde</description> </command> <command name="setOeldurchsatz" protocmd="setaddr"> <addr>5726</addr> <len>4</len> <unit>CO</unit> <description>Oeldurchsatz Brenner in Dezi-Liter pro Stunde einstellen</description> </command> <command name="getOelverbrauch" protocmd="getaddr"> <addr>7574</addr> <len>4</len> <unit>COL</unit> <description>Ermittle den Oelverbrauch kumuliert</description> <device ID="2053"/> </command> <!-- HEIZKURVEN --> <command name="getNeigungM1" protocmd="getaddr"> <addr>2305</addr> <len>1</len> <unit>UN</unit> <description>Ermittle Neigung Heizkennlinie M1</description> <device ID="2053"> <addr>65</addr> <unit>UN</unit> <len>1</len> </device> <device ID="20CB"> <addr>27D3</addr> <unit>UN</unit> <len>1</len> </device> </command> <command name="getNeigungM2" protocmd="getaddr"> <addr>3305</addr> <len>1</len> <unit>UN</unit> <description>Ermittle Neigung Heizkennlinie M2</description> <device ID="2053"> <addr>C4</addr> <unit>UN</unit> <len>1</len> </device> <device ID="20CB"> <addr>37D3</addr> <unit>UN</unit> <len>1</len> </device> </command> <command name="getNiveauM1" protocmd="getaddr"> <addr>2304</addr> <len>1</len> <unit>ST</unit> <description>Ermittle Niveau Heizkennlinie M1</description> <device ID="2053"> <addr>64</addr> <unit>ST</unit> <len>1</len> </device> <device ID="20CB"> <addr>27D4</addr> <unit>ST</unit> <len>1</len> </device> </command> <command name="getNiveauM2" protocmd="getaddr"> <addr>3304</addr> <len>1</len> <unit>ST</unit> <description>Ermittle Niveau Heizkennlinie M2</description> <device ID="2053"> <addr>C5</addr> <unit>ST</unit> <len>1</len> </device> <device ID="20CB"> <addr>37D4</addr> <unit>ST</unit> <len>1</len> </device> </command> <command name="setNeigungM1" protocmd="setaddr"> <!-- min zul.0.2 0.1 und 0.0 nicht erlaubt --> <addr>2305</addr> <len>1</len> <unit>UN</unit> <description>Setze Neigung Heizkennlinie M1</description> <device ID="2053"/> <device ID="20CB"> <addr>27D3</addr> <unit>UN</unit> <len>1</len> </device> </command> <command name="setNeigungM2" protocmd="setaddr"> <!-- min zul.0.2 0.1 und 0.0 nicht erlaubt --> <addr>3305</addr> <len>1</len> <unit>UN</unit> <description>Setze Neigung Heizkennlinie M2</description> <device ID="2053"/> <device ID="20CB"> <addr>37D3</addr> <unit>UN</unit> <len>1</len> </device> </command> <command name="setNiveauM1" protocmd="setaddr"> <addr>2304</addr> <len>1</len> <unit>ST</unit> <description>Setze Niveau Heizkennlinie M1</description> <device ID="2053"/> <device ID="20CB"> <addr>27D4</addr> <unit>ST</unit> <len>1</len> </device> </command> <command name="setNiveauM2" protocmd="setaddr"> <addr>3304</addr> <len>1</len> <unit>ST</unit> <description>Setze Niveau Heizkennlinie M2</description> <device ID="2053"/> <device ID="20CB"> <addr>37D4</addr> <unit>ST</unit> <len>1</len> </device> </command> <!-- HEIZKREISE --> <command name="getTempVListM1" protocmd="getaddr"> <len>2</len> <unit>UT</unit> <description>Ermittle die Vorlauftemperatur M1 in Grad C</description> <device ID="2053"/> <device ID="20CB"> <addr>2900</addr> <unit>UT</unit> <len>2</len> </device> </command> <command name="getTempVListM2" protocmd="getaddr"> <addr>080C</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Vorlauftemperatur M2 in Grad C</description> <device ID="2053"> <addr>41</addr> <unit>UT1</unit> <len>1</len> </device> <device ID="20CB"> <addr>3900</addr> <unit>UT</unit> <len>2</len> </device> </command> <command name="getTempVLsollM1" protocmd="getaddr"> <addr>2544</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Vorlaufsolltemperatur M1 in Grad C</description> <device ID="2053"> <addr>69</addr> <unit>UT1</unit> <len>1</len> </device> </command> <command name="getTempVLsollM2" protocmd="getaddr"> <addr>3544</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Vorlaufsolltemperatur M2 in Grad C</description> <device ID="2053"> <addr>63</addr> <unit>UT1</unit> <len>1</len> </device> </command> <command name="getTempVLsollM3" protocmd="getaddr"> <addr>4544</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Vorlaufsolltemperatur M3 in Grad C</description> <device ID="2053"/> </command> <command name="getTempRL17A" protocmd="getaddr"> <addr>080A</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Ruecklauftemperatur 17A in Grad C</description> <device ID="2053"/> <device ID="20CB"> <addr>0808</addr> <len>2</len> <unit>UT</unit> </device> </command> <!-- SOLAR --> <command name="getTempKol" protocmd="getaddr"> <addr>6564</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Kollektortemperatur in Grad C</description> <device ID="2053"/> </command> <command name="getSolarStatusWW" protocmd="getaddr"> <addr>6551</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Nachladeunterdrueckung</description> <device ID="2053"/> </command> <command name="getSolarStunden" protocmd="getaddr"> <addr>6568</addr> <len>2</len> <unit>CO</unit> <description>Solar Betriebsstunden</description> <device ID="2053"/> </command> <command name="getSolarLeistung" protocmd="getaddr"> <addr>6560</addr> <len>4</len> <unit>CO</unit> <description>Solar Leistung Gesamt</description> <device ID="2053"/> </command> <command name="getTempS4" protocmd="getaddr"> <addr>0124</addr> <len>1</len> <unit>UT1</unit> <description>Ermittle die Temperatur S4 in Grad C</description> <device ID="2053"/> </command> <!-- SPEICHER1 --> <command name="getTempSpu" protocmd="getaddr"> <addr>6566</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Speichertemperatur unten in Grad C</description> <device ID="2053"/> </command> <command name="getTempStp" protocmd="getaddr"> <addr>0812</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Speichertemperatur in Grad C (Tiefpass)</description> <device ID="2053"/> <device ID="2098"/> </command> <!-- SOLLTEMPERATUREN --> <command name="getTempRaumNorSollM1" protocmd="getaddr"> <addr>2306</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle die Raumsolltemperatur normal M1 in Grad C</description> <device ID="2053"> <addr>53</addr> <len>1</len> <unit>UTI</unit> </device> </command> <!-- Aufruf in vclient ganzzahlig 'setTempRaumNorSollM1 21' --> <command name="setTempRaumNorSollM1" protocmd="setaddr"> <addr>2306</addr> <len>1</len> <unit>UTI</unit> <description>Setze die Raumsolltemperatur normal M1 in Grad C</description> <device ID="2053"> <addr>53</addr> <len>1</len> <unit>UTI</unit> </device> </command> <command name="getTempRaumNorSollM2" protocmd="getaddr"> <addr>3306</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle die Raumsolltemperatur normal M2 in Grad C</description> <device ID="2053"/> </command> <!-- Aufruf in vclient ganzzahlig 'setTempRaumNorSollM2 21' --> <command name="setTempRaumNorSollM2" protocmd="setaddr"> <addr>3306</addr> <len>1</len> <unit>UTI</unit> <description>Setze die Raumsolltemperatur normal M2 in Grad C</description> <device ID="2053"/> </command> <command name="getTempRaumRedSollM1" protocmd="getaddr"> <addr>2307</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle die Raumsolltemperatur reduziert M1 in Grad C</description> <device ID="2053"> <addr>54</addr> <len>1</len> <unit>UTI</unit> </device> </command> <command name="setTempRaumRedSollM1" protocmd="setaddr"> <addr>2307</addr> <len>1</len> <unit>UTI</unit> <description>Setze die Raumsolltemperatur reduziert M1 in Grad C</description> <device ID="2053"> <addr>54</addr> <len>1</len> <unit>UTI</unit> </device> </command> <command name="getTempRaumRedSollM2" protocmd="getaddr"> <addr>3307</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle die Raumsolltemperatur reduziert M2 in Grad C</description> <device ID="2053"/> </command> <command name="setTempRaumRedSollM2" protocmd="setaddr"> <addr>3307</addr> <len>1</len> <unit>UTI</unit> <description>Setze die Raumsolltemperatur reduziert M2 in Grad C</description> <device ID="2053"/> </command> <!-- PUMPEN --> <command name="getPumpeStatusM1" protocmd="getaddr"> <addr>2906</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Pumpe M1</description> <device ID="2053" protocmd="getpaddr"> <addr>01</addr> <len>1</len> <bit>0</bit> <unit>BST</unit> </device> <device ID="20CB"> <addr>7663</addr> <len>2</len> <unit>PR2</unit> </device> </command> <command name="getPumpeStatusM2" protocmd="getaddr"> <addr>3906</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Pumpe M2</description> <device ID="2053"/> <device ID="20CB"> <addr>7665</addr> <len>1</len> <unit>RT</unit> </device> </command> <command name="getPumpeDrehzahlM2" protocmd="getaddr"> <addr>3906</addr> <len>1</len> <unit>RT</unit> <description>Ermittle die Drehzahl der Pumpe M2</description> <device ID="2053"/> <device ID="20CB"> <addr>7665</addr> <len>2</len> <unit>PR2</unit> </device> </command> <command name="getPumpeStatusIntern" protocmd="getaddr"> <description>Ermittle den Status der Internen Pumpe</description> <device ID="20CB"> <addr>7660</addr> <len>1</len> <unit>RT</unit> </device> </command> <command name="getPumpeDrehzahlIntern" protocmd="getaddr"> <addr>3906</addr> <len>1</len> <unit>RT</unit> <description>Ermittle die Drehzahl der Internen Pumpe</description> <device ID="2053"/> <device ID="20CB"> <addr>7660</addr> <len>2</len> <unit>PR2</unit> </device> </command> <command name="getPumpeStatusSp" protocmd="getaddr"> <addr>0845</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Speicherladepumpe</description> <device ID="2053"/> <device ID="20CB"> <addr>6513</addr> <len>1</len> <unit>RT</unit> </device> </command> <command name="getPumpeStatusZirku" protocmd="getaddr"> <addr>0846</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Zirkulationspumpe</description> <device ID="2053" protocmd="getpaddr"> <addr>01</addr> <len>1</len> <bit>2</bit> <unit>BST</unit> </device> <device ID="20CB"> <addr>6515</addr> <len>1</len> <unit>RT</unit> </device> </command> <command name="getPumpeStatusSolar" protocmd="getaddr"> <addr>6552</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Umwaelzpumpe Solar</description> <device ID="2053"/> </command> <command name="getPumpeDrehzahlSolar" protocmd="getaddr"> <addr>6552</addr> <len>1</len> <unit>RT</unit> <description>Ermittle die Drehzahl der Internen Pumpe</description> <device ID="2053"/> <device ID="20CB"> <addr>6552</addr> <len>2</len> <unit>PR2</unit> </device> </command> <command name="getPumpeStatusSolar2" protocmd="getaddr"> <addr>6553</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Pumpe 2 Solar </description> <device ID="2053"/> </command> <command name="getPumpeStatusSolar3" protocmd="getaddr"> <addr>6554</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Pumpe 3 Solar </description> <device ID="2053"/> </command> <command name="getPumpeStatusSolar4" protocmd="getaddr"> <addr>6555</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Pumpe 4 Solar </description> <device ID="2053"/> </command> <command name="getTempSTSSOL" protocmd="getaddr"> <addr>081A</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Speichertemperatur in Grad C (NRF_TiefpassTemperaturwert_STSSOL)</description> <device ID="2053"/> <device ID="2098"/> </command> <!-- MISCHER --> <command name="getMischerM1" protocmd="getaddr"> <addr>254C</addr> <len>1</len> <unit>PR</unit> <description>Ermittle Mischerposition M1</description> <device ID="2053"/> </command> <command name="getMischerM2" protocmd="getaddr"> <addr>354C</addr> <len>1</len> <unit>PR</unit> <description>Ermittle Mischerposition M2</description> <device ID="2053"/> <device ID="20CB"> <addr>354C</addr> <len>1</len> <unit>PR</unit> </device> </command> <command name="getMischerM3" protocmd="getaddr"> <addr>454C</addr> <len>1</len> <unit>PR</unit> <description>Ermittle Mischerposition M3</description> <device ID="2053"/> </command> <!-- HEIZZEITEN --> <command name="getTimerM1Mo" protocmd="getaddr"> <addr>2000</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag M1</description> <device ID="2053"/> </command> <command name="getTimerM1Di" protocmd="getaddr"> <addr>2008</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag M1</description> <device ID="2053"/> </command> <command name="getTimerM1Mi" protocmd="getaddr"> <addr>2010</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit MIttwoch M1</description> <device ID="2053"/> </command> <command name="getTimerM1Do" protocmd="getaddr"> <addr>2018</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag M1</description> <device ID="2053"/> </command> <command name="getTimerM1Fr" protocmd="getaddr"> <addr>2020</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag M1</description> <device ID="2053"/> </command> <command name="getTimerM1Sa" protocmd="getaddr"> <addr>2028</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag M1</description> <device ID="2053"/> </command> <command name="getTimerM1So" protocmd="getaddr"> <addr>2030</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag M1</description> <device ID="2053"/> </command> <command name="getTimerM2Mo" protocmd="getaddr"> <addr>3000</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag M2</description> <device ID="2053"/> </command> <command name="getTimerM2Di" protocmd="getaddr"> <addr>3008</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag M2</description> <device ID="2053"/> </command> <command name="getTimerM2Mi" protocmd="getaddr"> <addr>3010</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch M2</description> <device ID="2053"/> </command> <command name="getTimerM2Do" protocmd="getaddr"> <addr>3018</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag M2</description> <device ID="2053"/> </command> <command name="getTimerM2Fr" protocmd="getaddr"> <addr>3020</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag M2</description> <device ID="2053"/> </command> <command name="getTimerM2Sa" protocmd="getaddr"> <addr>3028</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag M2</description> <device ID="2053"/> </command> <command name="getTimerM2So" protocmd="getaddr"> <addr>3030</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag M2</description> <device ID="2053"/> </command> <!-- WARMWASSERZEITEN --> <command name="getTimerWWMo" protocmd="getaddr"> <addr>2100</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag Warmwasser</description> <device ID="2053"/> </command> <command name="getTimerWWDi" protocmd="getaddr"> <addr>2108</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag Warmwasser</description> <device ID="2053"/> </command> <command name="getTimerWWMi" protocmd="getaddr"> <addr>2110</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch Warmwasser</description> <device ID="2053"/> </command> <command name="getTimerWWDo" protocmd="getaddr"> <addr>2118</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag Warmwasser</description> <device ID="2053"/> </command> <command name="getTimerWWFr" protocmd="getaddr"> <addr>2120</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag Warmwasser</description> <device ID="2053"/> </command> <command name="getTimerWWSa" protocmd="getaddr"> <addr>2128</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag Warmwasser</description> <device ID="2053"/> </command> <command name="getTimerWWSo" protocmd="getaddr"> <addr>2130</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag Warmwasser</description> <device ID="2053"/> </command> <!-- ZIRKULATIONSZEITEN --> <command name="getTimerZirkuMo" protocmd="getaddr"> <addr>2200</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag Zirku</description> <device ID="2053"/> </command> <command name="getTimerZirkuDi" protocmd="getaddr"> <addr>2208</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag Zirku</description> <device ID="2053"/> </command> <command name="getTimerZirkuMi" protocmd="getaddr"> <addr>2210</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch Zirku</description> <device ID="2053"/> </command> <command name="getTimerZirkuDo" protocmd="getaddr"> <addr>2218</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag Zirku</description> <device ID="2053"/> </command> <command name="getTimerZirkuFr" protocmd="getaddr"> <addr>2220</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag Zirku</description> <device ID="2053"/> </command> <command name="getTimerZirkuSa" protocmd="getaddr"> <addr>2228</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag Zirku</description> <device ID="2053"/> </command> <command name="getTimerZirkuSo" protocmd="getaddr"> <addr>2230</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag Zirku</description> <device ID="2053"/> </command> <!-- BETRIEBSARTEN --> <command name="getBetriebArtM1" protocmd="getaddr"> <addr>2301</addr> <len>1</len> <unit>BA</unit> <description>Betriebsart M1</description> <device ID="2053"> <addr>51</addr> <len>1</len> <unit>BA</unit> </device> </command> <command name="getBetriebArt" protocmd="getaddr"> <addr>2301</addr> <len>1</len> <unit>BA</unit> <description>Betriebsart</description> <device ID="2053"/> </command> <command name="getBetriebArtM2" protocmd="getaddr"> <addr>3301</addr> <len>1</len> <unit>BA</unit> <description>Betriebsart M2</description> <device ID="2053"/> </command> <!-- SPARBETRIEB (SPARSCHWEIN) --> <command name="getBetriebSparM1" protocmd="getaddr"> <addr>2302</addr> <len>1</len> <unit>RT</unit> <description>Betriebsart Spar M1</description> <device ID="2053"/> </command> <command name="getBetriebSparM2" protocmd="getaddr"> <addr>3302</addr> <len>1</len> <unit>RT</unit> <description>Betriebsart Spar M2</description> <device ID="2053"/> </command> <!-- PARTYBETRIEB --> <command name="getBetriebPartyM1" protocmd="getaddr"> <addr>2303</addr> <len>1</len> <unit>RT</unit> <description>Betriebsart Party M1</description> <device ID="2053"/> </command> <command name="getBetriebPartyM2" protocmd="getaddr"> <addr>3303</addr> <len>1</len> <unit>RT</unit> <description>Betriebsart Party M2</description> <device ID="2053"/> </command> <command name="getTempPartyM1" protocmd="getaddr"> <addr>2308</addr> <len>1</len> <unit>ST</unit> <description>Solltemperatur Partybetrieb M1</description> <device ID="2053"/> </command> <command name="setTempPartyM1" protocmd="setaddr"> <addr>2308</addr> <len>1</len> <unit>ST</unit> <description>Setze die Warmwassersolltemperatur Party M1 in Grad C</description> <device ID="2053"/> </command> <command name="getTempPartyM2" protocmd="getaddr"> <addr>3308</addr> <len>1</len> <unit>ST</unit> <description>Solltemperatur Partybetrieb M2</description> <device ID="2053"/> </command> <command name="setTempPartyM2" protocmd="setaddr"> <addr>3308</addr> <len>1</len> <unit>ST</unit> <description>Setze die Warmwassersolltemperatur Party M2 in Grad C</description> <device ID="2053"/> </command> <command name="setBetriebPartyM1" protocmd="setaddr"> <addr>2303</addr> <len>1</len> <unit>RT</unit> <description>Setze Betriebsart Party M1</description> <device ID="2053"/> </command> <command name="setBetriebPartyM2" protocmd="setaddr"> <addr>3303</addr> <len>1</len> <unit>RT</unit> <description>Setze Betriebsart Party M2</description> <device ID="2053"/> </command> <!-- EXTERNES SPERREN und ANFORDERN --> <command name="getEinflussExtSperren" protocmd="getaddr"> <addr>5732</addr> <len>1</len> <unit>ST</unit> <description>Einfluss Extern Sperren auf Pumpen</description> </command> <command name="getEinflussExtAnforderung" protocmd="getaddr"> <addr>5734</addr> <len>1</len> <unit>ST</unit> <description>Einfluss Externe Anforderung auf Pumpen</description> </command> <command name="getExtSperren" protocmd="getaddr"> <addr>0A81</addr> <len>1</len> <unit>RT</unit> <description>Ist Extern Sperren aktiv</description> </command> <command name="getExtAnforderung" protocmd="getaddr"> <addr>0A80</addr> <len>1</len> <unit>RT</unit> <description>Ist Externe Anforderung aktiv</description> </command> <!-- FROSTSCHUTZ --> <command name="getStatusFrostM1" protocmd="getaddr"> <addr>2500</addr> <len>1</len> <unit>ST</unit> <description>Status Frostwarnung M1</description> <device ID="2053"/> </command> <command name="getStatusFrostM2" protocmd="getaddr"> <addr>3500</addr> <len>1</len> <unit>ST</unit> <description>Status Frostwarnung M2</description> <device ID="2053"/> </command> <!-- STOERUNG --> <command name="getStatusStoerung" protocmd="getaddr"> <addr>7579</addr> <len>1</len> <unit>RT</unit> <description>Status Sammelstoerung</description> <device ID="2053"/> <device ID="20CB"> <addr>0A82</addr> <len>1</len> <unit>RT</unit> </device> </command> <command name="getError0" protocmd="getaddr"> <addr>7507</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 1</description> <device ID="2053"> <addr>3F</addr> <len>1</len> <unit>ESG</unit> </device> </command> <command name="getError1" protocmd="getaddr"> <addr>7510</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 2</description> <device ID="2053"/> </command> <command name="getError2" protocmd="getaddr"> <addr>7519</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 3</description> <device ID="2053"/> </command> <command name="getError3" protocmd="getaddr"> <addr>7522</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 4</description> <device ID="2053"/> </command> <command name="getError4" protocmd="getaddr"> <addr>752B</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 5</description> <device ID="2053"/> </command> <command name="getError5" protocmd="getaddr"> <addr>7534</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 6</description> <device ID="2053"/> </command> <command name="getError6" protocmd="getaddr"> <addr>753D</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 7</description> <device ID="2053"/> </command> <command name="getError7" protocmd="getaddr"> <addr>7546</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 8</description> <device ID="2053"/> </command> <command name="getError8" protocmd="getaddr"> <addr>754F</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 9</description> <device ID="2053"/> </command> <command name="getError9" protocmd="getaddr"> <addr>7558</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 10</description> <device ID="2053"/> </command> <!-- SYSTEMZEIT --> <command name="getSystemTime" protocmd="getaddr"> <addr>088E</addr> <len>8</len> <unit>TI</unit> <description>Ermittle Systemzeit</description> <device ID="2053"/> </command> <command name="setSystemTime" protocmd="setaddr"> <addr>088E</addr> <len>8</len> <unit>TI</unit> <description>Setze Systemzeit</description> <device ID="2053"/> </command> <!-- KONFIGURATION UND SETZEN --> <!-- xxx Heizkreispumpenlogik-Funktion xxx --> <!-- A5:0 Ohne Heizkreispumpenlogik-Funktion Mit Heizkreispumpenlogik−Funktion: Heizkreispumpe aus, wenn A5:1 AT > RTSoll + 5 K A5:2 AT > RTSoll + 4 K A5:3 AT > RTSoll + 3 K A5:4 AT > RTSoll + 2 K A5:5 AT > RTSoll + 1 K A5:6 AT = RTSoll A5:7 AT > RTSoll -1 K bis A5:15 AT > RTSoll -9 K --> <command name="getKA5" protocmd="getaddr"> <addr>27A5</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle die Heizkreispumpenlogik−Funktion</description> <!-- KA5_KonfSommersparSchaltschwelle A5 0x27a5 --> </command> <command name="setKA5" protocmd="setaddr"> <addr>27A5</addr> <len>1</len> <unit>UTI</unit> <description>Setze die Heizkreispumpenlogik−Funktion</description> <!-- KA5_KonfSommersparSchaltschwelle A5 0x27a5 1Byte --> </command> <command name="getKA5M2" protocmd="getaddr"> <addr>37A5</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle die Heizkreispumpenlogik−Funktion M2</description> <!-- KA5_KonfSommersparSchaltschwelleM2 A5 0x37a5 --> </command> <command name="setKA5M2" protocmd="setaddr"> <addr>37A5</addr> <len>1</len> <unit>UTI</unit> <description>Setze die Heizkreispumpenlogik−Funktion M2</description> <!-- KA5_KonfSommersparSchaltschwelleM2 A5 0x37a5 1Byte --> </command> <command name="getKA5M3" protocmd="getaddr"> <addr>47A5</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle die Heizkreispumpenlogik−Funktion M3</description> <!-- KA5_KonfSommersparSchaltschwelleM2 A5 0x47a5 --> </command> <command name="setKA5M3" protocmd="setaddr"> <addr>47A5</addr> <len>1</len> <unit>UTI</unit> <description>Setze die Heizkreispumpenlogik−Funktion M3</description> <!-- KA5_KonfSommersparSchaltschwelleM2 A5 0x47a5 1Byte --> </command> <!-- xxx Konfiguration A6 Erweiterte Sparschaltung xxx --> <!-- KA6_KonfiAbsolutSommersparM2 A6 0x37a6 --> <!-- A6:36 Erweiterte Sparschaltung nicht aktiv A6:5 bis A6:35 Erweiterte Sparschaltung aktiv, d.h. bei einem variabel einstellbaren Wert von 5 bis 35 °C zuzüglich 1°C werden Brenner und Heizkreispumpe ausgeschaltet. Grundlage ist die gedämpfte Außentemperatur, die sich aus tatsächlicher Außentemperatur und einer Zeitkonstanten, die das Auskühlen eines durchschnittlichen Gebäudes berücksichtigt, zusammensetzt. --> <command name="getKA6" protocmd="getaddr"> <addr>27A6</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle die AbsolutSommersparschaltung </description> <!-- KA6_KonfiAbsolutSommerspar A6 0x27a6 --> </command> <command name="setKA6" protocmd="setaddr"> <addr>27A6</addr> <len>1</len> <unit>UTI</unit> <description>Setze die AbsolutSommersparschaltung</description> <!-- KA6_KonfiAbsolutSommerspar A6 0x27a6 --> </command> <command name="getKA6M2" protocmd="getaddr"> <addr>37A6</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle die AbsolutSommersparschaltung M2</description> <!-- KA6_KonfiAbsolutSommersparM2 A6 0x37a6 --> </command> <command name="setKA6M2" protocmd="setaddr"> <addr>37A6</addr> <len>1</len> <unit>UTI</unit> <description>Setze die AbsolutSommersparschaltung M2</description> <!-- KA6_KonfiAbsolutSommersparM2 A6 0x37a6 1Byte --> </command> <command name="getKA6M3" protocmd="getaddr"> <addr>47A6</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle die AbsolutSommersparschaltung M3</description> <!-- KA6_KonfiAbsolutSommersparM3 A6 0x47a6 --> </command> <command name="setKA6M3" protocmd="setaddr"> <addr>47A6</addr> <len>1</len> <unit>UTI</unit> <description>Setze die AbsolutSommersparschaltung M3</description> <!-- KA6_KonfiAbsolutSommersparM3 A6 0x47a6 1Byte --> </command> <!-- Auswirkung Mischer auf interne Pumpe --> <command name="getKonfiWirkung_aufPumpe" protocmd="getaddr"> <addr>37A8</addr> <len>1</len> <unit>ST</unit> <description>Ermittle Einfluss Mischer auf int UWP</description> <!-- 0 ohne 1 M2 setzt Anforderung an Int.Pumpe - nur sinnvoll bei Mischerkreis --> <!-- wenn nicht vorhanden Rückgabewert -1.0 --> </command> <command name="setKonfiWirkung_aufPumpe" protocmd="setaddr"> <addr>37A8</addr> <len>1</len> <unit>ST</unit> <description>Setze Einfluss Mischer auf int UWP</description> <!-- 0 ohne 1 M2 setzt Anforderung an Int.Pumpe - nur sinnvoll bei Mischerkreis --> <!-- wenn nicht vorhanden Rückgabewert -1.0 --> </command> <command name="getKA3_KonfiFrostgrenzeM1_GWG" protocmd="getaddr"> <addr>27A3</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle die eingestellte Frostgrenze A1M1</description> <!-- Range GradCelsius SByte 1 -9 15 --> </command> <command name="setKA3_KonfiFrostgrenzeM1_GWG" protocmd="setaddr"> <addr>27A3</addr> <len>1</len> <unit>UTI</unit> <description>Setze die Frostgrenze A1M1</description> <!-- Range GradCelsius SByte 1 -9 15 --> </command> <command name="getKA3_KonfiFrostgrenzeM2_GWG" protocmd="getaddr"> <addr>37A3</addr> <len>1</len> <unit>UTI</unit> <description>Ermittle die eingestellte Frostgrenze</description> <!-- Range GradCelsius SByte 1 -9 15 --> </command> <command name="setKA3_KonfiFrostgrenzeM2_GWG" protocmd="setaddr"> <addr>37A3</addr> <len>1</len> <unit>UTI</unit> <description>Setze die Frostgrenze</description> <!-- Range GradCelsius SByte 1 -9 15 --> </command> <command name="setPumpeStatusZirku" protocmd="setaddr"> <addr>0846</addr> <len>1</len> <unit>RT</unit> <description>Setze den Status der Zirkulationspumpe</description> <device ID="2053"> <addr>01</addr> <len>1</len> <bit>2</bit> <precommand>getPumpeStatusZirku</precommand> <unit>BA</unit> </device> </command> <command name="setTimerM1Mo" protocmd="setaddr"> <addr>2000</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag M1</description> <device ID="2053"/> </command> <command name="setTimerM1Di" protocmd="setaddr"> <addr>2008</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag M1</description> <device ID="2053"/> </command> <command name="setTimerM1Mi" protocmd="setaddr"> <addr>2010</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch M1</description> <device ID="2053"/> </command> <command name="setTimerM1Do" protocmd="setaddr"> <addr>2018</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag M1</description> <device ID="2053"/> </command> <command name="setTimerM1Fr" protocmd="setaddr"> <addr>2020</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag M1</description> <device ID="2053"/> </command> <command name="setTimerM1Sa" protocmd="setaddr"> <addr>2028</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag M1</description> <device ID="2053"/> </command> <command name="setTimerM1So" protocmd="setaddr"> <addr>2030</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag M1</description> <device ID="2053"/> </command> <command name="setTimerM2Mo" protocmd="setaddr"> <addr>3000</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag M2</description> <device ID="2053"/> </command> <command name="setTimerM2Di" protocmd="setaddr"> <addr>3008</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag M2</description> <device ID="2053"/> </command> <command name="setTimerM2Mi" protocmd="setaddr"> <addr>3010</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch M2</description> <device ID="2053"/> </command> <command name="setTimerM2Do" protocmd="setaddr"> <addr>3018</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag M2</description> <device ID="2053"/> </command> <command name="setTimerM2Fr" protocmd="setaddr"> <addr>3020</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag M2</description> <device ID="2053"/> </command> <command name="setTimerM2Sa" protocmd="setaddr"> <addr>3028</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag M2</description> <device ID="2053"/> </command> <command name="setTimerM2So" protocmd="setaddr"> <addr>3030</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag M2</description> <device ID="2053"/> </command> <command name="setTimerWWMo" protocmd="setaddr"> <addr>2100</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerWWDi" protocmd="setaddr"> <addr>2108</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerWWMi" protocmd="setaddr"> <addr>2110</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerWWDo" protocmd="setaddr"> <addr>2118</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerWWFr" protocmd="setaddr"> <addr>2120</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerWWSa" protocmd="setaddr"> <addr>2128</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerWWSo" protocmd="setaddr"> <addr>2130</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerZirkuMo" protocmd="setaddr"> <addr>2200</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag Zirku</description> <device ID="2053"/> </command> <command name="setTimerZirkuDi" protocmd="setaddr"> <addr>2208</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag Zirku</description> <device ID="2053"/> </command> <command name="setTimerZirkuMi" protocmd="setaddr"> <addr>2210</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch Zirku</description> <device ID="2053"/> </command> <command name="setTimerZirkuDo" protocmd="setaddr"> <addr>2218</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag Zirku</description> <device ID="2053"/> </command> <command name="setTimerZirkuFr" protocmd="setaddr"> <addr>2220</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag Zirku</description> <device ID="2053"/> </command> <command name="setTimerZirkuSa" protocmd="setaddr"> <addr>2228</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag Zirku</description> <device ID="2053"/> </command> <command name="setTimerZirkuSo" protocmd="setaddr"> <addr>2230</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag Zirku</description> <device ID="2053"/> </command> <!-- Gerätedaten --> <command name="getDevType" protocmd="getaddr"> <addr>00F8</addr> <len>8</len> <unit>DT</unit> <description>Ermittle Device Typ der Anlage / SystemIdent_SX</description> </command> <command name="getCtrlId" protocmd="getaddr"> <addr>00F9</addr> <len>7</len> <unit>DT</unit> <description>Reglerkennung</description> </command> <command name="getInventory" protocmd="getaddr"> <addr>08E0</addr> <len>7</len> <unit>SN</unit> <description>Sachnummer</description> </command> <command name="getInvCodePlug" protocmd="getaddr"> <addr>1010</addr> <len>7</len> <unit>SN</unit> <description>Sachnummer Codierstecker</description> </command> <command name="getPanelSWIndex" protocmd="getaddr"> <addr>7330</addr> <len>8</len> <unit>DT</unit> <description>Bedienteil SW Index</description> </command> <command name="getKsCardType" protocmd="getaddr"> <addr>7656</addr> <len>4</len> <unit>DT</unit> <description>KS Karte Typ</description> </command> <command name="getAnlagenschema" protocmd="getaddr"> <addr>7700</addr> <len>2</len> <unit>ST</unit> <description>Ermittle das Anlagenschema</description> <!-- K00_KonfiAnlagenschemaGWG_W (00) Heizkreis-Warmwasserschema Adresse 7700 1 A1 | 1 2 A1 + WW | 2 3 M2 | 3 4 M2 + WW | 4 5 A1 + M2 | 5 6 A1 + M2 + WW | 6 --> </command> <command name="init" protocmd="getaddr"> <description>Inintialisierung</description> <device ID="2053" protocmd="init"> <addr>dummy</addr> </device> </command> <command name="get" protocmd="gettestaddr"> <description>Testabfrage, Adresse eingeben</description> <device ID="20CB"> <addr>dummy</addr> <len>2</len> </device> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> <device ID="2094"> <addr>dummy</addr> <len>2</len> </device> </command> <command name="vget" protocmd="getvtestaddr"> <description>Testabfrage, Virtuelle Adresse eingeben</description> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> </command> <command name="bget" protocmd="getbtestaddr"> <description>Testabfrage, Bedienteil Adresse eingeben</description> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> </command> <command name="pget" protocmd="getptestaddr"> <description>Testabfrage, Port Adresse eingeben</description> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> </command> <command name="eget" protocmd="getetestaddr"> <description>Testabfrage, EEProm Adresse eingeben</description> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> </command> <command name="xget" protocmd="getxtestaddr"> <description>Testabfrage, XRAM Adresse eingeben</description> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> </command> <command name="kmget" protocmd="getkmtestaddr"> <description>Testabfrage, KM-Bus EEProm Adresse eingeben</description> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> </command> <command name="getExtBA" protocmd="getxaddr"> <description>Ermittle Zustand der externen Betriebsartenumschaltung</description> <device ID="2053"> <addr>00</addr> <len>1</len> <bit>0</bit> <unit>BST</unit> </device> </command> <command name="getPumpeSollM1" protocmd="getaddr"> <description>Ermittle Solldrehzahl Pumpe M1</description> <device ID="2053"> <addr>B0</addr> <len>1</len> <unit>PR1</unit> </device> </command> <command name="getVentilStatus" protocmd="getpaddr"> <description>Ermittle Zustand Umschaltventil WW/Heizen</description> <device ID="2053"> <addr>01</addr> <len>1</len> <bit>1</bit> <unit>BST</unit> </device> </command> <command name="getUmschaltventil" protocmd="getaddr"> <addr>0A10</addr> <len>1</len> <unit>USV</unit> <description>Ermittle den Status des Umschaltventils WW/Heizen</description> <device ID="2098"/> <device ID="2053"> <addr>01</addr> <len>1</len> <bit>1</bit> <unit>BST</unit> </device> </command> <command name="setUmschaltventil" protocmd="setaddr"> <addr>0A10</addr> <len>1</len> <unit>USV</unit> <description>Setze den Status des Umschaltventils WW/Heizen</description> <device ID="2098"/> <device ID="2053"> <addr>01</addr> <len>1</len> <bit>1</bit> <unit>BST</unit> </device> </command> <command name="getHKPTyp" protocmd="geteaddr"> <description>Ermittle Typ der Heizkreispumpe</description> <device ID="2053"> <addr>05</addr> <len>1</len> <bit>5</bit> <unit>HKT</unit> </device> </command> <command name="getTempRueck" protocmd="getaddr"> <description>Ermittle die Rueckauftemepratur</description> <device ID="2053"> <addr>44</addr> <len>1</len> <bit>5</bit> <unit>UT1</unit> </device> </command> </commands> </vito> 07070100000042000041ED000028240000003200000002607BF44800000000000000000000000000000000000000000000002E00000000vcontrold-v0.98.10+git20210418.977e6f5/xml/kw07070100000043000081A4000028240000003200000001607BF448000035B9000000000000000000000000000000000000003C00000000vcontrold-v0.98.10+git20210418.977e6f5/xml/kw/vcontrold.xml<?xml version="1.0"?> <V-Control xmlns:vcontrol="http://www.openv.de/vcontrol"> <unix> <config> <serial> <tty>192.168.1.153:3002</tty> </serial> <net> <port>3002</port> </net> <logging> <file>/tmp/vcontrold.log</file> <syslog>n</syslog> <debug>n</debug> </logging> <device ID="2053"/> </config> </unix> <units> <unit name="Temperatur"> <abbrev>UT</abbrev> <calc get="V/10" set="V*10"/> <type>short</type> <entity>Grad Celsius</entity> </unit> <unit name="Neigung"> <abbrev>UN</abbrev> <calc get="V/10" set="V*10"/> <type>short</type> <entity/> </unit> <unit name="Temperatur 1Byte"> <abbrev>UT1</abbrev> <calc get="V/2" set="V*2"/> <type>char</type> <entity>Grad Celsius</entity> </unit> <unit name="Temperatur 1Byte unsigned"> <abbrev>UT1U</abbrev> <calc get="V/2" set="V*2"/> <type>uchar</type> <entity>Grad Celsius</entity> </unit> <unit name="Temperatur 1Byte ganzzahlig"> <abbrev>UTI</abbrev> <calc get="V" set="V"/> <type>uchar</type> <entity>Grad Celsius</entity> </unit> <unit name="Status"> <abbrev>ST</abbrev> <calc get="V" set="V"/> <type>char</type> <entity/> </unit> <unit name="Counter"> <abbrev>CO</abbrev> <calc get="V" set="V"/> <type>int</type> <entity/> </unit> <unit name="Prozent"> <abbrev>PR</abbrev> <calc get="V/2" set="V*2"/> <type>short</type> <entity>%</entity> </unit> <unit name="Prozent 1 Byte ganzzahlig"> <abbrev>PR1</abbrev> <calc get="V" set="V"/> <type>uchar</type> <entity>%</entity> </unit> <unit name="CounterS"> <abbrev>CS</abbrev> <calc get="V/3600" set="V*3600"/> <type>uint</type> <entity>Stunden</entity> </unit> <unit name="CycleTime"> <abbrev>CT</abbrev> <type>cycletime</type> </unit> <unit name="ReturnStatus"> <abbrev>RT</abbrev> <type>enum</type> <enum bytes="00" text="0"/> <enum bytes="01" text="1"/> <enum text="NOT OK"/> </unit> <unit name="BetriebsArt"> <abbrev>BA</abbrev> <type>enum</type> <enum bytes="00" text="WW"/> <enum bytes="01" text="RED"/> <enum bytes="02" text="NORM"/> <enum bytes="04" text="H+WW"/> <enum bytes="03" text="H+WW"/> <enum bytes="05" text="ABSCHALT"/> <enum text="UNKNOWN"/> </unit> <unit name="SetReturnStatus"> <abbrev>SR</abbrev> <type>enum</type> <enum bytes="00" text="OK"/> <enum bytes="05" text="SYNC (NOT OK)"/> <enum text="NOT OK"/> </unit> <unit name="SystemTime"> <abbrev>TI</abbrev> <type>systime</type> </unit> <unit name="ErrorState"> <abbrev>ES</abbrev> <type>errstate</type> <enum bytes="00" text="Regelbetrieb (kein Fehler)"/> <enum bytes="0F" text="Wartung (fuer Reset Codieradresse 24 auf 0 stellen)"/> <enum bytes="10" text="Kurzschluss Aussentemperatursensor"/> <enum bytes="18" text="Unterbrechung Aussentemperatursensor"/> <enum bytes="20" text="Kurzschluss Vorlauftemperatursensor"/> <enum bytes="21" text="Kurzschluss Ruecklauftemperatursensor"/> <enum bytes="28" text="Unterbrechung Aussentemperatursensor"/> <enum bytes="29" text="Unterbrechung Ruecklauftemperatursensor"/> <enum bytes="30" text="Kurzschluss Kesseltemperatursensor"/> <enum bytes="38" text="Unterbrechung Kesseltemperatursensor"/> <enum bytes="40" text="Kurzschluss Vorlauftemperatursensor M2"/> <enum bytes="42" text="Unterbrechung Vorlauftemperatursensor M2"/> <enum bytes="50" text="Kurzschluss Speichertemperatursensor"/> <enum bytes="58" text="Unterbrechung Speichertemperatursensor"/> <enum bytes="92" text="Solar: Kurzschluss Kollektortemperatursensor"/> <enum bytes="93" text="Solar: Kurzschluss Sensor S3"/> <enum bytes="94" text="Solar: Kurzschluss Speichertemperatursensor"/> <enum bytes="9A" text="Solar: Unterbrechung Kollektortemperatursensor"/> <enum bytes="9B" text="Solar: Unterbrechung Sensor S3"/> <enum bytes="9C" text="Solar: Unterbrechung Speichertemperatursensor"/> <enum bytes="9F" text="Solar: Fehlermeldung Solarteil (siehe Solarregler)"/> <enum bytes="A7" text="Bedienteil defekt"/> <enum bytes="B0" text="Kurzschluss Abgastemperatursensor"/> <enum bytes="B1" text="Kommunikationsfehler Bedieneinheit"/> <enum bytes="B4" text="Interner Fehler (Elektronik)"/> <enum bytes="B5" text="Interner Fehler (Elektronik)"/> <enum bytes="B6" text="Ungueltige Hardwarekennung (Elektronik)"/> <enum bytes="B7" text="Interner Fehler (Kesselkodierstecker)"/> <enum bytes="B8" text="Unterbrechung Abgastemperatursensor"/> <enum bytes="B9" text="Interner Fehler (Dateneingabe wiederholen)"/> <enum bytes="BA" text="Kommunikationsfehler Erweiterungssatz fuer Mischerkreis M2"/> <enum bytes="BC" text="Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M1"/> <enum bytes="BD" text="Kommunikationsfehler Fernbedienung Vitorol, Heizkreis M2"/> <enum bytes="BE" text="Falsche Codierung Fernbedienung Vitorol"/> <enum bytes="C1" text="Externe Sicherheitseinrichtung (Kessel kuehlt aus)"/> <enum bytes="C2" text="Kommunikationsfehler Solarregelung"/> <enum bytes="C5" text="Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M1"/> <enum bytes="C6" text="Kommunikationsfehler drehzahlgeregelte Heizkreispumpe, Heizkreis M2"/> <enum bytes="C7" text="Falsche Codierung der Heizkreispumpe"/> <enum bytes="C9" text="Stoermeldeeingang am Schaltmodul-V aktiv"/> <enum bytes="CD" text="Kommunikationsfehler Vitocom 100 (KM-BUS)"/> <enum bytes="CE" text="Kommunikationsfehler Schaltmodul-V"/> <enum bytes="CF" text="Kommunikationsfehler LON Modul"/> <enum bytes="D1" text="Brennerstoerung"/> <enum bytes="D4" text="Sicherheitstemperaturbegrenzer hat ausgeloest oder Stoermeldemodul nicht richtig gesteckt"/> <enum bytes="DA" text="Kurzschluss Raumtemperatursensor, Heizkreis M1"/> <enum bytes="DB" text="Kurzschluss Raumtemperatursensor, Heizkreis M2"/> <enum bytes="DD" text="Unterbrechung Raumtemperatursensor, Heizkreis M1"/> <enum bytes="DE" text="Unterbrechung Raumtemperatursensor, Heizkreis M2"/> <enum bytes="E4" text="Fehler Versorgungsspannung"/> <enum bytes="E5" text="Interner Fehler (Ionisationselektrode)"/> <enum bytes="E6" text="Abgas- / Zuluftsystem verstopft"/> <enum bytes="F0" text="Interner Fehler (Regelung tauschen)"/> <enum bytes="F1" text="Abgastemperaturbegrenzer ausgeloest"/> <enum bytes="F2" text="Temperaturbegrenzer ausgeloest"/> <enum bytes="F3" text="Flammensigal beim Brennerstart bereits vorhanden"/> <enum bytes="F4" text="Flammensigal nicht vorhanden"/> <enum bytes="F7" text="Differenzdrucksensor defekt"/> <enum bytes="F8" text="Brennstoffventil schliesst zu spaet"/> <enum bytes="F9" text="Geblaesedrehzahl beim Brennerstart zu niedrig"/> <enum bytes="FA" text="Geblaesestillstand nicht erreicht"/> <enum bytes="FD" text="Fehler Gasfeuerungsautomat"/> <enum bytes="FE" text="Starkes Stoerfeld (EMV) in der Naehe oder Elektronik defekt"/> <enum bytes="FF" text="Starkes Stoerfeld (EMV) in der Naehe oder interner Fehler"/> <enum text="UNKNOWN"/> </unit> <unit name="DeviceType"> <abbrev>DT</abbrev> <type>enum</type> <enum bytes="20 53 01 2B" text="V200WB2 ID=2053 Protokoll:GWG_VBEM"/> <enum bytes="20 94" text="V200KW1 ID=2094 Protokoll:KW"/> <enum bytes="20 98" text="V200KW2 ID=2098 Protokoll:KW"/> <enum text="UNKNOWN"/> </unit> <unit name="Brenner Stunden"> <abbrev>BH</abbrev> <type>uchar</type> <calc get="(B1 * 100)+B0"/> <entity>h</entity> </unit> <unit name="ErrorStateGWG"> <abbrev>ESG</abbrev> <type>enum</type> <enum bytes="00" text="Keine Stoerung"/> <enum bytes="02" text="Fehler Sicherheitskette"/> <enum bytes="04" text="Brennerstoerung 04"/> <enum bytes="05" text="Brennerstoerung 05"/> <enum bytes="07" text="Brennerstoerung 07"/> <enum bytes="08" text="Brennerstoerung 09"/> <enum bytes="08" text="Brennerstoerung 09"/> <enum bytes="0A" text="Brennerstoerung 10"/> <enum text="UNKNOWN"/> </unit> <unit name="Bitstatus"> <abbrev>BST</abbrev> <type>uchar</type> <icalc get="(B0 & (0x01<<BP))>> BP"/> <enum bytes="00" text="0"/> <enum bytes="01" text="1"/> <enum text="UNKNOWN"/> </unit> <unit name="HKP Pumpentyp"> <abbrev>HKT</abbrev> <type>uchar</type> <icalc get="(B0 & (0x01<<BP))>> BP"/> <enum bytes="00" text="stufig"/> <enum bytes="01" text="drehzahlgeregelt"/> <enum text="UNKNOWN"/> </unit> </units> <protocols> <protocol name="KW2"> <macros> <macro name="SYNC"> <command>SEND 04;WAIT 05</command> </macro> <macro name="GETADDR"> <command>SEND 01 F7</command> </macro> <macro name="SETADDR"> <command>SEND 01 F4</command> </macro> </macros> <commands> <command name="getaddr"> <send>SYNC;GETADDR $addr $hexlen;RECV $len $unit</send> </command> <command name="setaddr"> <send>SYNC;SETADDR $addr $hexlen;SEND BYTES $unit;RECV 1 SR</send> </command> </commands> </protocol> <protocol name="GWG"> <macros> <macro name="SYNC"> <command>SEND 04;WAIT 05</command> </macro> <macro name="GETADDR"> <command>SEND 01 CB</command> </macro> <macro name="GETBADDR"> <command>SEND 01 9E</command> </macro> <macro name="GETVADDR"> <command>SEND 01 C7</command> </macro> <macro name="GETPADDR"> <command>SEND 01 6E</command> </macro> <macro name="GETEADDR"> <command>SEND 01 AE</command> </macro> <macro name="GETXADDR"> <command>SEND 01 C5</command> </macro> <macro name="GETKMADDR"> <command>SEND 01 43</command> </macro> </macros> <commands> <command name="getaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETADDR $addr $hexlen 04;RECV $len $unit</send> </command> <command name="gettestaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="getbaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETBADDR $addr $hexlen 04;RECV $len $unit</send> </command> <command name="getbtestaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETBADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="getpaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETPADDR $addr $hexlen 04;RECV $len $unit</send> </command> <command name="getptestaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETPADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="getvaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETVADDR $addr $hexlen 04;RECV $len $unit</send> </command> <command name="getvtestaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETVADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="geteaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETEADDR $addr $hexlen 04;RECV $len $unit</send> </command> <command name="getetestaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETEADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="getxaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETXADDR $addr $hexlen 04;RECV $len $unit</send> </command> <command name="getxtestaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETXADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="getkmaddr"> <send>SYNC;GETKMDDR $addr $hexlen 04;RECV $len $unit</send> <retry>3</retry> <recvTimeout>150</recvTimeout> </command> <command name="getkmtestaddr"> <retry>3</retry> <recvTimeout>150</recvTimeout> <send>SYNC;GETKMADDR;SEND BYTES;SEND 01 04;RECV 1</send> </command> <command name="init"> <send>SEND 16 00 00;PAUSE 100;SEND 16 00 00;PAUSE 100;SEND 16 00 00;PAUSE 100;SEND 16 00 00;PAUSE 100</send> </command> <command name="setaddr"> <send>SYNC;RECV 1</send> </command> </commands> </protocol> </protocols> <extern xmlns:xi="http://www.w3.org/2003/XInclude"> <xi:include href="vito.xml" parse="xml"/> </extern> </V-Control> 07070100000044000081A4000028240000003200000001607BF44800008755000000000000000000000000000000000000003700000000vcontrold-v0.98.10+git20210418.977e6f5/xml/kw/vito.xml<?xml version="1.0"?> <vito> <devices> <device ID="2098" name="V200KW2" protocol="KW2"/> <device ID="2053" name="GWG_VBEM" protocol="GWG"/> </devices> <commands> <command name="getTempA" protocmd="getaddr"> <addr>0800</addr> <len>2</len> <unit>UT</unit> <error>05 05</error> <description>Ermittle die Aussentemeratur in Grad C</description> <device ID="2053"> <addr>6F</addr> <unit>UT1</unit> <len>1</len> </device> </command> <command name="getTempWWist" protocmd="getaddr"> <addr>0804</addr> <len>2</len> <unit>UT</unit> <error>05 05</error> <description>Ermittle die Warmwassertemperatur in Grad C</description> <device ID="2053"> <addr>42</addr> <unit>UT1U</unit> <len>1</len> </device> </command> <command name="getTempWWsoll" protocmd="getaddr"> <addr>6300</addr> <len>1</len> <unit>ST</unit> <description>Ermittle die Warmwassersolltemperatur in Grad C</description> <device ID="2053"> <addr>5C</addr> <unit>UT1</unit> <len>1</len> </device> </command> <command name="getTempKist" protocmd="getaddr"> <addr>0802</addr> <len>2</len> <unit>UT</unit> <error>05 05</error> <description>Ermittle die Kesseltemperatur in Grad C</description> <device ID="2053"> <addr>70</addr> <unit>UT1</unit> <len>1</len> </device> </command> <command name="getTempKsoll" protocmd="getaddr"> <addr>5502</addr> <len>2</len> <unit>UT</unit> <error>05 05</error> <description>Ermittle die Kesselsolltemperatur in Grad C</description> <device ID="2053"> <addr>71</addr> <unit>UT1</unit> <len>1</len> </device> </command> <command name="getTempVListM1" protocmd="getaddr"> <len>2</len> <unit>UT</unit> <description>Ermittle die Vorlauftemperatur M1 in Grad C</description> <device ID="2053"/> </command> <command name="getTempVListM2" protocmd="getaddr"> <addr>080C</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Vorlauftemperatur M2 in Grad C</description> <device ID="2053"> <addr>41</addr> <unit>UT1</unit> <len>1</len> </device> </command> <command name="getTempVLsollM1" protocmd="getaddr"> <addr>2544</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Vorlaufsolltemperatur M1 in Grad C</description> <device ID="2053"> <addr>69</addr> <unit>UT1</unit> <len>1</len> </device> </command> <command name="getTempVLsollM2" protocmd="getaddr"> <addr>3544</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Vorlaufsolltemperatur M2 in Grad C</description> <device ID="2053"> <addr>63</addr> <unit>UT1</unit> <len>1</len> </device> </command> <command name="getTempVLsollM3" protocmd="getaddr"> <addr>4544</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Vorlaufsolltemperatur M3 in Grad C</description> <device ID="2053"/> </command> <command name="getTempKol" protocmd="getaddr"> <addr>6564</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Kollektortemperatur in Grad C</description> <device ID="2053"/> </command> <command name="getTempSpu" protocmd="getaddr"> <addr>6566</addr> <len>2</len> <unit>UT</unit> <description>Ermittle die Speichertemperatur unten in Grad C</description> <device ID="2053"/> </command> <command name="getTempRaumNorSollM1" protocmd="getaddr"> <addr>2306</addr> <len>1</len> <unit>ST</unit> <description>Ermittle die Raumsolltemperatur normal M1 in Grad C</description> <device ID="2053"> <addr>53</addr> <len>1</len> <unit>UTI</unit> </device> </command> <command name="setTempRaumNorSollM1" protocmd="setaddr"> <addr>2306</addr> <len>1</len> <unit>ST</unit> <description>Setze die Raumsolltemperatur normal M1 in Grad C</description> <device ID="2053"> <addr>53</addr> <len>1</len> <unit>UTI</unit> </device> </command> <command name="getTempRaumNorSollM2" protocmd="getaddr"> <addr>3306</addr> <len>1</len> <unit>ST</unit> <description>Ermittle die Raumsolltemperatur normal M2 in Grad C</description> <device ID="2053"/> </command> <command name="getTempRaumRedSollM1" protocmd="getaddr"> <addr>2307</addr> <len>1</len> <unit>ST</unit> <description>Ermittle die Raumsolltemperatur reduziert M1 in Grad C</description> <device ID="2053"> <addr>54</addr> <len>1</len> <unit>UTI</unit> </device> </command> <command name="setTempRaumRedSollM1" protocmd="setaddr"> <addr>2307</addr> <len>1</len> <unit>ST</unit> <description>Setze die Raumsolltemperatur reduziert M1 in Grad C</description> <device ID="2053"> <addr>54</addr> <len>1</len> <unit>UTI</unit> </device> </command> <command name="getTempRaumRedSollM2" protocmd="getaddr"> <addr>3307</addr> <len>1</len> <unit>ST</unit> <description>Ermittle die Raumsolltemperatur reduziert M2 in Grad C</description> <device ID="2053"/> </command> <command name="getBrennerStatus" protocmd="getaddr"> <addr>551E</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Brennerstatus</description> <device ID="2053"> <addr>22</addr> <len>1</len> <bit>1</bit> <unit>BST</unit> </device> </command> <command name="getBrennerStarts" protocmd="getaddr"> <addr>088A</addr> <len>2</len> <unit>CO</unit> <description>Ermittle die Brennerstarts</description> <device ID="2053"/> </command> <command name="getBrennerStunden1" protocmd="getaddr"> <addr>08A7</addr> <len>4</len> <unit>CS</unit> <description>Ermittle die Brennerstunden Stufe 1</description> <device ID="2053" protocmd="geteaddr"> <addr>17</addr> <len>2</len> <unit>BH</unit> </device> </command> <command name="getBrennerStunden2" protocmd="getaddr"> <addr>08AB</addr> <len>4</len> <unit>CS</unit> <description>Ermittle die Brennerstunden Stufe 2</description> <device ID="2053"/> </command> <command name="getPumpeStatusM1" protocmd="getaddr"> <addr>2906</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Pumpe M1</description> <device ID="2053" protocmd="getpaddr"> <addr>01</addr> <len>1</len> <bit>0</bit> <unit>BST</unit> </device> </command> <command name="getPumpeStatusSp" protocmd="getaddr"> <addr>0845</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Speicherladepumpe</description> <device ID="2053"/> </command> <command name="getPumpeStatusZirku" protocmd="getaddr"> <addr>0846</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Zirkulationspumpe</description> <device ID="2053" protocmd="getpaddr"> <addr>01</addr> <len>1</len> <bit>2</bit> <unit>BST</unit> </device> </command> <command name="getPumpeStatusSolar" protocmd="getaddr"> <addr>6552</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Zirkulationspumpe Solar</description> <device ID="2053"/> </command> <command name="getPumpeStatusM2" protocmd="getaddr"> <addr>3906</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Pumpe M2</description> <device ID="2053"/> </command> <command name="getMischerM1" protocmd="getaddr"> <addr>254C</addr> <len>1</len> <unit>PR</unit> <description>Ermittle Mischerposition M1</description> <device ID="2053"/> </command> <command name="getMischerM2" protocmd="getaddr"> <addr>354C</addr> <len>1</len> <unit>PR</unit> <description>Ermittle Mischerposition M2</description> <device ID="2053"/> </command> <command name="getMischerM3" protocmd="getaddr"> <addr>454C</addr> <len>1</len> <unit>PR</unit> <description>Ermittle Mischerposition M3</description> <device ID="2053"/> </command> <command name="getSolarStatusWW" protocmd="getaddr"> <addr>6551</addr> <len>1</len> <unit>RT</unit> <description>Ermittle den Status der Nachladeunterdrueckung</description> <device ID="2053"/> </command> <command name="getTimerM1Mo" protocmd="getaddr"> <addr>2000</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag M1</description> <device ID="2053"/> </command> <command name="getTimerM1Di" protocmd="getaddr"> <addr>2008</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag M1</description> <device ID="2053"/> </command> <command name="getTimerM1Mi" protocmd="getaddr"> <addr>2010</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit MIttwoch M1</description> <device ID="2053"/> </command> <command name="getTimerM1Do" protocmd="getaddr"> <addr>2018</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag M1</description> <device ID="2053"/> </command> <command name="getTimerM1Fr" protocmd="getaddr"> <addr>2020</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag M1</description> <device ID="2053"/> </command> <command name="getTimerM1Sa" protocmd="getaddr"> <addr>2028</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag M1</description> <device ID="2053"/> </command> <command name="getTimerM1So" protocmd="getaddr"> <addr>2030</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag M1</description> <device ID="2053"/> </command> <command name="getTimerM2Mo" protocmd="getaddr"> <addr>3000</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag M2</description> <device ID="2053"/> </command> <command name="getTimerM2Di" protocmd="getaddr"> <addr>3008</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag M2</description> <device ID="2053"/> </command> <command name="getTimerM2Mi" protocmd="getaddr"> <addr>3010</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch M2</description> <device ID="2053"/> </command> <command name="getTimerM2Do" protocmd="getaddr"> <addr>3018</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag M2</description> <device ID="2053"/> </command> <command name="getTimerM2Fr" protocmd="getaddr"> <addr>3020</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag M2</description> <device ID="2053"/> </command> <command name="getTimerM2Sa" protocmd="getaddr"> <addr>3028</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag M2</description> <device ID="2053"/> </command> <command name="getTimerM2So" protocmd="getaddr"> <addr>3030</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag M2</description> <device ID="2053"/> </command> <command name="getTimerWWMo" protocmd="getaddr"> <addr>2100</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag Warmwasser</description> <device ID="2053"/> </command> <command name="getTimerWWDi" protocmd="getaddr"> <addr>2108</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag Warmwasser</description> <device ID="2053"/> </command> <command name="getTimerWWMi" protocmd="getaddr"> <addr>2110</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch Warmwasser</description> <device ID="2053"/> </command> <command name="getTimerWWDo" protocmd="getaddr"> <addr>2118</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag Warmwasser</description> <device ID="2053"/> </command> <command name="getTimerWWFr" protocmd="getaddr"> <addr>2120</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag Warmwasser</description> <device ID="2053"/> </command> <command name="getTimerWWSa" protocmd="getaddr"> <addr>2128</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag Warmwasser</description> <device ID="2053"/> </command> <command name="getTimerWWSo" protocmd="getaddr"> <addr>2130</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag Warmwasser</description> <device ID="2053"/> </command> <command name="getTimerZirkuMo" protocmd="getaddr"> <addr>2200</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag Zirku</description> <device ID="2053"/> </command> <command name="getTimerZirkuDi" protocmd="getaddr"> <addr>2208</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag Zirku</description> <device ID="2053"/> </command> <command name="getTimerZirkuMi" protocmd="getaddr"> <addr>2210</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch Zirku</description> <device ID="2053"/> </command> <command name="getTimerZirkuDo" protocmd="getaddr"> <addr>2218</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag Zirku</description> <device ID="2053"/> </command> <command name="getTimerZirkuFr" protocmd="getaddr"> <addr>2220</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag Zirku</description> <device ID="2053"/> </command> <command name="getTimerZirkuSa" protocmd="getaddr"> <addr>2228</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag Zirku</description> <device ID="2053"/> </command> <command name="getTimerZirkuSo" protocmd="getaddr"> <addr>2230</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag Zirku</description> <device ID="2053"/> </command> <command name="getBetriebArtM1" protocmd="getaddr"> <addr>2301</addr> <len>1</len> <unit>BA</unit> <description>Betriebsart M1</description> <device ID="2053"> <addr>51</addr> <len>1</len> <unit>BA</unit> </device> </command> <command name="getBetriebArtM2" protocmd="getaddr"> <addr>3301</addr> <len>1</len> <unit>BA</unit> <description>Betriebsart M2</description> <device ID="2053"/> </command> <command name="getBetriebSparM1" protocmd="getaddr"> <addr>2302</addr> <len>1</len> <unit>RT</unit> <description>Betriebsart Spar M1</description> <device ID="2053"/> </command> <command name="getBetriebSparM2" protocmd="getaddr"> <addr>3302</addr> <len>1</len> <unit>RT</unit> <description>Betriebsart Spar M2</description> <device ID="2053"/> </command> <command name="getBetriebPartyM1" protocmd="getaddr"> <addr>2303</addr> <len>1</len> <unit>RT</unit> <description>Betriebsart Party M1</description> <device ID="2053"/> </command> <command name="getBetriebPartyM2" protocmd="getaddr"> <addr>3303</addr> <len>1</len> <unit>RT</unit> <description>Betriebsart Party M2</description> <device ID="2053"/> </command> <command name="getSolarStunden" protocmd="getaddr"> <addr>6568</addr> <len>2</len> <unit>CO</unit> <description>Solar Betriebsstunden</description> <device ID="2053"/> </command> <command name="getSolarLeistung" protocmd="getaddr"> <addr>6560</addr> <len>4</len> <unit>CO</unit> <description>Solar Leistung Gesamt</description> <device ID="2053"/> </command> <command name="getStatusFrostM1" protocmd="getaddr"> <addr>2500</addr> <len>1</len> <unit>ST</unit> <description>Status Frostwarnung M1</description> <device ID="2053"/> </command> <command name="getStatusFrostM2" protocmd="getaddr"> <addr>3500</addr> <len>1</len> <unit>ST</unit> <description>Status Frostwarnung M2</description> <device ID="2053"/> </command> <command name="getStatusStoerung" protocmd="getaddr"> <addr>7579</addr> <len>1</len> <unit>RT</unit> <description>Status Sammelstoerung</description> <device ID="2053"/> </command> <command name="getTempPartyM1" protocmd="getaddr"> <addr>2308</addr> <len>1</len> <unit>ST</unit> <description>Solltemperatur Partybetrieb M1</description> <device ID="2053"/> </command> <command name="getTempPartyM2" protocmd="getaddr"> <addr>3308</addr> <len>1</len> <unit>ST</unit> <description>Solltemperatur Partybetrieb M2</description> <device ID="2053"/> </command> <command name="getSystemTime" protocmd="getaddr"> <addr>088E</addr> <len>8</len> <unit>TI</unit> <description>Ermittle Systemzeit</description> <device ID="2053"/> </command> <command name="setSystemTime" protocmd="setaddr"> <addr>088E</addr> <len>8</len> <unit>TI</unit> <description>Setze Systemzeit</description> <device ID="2053"/> </command> <command name="setTempWWsoll" protocmd="setaddr"> <addr>6300</addr> <len>1</len> <unit>ST</unit> <description>Setze die Warmwassersolltemperatur in Grad C</description> <device ID="2053"/> </command> <command name="setTempPartyM1" protocmd="setaddr"> <addr>2308</addr> <len>1</len> <unit>ST</unit> <description>Setze die Warmwassersolltemperatur Party M1 in Grad C</description> <device ID="2053"/> </command> <command name="setTempPartyM2" protocmd="setaddr"> <addr>3308</addr> <len>1</len> <unit>ST</unit> <description>Setze die Warmwassersolltemperatur Party M2 in Grad C</description> <device ID="2053"/> </command> <command name="setBetriebArtM1" protocmd="setaddr"> <addr>2301</addr> <len>1</len> <unit>BA</unit> <description>Setze Betriebsart M1</description> <device ID="2053"> <addr>51</addr> <len>1</len> <unit>BA</unit> </device> </command> <command name="setBetriebSparM1" protocmd="setaddr"> <addr>2302</addr> <len>1</len> <unit>RT</unit> <description>Setze Betriebsart Spar M1</description> <device ID="2053"/> </command> <command name="setBetriebPartyM1" protocmd="setaddr"> <addr>2303</addr> <len>1</len> <unit>RT</unit> <description>Setze Betriebsart Party M1</description> <device ID="2053"/> </command> <command name="setBetriebPartyM2" protocmd="setaddr"> <addr>3303</addr> <len>1</len> <unit>RT</unit> <description>Setze Betriebsart Party M2</description> <device ID="2053"/> </command> <command name="setPumpeStatusZirku" protocmd="setaddr"> <addr>0846</addr> <len>1</len> <unit>RT</unit> <description>Setze den Status der Zirkulationspumpe</description> <device ID="2053"> <addr>01</addr> <len>1</len> <bit>2</bit> <precommand>getPumpeStatusZirku</precommand> <unit>BA</unit> </device> </command> <command name="setTimerM1Mo" protocmd="setaddr"> <addr>2000</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag M1</description> <device ID="2053"/> </command> <command name="setTimerM1Di" protocmd="setaddr"> <addr>2008</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag M1</description> <device ID="2053"/> </command> <command name="setTimerM1Mi" protocmd="setaddr"> <addr>2010</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch M1</description> <device ID="2053"/> </command> <command name="setTimerM1Do" protocmd="setaddr"> <addr>2018</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag M1</description> <device ID="2053"/> </command> <command name="setTimerM1Fr" protocmd="setaddr"> <addr>2020</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag M1</description> <device ID="2053"/> </command> <command name="setTimerM1Sa" protocmd="setaddr"> <addr>2028</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag M1</description> <device ID="2053"/> </command> <command name="setTimerM1So" protocmd="setaddr"> <addr>2030</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag M1</description> <device ID="2053"/> </command> <command name="setTimerM2Mo" protocmd="setaddr"> <addr>3000</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag M2</description> <device ID="2053"/> </command> <command name="setTimerM2Di" protocmd="setaddr"> <addr>3008</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag M2</description> <device ID="2053"/> </command> <command name="setTimerM2Mi" protocmd="setaddr"> <addr>3010</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch M2</description> <device ID="2053"/> </command> <command name="setTimerM2Do" protocmd="setaddr"> <addr>3018</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag M2</description> <device ID="2053"/> </command> <command name="setTimerM2Fr" protocmd="setaddr"> <addr>3020</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag M2</description> <device ID="2053"/> </command> <command name="setTimerM2Sa" protocmd="setaddr"> <addr>3028</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag M2</description> <device ID="2053"/> </command> <command name="setTimerM2So" protocmd="setaddr"> <addr>3030</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag M2</description> <device ID="2053"/> </command> <command name="setTimerWWMo" protocmd="setaddr"> <addr>2100</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerWWDi" protocmd="setaddr"> <addr>2108</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerWWMi" protocmd="setaddr"> <addr>2110</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerWWDo" protocmd="setaddr"> <addr>2118</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerWWFr" protocmd="setaddr"> <addr>2120</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerWWSa" protocmd="setaddr"> <addr>2128</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerWWSo" protocmd="setaddr"> <addr>2130</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag Warmwasser</description> <device ID="2053"/> </command> <command name="setTimerZirkuMo" protocmd="setaddr"> <addr>2200</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Montag Zirku</description> <device ID="2053"/> </command> <command name="setTimerZirkuDi" protocmd="setaddr"> <addr>2208</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Dienstag Zirku</description> <device ID="2053"/> </command> <command name="setTimerZirkuMi" protocmd="setaddr"> <addr>2210</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Mittwoch Zirku</description> <device ID="2053"/> </command> <command name="setTimerZirkuDo" protocmd="setaddr"> <addr>2218</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Donnerstag Zirku</description> <device ID="2053"/> </command> <command name="setTimerZirkuFr" protocmd="setaddr"> <addr>2220</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Freitag Zirku</description> <device ID="2053"/> </command> <command name="setTimerZirkuSa" protocmd="setaddr"> <addr>2228</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Samstag Zirku</description> <device ID="2053"/> </command> <command name="setTimerZirkuSo" protocmd="setaddr"> <addr>2230</addr> <len>8</len> <unit>CT</unit> <description>Schaltzeit Sonntag Zirku</description> <device ID="2053"/> </command> <command name="getError0" protocmd="getaddr"> <addr>7507</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 1</description> <device ID="2053"> <addr>3F</addr> <len>1</len> <unit>ESG</unit> </device> </command> <command name="getError1" protocmd="getaddr"> <addr>7510</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 2</description> <device ID="2053"/> </command> <command name="getError2" protocmd="getaddr"> <addr>7519</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 3</description> <device ID="2053"/> </command> <command name="getError3" protocmd="getaddr"> <addr>7522</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 4</description> <device ID="2053"/> </command> <command name="getError4" protocmd="getaddr"> <addr>752B</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 5</description> <device ID="2053"/> </command> <command name="getError5" protocmd="getaddr"> <addr>7534</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 6</description> <device ID="2053"/> </command> <command name="getError6" protocmd="getaddr"> <addr>753D</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 7</description> <device ID="2053"/> </command> <command name="getError7" protocmd="getaddr"> <addr>7546</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 8</description> <device ID="2053"/> </command> <command name="getError8" protocmd="getaddr"> <addr>754F</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 9</description> <device ID="2053"/> </command> <command name="getError9" protocmd="getaddr"> <addr>7558</addr> <len>9</len> <unit>ES</unit> <description>Ermittle Fehlerhistory Eintrag 10</description> <device ID="2053"/> </command> <command name="getNeigungM1" protocmd="getaddr"> <addr>2305</addr> <len>1</len> <unit>UN</unit> <description>Ermittle Neigung Heizkennlinie M1</description> <device ID="2053"> <addr>65</addr> <unit>UN</unit> <len>1</len> </device> </command> <command name="getNeigungM2" protocmd="getaddr"> <addr>3305</addr> <len>1</len> <unit>UN</unit> <description>Ermittle Neigung Heizkennlinie M2</description> <device ID="2053"> <addr>C4</addr> <unit>UN</unit> <len>1</len> </device> </command> <command name="getNiveauM1" protocmd="getaddr"> <addr>2304</addr> <len>1</len> <unit>ST</unit> <description>Ermittle Niveau Heizkennlinie M1</description> <device ID="2053"> <addr>64</addr> <unit>ST</unit> <len>1</len> </device> </command> <command name="getNiveauM2" protocmd="getaddr"> <addr>3304</addr> <len>1</len> <unit>ST</unit> <description>Ermittle Niveau Heizkennlinie M2</description> <device ID="2053"> <addr>C5</addr> <unit>ST</unit> <len>1</len> </device> </command> <command name="setNeigungM1" protocmd="setaddr"> <addr>2305</addr> <len>1</len> <unit>UN</unit> <description>Setze Neigung Heizkennlinie M1</description> <device ID="2053"/> </command> <command name="setNeigungM2" protocmd="setaddr"> <addr>3305</addr> <len>1</len> <unit>UN</unit> <description>Setze Neigung Heizkennlinie M2</description> <device ID="2053"/> </command> <command name="setNiveauM1" protocmd="setaddr"> <addr>2304</addr> <len>1</len> <unit>ST</unit> <description>Setze Niveau Heizkennlinie M1</description> <device ID="2053"/> </command> <command name="setNiveauM2" protocmd="setaddr"> <addr>3304</addr> <len>1</len> <unit>ST</unit> <description>Setze Niveau Heizkennlinie M2</description> <device ID="2053"/> </command> <command name="getDevType" protocmd="getaddr"> <addr>00F8</addr> <len>2</len> <unit>DT</unit> <description>Ermittle Device Typ der Anlage</description> <device ID="2053" protocmd="getvaddr"> <addr>F8</addr> <len>4</len> <error>05 05 05 05</error> </device> </command> <command name="init" protocmd="getaddr"> <description>Inintialisierung</description> <device ID="2053" protocmd="init"> <addr>dummy</addr> </device> </command> <command name="get" protocmd="gettestaddr"> <description>Testabfrage, Adresse eingeben</description> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> </command> <command name="vget" protocmd="getvtestaddr"> <description>Testabfrage, Virtuelle Adresse eingeben</description> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> </command> <command name="bget" protocmd="getbtestaddr"> <description>Testabfrage, Bedienteil Adresse eingeben</description> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> </command> <command name="pget" protocmd="getptestaddr"> <description>Testabfrage, Port Adresse eingeben</description> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> </command> <command name="eget" protocmd="getetestaddr"> <description>Testabfrage, EEProm Adresse eingeben</description> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> </command> <command name="xget" protocmd="getxtestaddr"> <description>Testabfrage, XRAM Adresse eingeben</description> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> </command> <command name="kmget" protocmd="getkmtestaddr"> <description>Testabfrage, KM-Bus EEProm Adresse eingeben</description> <device ID="2053"> <addr>dummy</addr> <len>1</len> </device> </command> <command name="getExtBA" protocmd="getxaddr"> <description>Ermittle Zustand der externen Betriebsartenumschaltung</description> <device ID="2053"> <addr>00</addr> <len>1</len> <bit>0</bit> <unit>BST</unit> </device> </command> <command name="getPumpeSollM1" protocmd="getaddr"> <description>Ermittle Solldrehzahl Pumpe M1</description> <device ID="2053"> <addr>B0</addr> <len>1</len> <unit>PR1</unit> </device> </command> <command name="getVentilStatus" protocmd="getpaddr"> <description>Ermittle Zustand Umschaltventil WW/Heizen</description> <device ID="2053"> <addr>01</addr> <len>1</len> <bit>1</bit> <unit>BST</unit> </device> </command> <command name="getHKPTyp" protocmd="geteaddr"> <description>Ermittle Typ der Heizkreispumpe</description> <device ID="2053"> <addr>05</addr> <len>1</len> <bit>5</bit> <unit>HKT</unit> </device> </command> <command name="getTempRueck" protocmd="getaddr"> <description>Ermittle die Rueckauftemepratur</description> <device ID="2053"> <addr>44</addr> <len>1</len> <bit>5</bit> <unit>UT1</unit> </device> </command> </commands> </vito> 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!889 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor