├── .github └── workflows │ ├── build.yml │ ├── build_linux.yml │ ├── build_linux_rpi.yml │ ├── build_windows_cygwin.yml │ ├── codeql.yml │ └── test.yml ├── .gitignore ├── CMakeLists.txt ├── COPYING ├── LICENSES ├── BSD-3-Clause.txt ├── CC-BY-SA-4.0.txt ├── CC0-1.0.txt └── GPL-3.0-or-later.txt ├── README.md ├── cmake ├── GitDescription.cmake ├── Toolchain-rpi.cmake └── UpdateVersion.cmake ├── doc ├── INSTALL.md ├── README-de.md ├── examples │ ├── README.txt │ ├── rrd.min.cmds │ ├── rrd.tmpl │ ├── rrdb │ │ ├── createRRDB.sh │ │ ├── graph.sh │ │ ├── rrdb-update.sh │ │ ├── rrdb-update.tmpl │ │ ├── vc-aufruf.txt │ │ └── vc-commands.txt │ ├── sim-2098.ini │ ├── sql.tmpl │ ├── vcontrold.initd.sh │ ├── vcontrold.service │ ├── vcontrold.xml │ └── vupdate.sh ├── man │ ├── CMakeLists.txt │ ├── vclient.rst │ ├── vcontrold.rst │ └── vsim.rst ├── original_authors.txt └── original_authors.txt.license ├── src ├── arithmetic.c ├── arithmetic.h ├── client.c ├── client.h ├── common.c ├── common.h ├── framer.c ├── framer.h ├── io.c ├── io.h ├── parser.c ├── parser.h ├── prompt.h ├── semaphore.c ├── semaphore.h ├── socket.c ├── socket.h ├── unit.c ├── unit.h ├── vclient.c ├── vclient.h ├── vcontrold.c ├── version.h.in ├── vsim.c ├── xmlconfig.c └── xmlconfig.h └── xml ├── 300 ├── vcontrold.xml └── vito.xml └── kw ├── vcontrold.xml └── vito.xml /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: BuildAll 2 | 3 | on: 4 | push: 5 | tags: 6 | - v[0-9]+.[0-9]+.[0-9]+ 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build_linux_rpi: 11 | name: Build for Raspberry Pi on RaspiOs 12 | uses: ./.github/workflows/build_linux_rpi.yml 13 | with: 14 | target: raspios_lite:latest 15 | artifact_archive: artifacts-build_rpi 16 | 17 | build_linux_rpi64: 18 | name: Build for arm64 Raspberry Pi on RaspiOs 19 | uses: ./.github/workflows/build_linux_rpi.yml 20 | with: 21 | target: raspios_lite_arm64:latest 22 | artifact_archive: artifacts-build_rpi64 23 | 24 | build_linux: 25 | name: Build for Linux (default) 26 | uses: ./.github/workflows/build_linux.yml 27 | with: 28 | artifact_archive: artifacts-build_linux 29 | 30 | build_cygwin_x86_64: 31 | name: Build for Windows with Cygwin (x86_64) 32 | uses: ./.github/workflows/build_windows_cygwin.yml 33 | with: 34 | platform: x86_64 35 | artifact_archive: artifacts-build_cygwin_x86_64 36 | 37 | upload: 38 | needs: [build_linux_rpi, build_linux, build_linux_rpi64, build_cygwin_x86_64] 39 | runs-on: ubuntu-latest 40 | steps: 41 | - uses: actions/checkout@v3 42 | with: 43 | fetch-depth: 0 44 | - name: Hack around https://github.com/actions/checkout/issues/290 45 | run: | 46 | git fetch --tags --force 47 | 48 | - name: Get Linux RPi build 49 | uses: actions/download-artifact@v4 50 | with: 51 | name: artifacts-build_rpi 52 | path: artifacts 53 | 54 | - name: Get Linux RPi arm64 build 55 | uses: actions/download-artifact@v4 56 | with: 57 | name: artifacts-build_rpi64 58 | path: artifacts 59 | 60 | - name: Get Linux build 61 | uses: actions/download-artifact@v4 62 | with: 63 | name: artifacts-build_linux 64 | path: artifacts 65 | 66 | - name: Get Cygwin (x86_64) build 67 | uses: actions/download-artifact@v4 68 | with: 69 | name: artifacts-build_cygwin_x86_64 70 | path: artifacts 71 | 72 | - name: Sum files 73 | run: | 74 | for FILE in artifacts/* ; do md5sum ${FILE} > ${FILE}.md5sum ; sha256sum ${FILE} > ${FILE}.sha256sum ; done 75 | ls -laF artifacts/ 76 | 77 | - name: Release 78 | if: ${{startsWith(github.ref, 'refs/tags/')}} 79 | uses: ncipollo/release-action@58ae73b360456532aafd58ee170c045abbeaee37 80 | with: 81 | artifacts: "artifacts/*" 82 | allowUpdates: true 83 | generateReleaseNotes: true 84 | omitDraftDuringUpdate: true 85 | -------------------------------------------------------------------------------- /.github/workflows/build_linux.yml: -------------------------------------------------------------------------------- 1 | name: Builds for Linux 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | artifact_archive: 7 | required: true 8 | type: string 9 | workflow_dispatch: 10 | inputs: 11 | artifact_archive: 12 | required: true 13 | type: string 14 | default: artifacts-build_linux 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v3 22 | with: 23 | fetch-depth: 0 24 | - name: Hack around https://github.com/actions/checkout/issues/290 25 | run: | 26 | git fetch --tags --force 27 | 28 | - name: Build on Ubuntu Linux 29 | run: | 30 | sudo apt-get update -y --allow-releaseinfo-change 31 | sudo apt-get install -y build-essential git cmake libxml2-dev python3-docutils zip checkinstall 32 | mkdir build 33 | cmake -S . -B ./build -DCMAKE_C_FLAGS="-Wall" -DCMAKE_VERBOSE_MAKEFILE=ON 34 | cmake --build ./build 35 | 36 | - name: Set env vars 37 | run: | 38 | ARCH="$(dpkg --print-architecture)" 39 | echo "ARCH=${ARCH}">> ${GITHUB_ENV} 40 | BUILD_DIR="./build" 41 | echo "BUILD_DIR=${BUILD_DIR}" >> ${GITHUB_ENV} 42 | VERSION=$(sed -n -e '/^#define VERSION /{s/#define VERSION "\(.*\)"/\1/;s/unknown/'"$(date +0.0.%Y%m%d)"'/g;p}' ${BUILD_DIR}/version.h) 43 | echo "VERSION=${VERSION}" >> ${GITHUB_ENV} 44 | GH_REPO=$(echo -n "${GITHUB_REPOSITORY}" | cut -d "/" -f 2) 45 | echo "GH_REPO=${GH_REPO}" >> ${GITHUB_ENV} 46 | GH_USER=$(echo -n "${GITHUB_REPOSITORY}" | cut -d "/" -f 1) 47 | echo "GH_USER=${GH_USER}" >> ./build/env 48 | DEPLOYFILEPREFIX="${GH_REPO}_${VERSION}" 49 | echo DEPLOYFILEPREFIX="${DEPLOYFILEPREFIX}" >> ${GITHUB_ENV} 50 | DEPLOYFILEPREFIX_BIN="${DEPLOYFILEPREFIX}-${GITHUB_RUN_NUMBER}_${ARCH}" 51 | echo DEPLOYFILEPREFIX_BIN="${DEPLOYFILEPREFIX_BIN}" >> ${GITHUB_ENV} 52 | cat ${GITHUB_ENV} 53 | 54 | - name: Checkinstall deb package creation 55 | run: | 56 | sudo checkinstall --strip=no --install=no --pkgname="${GH_REPO}" --pkgversion="${VERSION}" --pkgrelease=${GITHUB_RUN_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=./build/ -D -y cmake --build ./build/ --target install 57 | 58 | - name: Collect files 59 | run: | 60 | sudo chown -R $USER:$USER ./build/ 61 | for FILE in ./build/doc/man/*.1 ; do gzip ${FILE} ; done 62 | zip -j ./build/${DEPLOYFILEPREFIX_BIN}.zip ./build/vcontrold ./build/vclient ./build/doc/man/vcontrold.1.gz ./build/doc/man/vclient.1.gz COPYING README.md 63 | 64 | - name: Archive Source 65 | # this is just to provide a *.orig.tar.gz source archive as it is tradition for Debian packages 66 | # TODO: Use .gitattributes to set export-ignore instead of tar --delete 67 | run: | 68 | git archive --prefix "${GH_REPO}-${VERSION}/" -o "./build/${DEPLOYFILEPREFIX}.orig.tar" ${GITHUB_SHA} 69 | tar -rf "./build/${DEPLOYFILEPREFIX}.orig.tar" --owner=root --group=root --transform="s#^.*build/#${GH_REPO}-${VERSION}/src/#" ./build/version.h 70 | tar --delete -f "./build/${DEPLOYFILEPREFIX}.orig.tar" --wildcards "${GH_REPO}-${VERSION}/.*" 71 | gzip --best "./build/${DEPLOYFILEPREFIX}.orig.tar" 72 | tar tzvf "./build/${DEPLOYFILEPREFIX}.orig.tar.gz" --force-local 73 | 74 | - name: Collect files 2 75 | run: | 76 | mkdir artifact-upload 77 | mv ./build/*.zip ./build/*.deb ./build/*.tar.gz ./artifact-upload/ 78 | ls -laF ./artifact-upload/ 79 | 80 | - name: Upload artifacts 81 | uses: actions/upload-artifact@v3 82 | with: 83 | name: ${{ inputs.artifact_archive }} 84 | path: | 85 | artifact-upload/* 86 | if-no-files-found: error -------------------------------------------------------------------------------- /.github/workflows/build_linux_rpi.yml: -------------------------------------------------------------------------------- 1 | name: Builds for RPi on RaspiOS 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | target: 7 | description: 'RPi base_image target' 8 | # see https://github.com/pguyot/arm-runner-action 9 | required: true 10 | default: 'raspios_lite:latest' 11 | type: string 12 | # type: choice 13 | # options: 14 | # - raspios_lite:latest 15 | # - raspios_lite_arm64:latest 16 | # - raspi_1_bullseye:20220121 17 | artifact_archive: 18 | required: true 19 | type: string 20 | workflow_dispatch: 21 | inputs: 22 | target: 23 | description: 'RPi base_image target' 24 | # see https://github.com/pguyot/arm-runner-action 25 | required: true 26 | default: 'raspios_lite:latest' 27 | type: choice 28 | options: 29 | - raspios_lite:latest 30 | - raspios_lite_arm64:latest 31 | - raspi_1_bullseye:20220121 32 | artifact_archive: 33 | required: true 34 | type: string 35 | default: artifacts-build_raspios 36 | 37 | jobs: 38 | build: 39 | runs-on: ubuntu-latest 40 | steps: 41 | - name: Checkout 42 | uses: actions/checkout@v3 43 | with: 44 | fetch-depth: 0 45 | - name: Hack around https://github.com/actions/checkout/issues/290 46 | run: | 47 | git fetch --tags --force 48 | 49 | - name: Build on RaspiOs 50 | uses: pguyot/arm-runner-action@e04ca3becb581a2b52cabe31e53835ada344522f 51 | with: 52 | image_additional_mb: 1024 53 | base_image: ${{ inputs.target }} 54 | copy_artifact_path: build 55 | import_github_env: true 56 | commands: | 57 | apt-get update -y --allow-releaseinfo-change 58 | apt-get install -y build-essential git cmake libxml2-dev python3-docutils zip checkinstall 59 | mkdir build 60 | cmake -S . -B ./build -DCMAKE_C_FLAGS="-Wall" -DCMAKE_VERBOSE_MAKEFILE=ON 61 | cmake --build ./build 62 | ARCH="$(dpkg --print-architecture)" 63 | echo "ARCH=${ARCH}" > ./build/env 64 | BUILD_DIR="./build" 65 | echo "BUILD_DIR=${BUILD_DIR}" >> ./build/env 66 | VERSION=$(sed -n -e '/^#define VERSION /{s/#define VERSION "\(.*\)"/\1/;s/unknown/'"$(date +0.0.%Y%m%d)"'/g;p}' ${BUILD_DIR}/version.h) 67 | echo "VERSION=${VERSION}" >> ./build/env 68 | GH_REPO=$(echo -n "${GITHUB_REPOSITORY}" | cut -d "/" -f 2) 69 | echo "GH_REPO=${GH_REPO}" >> ./build/env 70 | GH_USER=$(echo -n "${GITHUB_REPOSITORY}" | cut -d "/" -f 1) 71 | echo "GH_USER=${GH_USER}" >> ./build/env 72 | DEPLOYFILEPREFIX="${GH_REPO}_${VERSION}" 73 | echo DEPLOYFILEPREFIX="${DEPLOYFILEPREFIX}" >> ./build/env 74 | DEPLOYFILEPREFIX_BIN="${DEPLOYFILEPREFIX}-${GITHUB_RUN_NUMBER}_${ARCH}" 75 | echo DEPLOYFILEPREFIX_BIN="${DEPLOYFILEPREFIX_BIN}" >> ./build/env 76 | sudo checkinstall --strip=no --install=no --pkgname="${GH_REPO}" --pkgversion="${VERSION}" --pkgrelease=${GITHUB_RUN_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=./build/ -D -y cmake --build ./build/ --target install 77 | 78 | - name: Set env vars 79 | run: | 80 | source ./build/env 81 | cat ./build/env >> ${GITHUB_ENV} 82 | cat ${GITHUB_ENV} 83 | 84 | - name: Collect files 85 | run: | 86 | sudo chown -R $USER:$USER ./build/ 87 | for FILE in ./build/doc/man/*.1 ; do gzip ${FILE} ; done 88 | zip -j ./build/${DEPLOYFILEPREFIX_BIN}.zip ./build/vcontrold ./build/vclient ./build/doc/man/vcontrold.1.gz ./build/doc/man/vclient.1.gz COPYING README.md 89 | dpkg --info "./build/${DEPLOYFILEPREFIX_BIN}.deb" 90 | dpkg --contents "./build/${DEPLOYFILEPREFIX_BIN}.deb" 91 | mkdir artifact-upload 92 | mv ./build/*.zip ./build/*.deb ./artifact-upload/ 93 | ls -laF ./artifact-upload/ 94 | 95 | - name: Upload artifacts 96 | uses: actions/upload-artifact@v3 97 | with: 98 | name: ${{ inputs.artifact_archive }} 99 | path: | 100 | artifact-upload/* 101 | if-no-files-found: error 102 | -------------------------------------------------------------------------------- /.github/workflows/build_windows_cygwin.yml: -------------------------------------------------------------------------------- 1 | name: Builds for Windows with Cygwin 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | platform: 7 | required: true 8 | type: string 9 | artifact_archive: 10 | required: true 11 | type: string 12 | workflow_dispatch: 13 | inputs: 14 | platform: 15 | description: 'Cygwin platform' 16 | required: true 17 | default: 'x86_64' 18 | type: choice 19 | options: 20 | - x86_64 21 | artifact_archive: 22 | required: true 23 | type: string 24 | default: artifacts-build_cygwin 25 | env: 26 | #CYGWIN_NOWINPATH: 1 27 | CHERE_INVOKING: 1 28 | 29 | jobs: 30 | build: 31 | runs-on: windows-latest 32 | defaults: 33 | run: 34 | shell: C:\cygwin\bin\bash.exe --login --norc -eo pipefail -o igncr '{0}' 35 | steps: 36 | - name: Checkout 37 | uses: actions/checkout@v3 38 | with: 39 | fetch-depth: 0 40 | - name: Hack around https://github.com/actions/checkout/issues/290 41 | shell: powershell 42 | run: | 43 | git fetch --tags --force 44 | 45 | - name: Prepare environment 46 | shell: bash 47 | run: | 48 | git config --global core.autocrlf input 49 | 50 | - name: Install Cygwin environment 51 | uses: cygwin/cygwin-install-action@cf17b9c15958a86fd5b0a53332b91f890aecadfd 52 | with: 53 | platform: ${{ inputs.platform }} 54 | packages: cygwin-devel,make,git,gcc-core,libxml2,libxml2-devel,cmake,p7zip,libiconv,libiconv-devel,python39-docutils 55 | 56 | - name: Cmake configure 57 | env: 58 | CYGWIN_NOWINPATH: 1 59 | run: | 60 | git config --global core.autocrlf input 61 | mkdir build 62 | cmake -S . -B ./build -DCMAKE_C_FLAGS="-Wall" -DCMAKE_VERBOSE_MAKEFILE=ON -DMANPAGES=ON 63 | ls -laF build 64 | 65 | - name: Cmake build 66 | env: 67 | CYGWIN_NOWINPATH: 1 68 | run: | 69 | export PATH=/usr/bin:$(cygpath ${SYSTEMROOT})/system32 70 | git config --global --add safe.directory $(pwd) 71 | cmake --build build 72 | ls -laF build 73 | 74 | - name: Set env vars 75 | run: | 76 | ARCH="${{inputs.platform}}" 77 | echo "ARCH=${ARCH}" >> ${GITHUB_ENV} 78 | BUILD_DIR="./build" 79 | echo "BUILD_DIR=${BUILD_DIR}" >> ${GITHUB_ENV} 80 | VERSION=$(sed -n -e '/^#define VERSION /{s/#define VERSION "\(.*\)"/\1/;s/unknown/'"$(date +0.0.%Y%m%d)"'/g;p}' ${BUILD_DIR}/version.h) 81 | echo "VERSION=${VERSION}" >> ${GITHUB_ENV} 82 | GH_REPO=$(echo -n "${GITHUB_REPOSITORY}" | cut -d "/" -f 2) 83 | echo "GH_REPO=${GH_REPO}" >> ${GITHUB_ENV} 84 | GH_USER=$(echo -n "${GITHUB_REPOSITORY}" | cut -d "/" -f 1) 85 | echo "GH_USER=${GH_USER}" >> ./build/env 86 | DEPLOYFILEPREFIX="${GH_REPO}_${VERSION}" 87 | echo DEPLOYFILEPREFIX="${DEPLOYFILEPREFIX}" >> ${GITHUB_ENV} 88 | DEPLOYFILEPREFIX_BIN="${DEPLOYFILEPREFIX}-${GITHUB_RUN_NUMBER}_${ARCH}" 89 | echo DEPLOYFILEPREFIX_BIN="${DEPLOYFILEPREFIX_BIN}" >> ${GITHUB_ENV} 90 | cat ${GITHUB_ENV} 91 | 92 | - name: Collect files 93 | run: | 94 | mkdir artifact-upload 95 | echo ${VERSION} > ./build/VERSION 96 | cd ./build && cp ../COPYING ../README.md . && 7z a ../artifact-upload/vcontrold_$(echo -n ${VERSION} | sed -e s/^v//)-${GITHUB_RUN_NUMBER}-cygwin_${ARCH}.zip *.exe COPYING VERSION README.md 97 | 98 | - name: Upload artifacts 99 | uses: actions/upload-artifact@v3 100 | with: 101 | name: ${{ inputs.artifact_archive }} 102 | path: | 103 | artifact-upload/* 104 | if-no-files-found: error 105 | 106 | - name: Cleanup 107 | shell: powershell 108 | # this prevents the intrinsic "Post Checkout" step from accessing git.exe from Cygwin 109 | run: Rename-Item C:\cygwin\bin\git.exe cygwin_git.exe 110 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | # branches: [ "master", "main" ] 6 | pull_request: 7 | # # The branches below must be a subset of the branches above 8 | # branches: [ "master", "main" ] 9 | #schedule: 10 | # - cron: '15 20 * * 2' 11 | workflow_dispatch: 12 | 13 | jobs: 14 | analyze: 15 | name: Analyze 16 | runs-on: ubuntu-latest 17 | permissions: 18 | actions: read 19 | contents: read 20 | security-events: write 21 | 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | language: [ 'cpp' ] 26 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 27 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 28 | 29 | steps: 30 | - name: Checkout repository 31 | uses: actions/checkout@v3 32 | with: 33 | fetch-depth: 0 34 | - name: Hack around https://github.com/actions/checkout/issues/290 35 | run: | 36 | git fetch --tags --force 37 | 38 | - name: Installing needed dependencies 39 | run: | 40 | sudo apt-get install -y -qq libxml2-dev python3-docutils 41 | 42 | # Initializes the CodeQL tools for scanning. 43 | - name: Initialize CodeQL 44 | uses: github/codeql-action/init@v2 45 | with: 46 | languages: ${{ matrix.language }} 47 | 48 | - name: Build Application 49 | run: | 50 | mkdir build 51 | cmake -S . -B build -DVSIM=ON -DMANPAGES=ON -DCMAKE_VERBOSE_MAKEFILE=ON 52 | cmake --build build 53 | 54 | - name: Perform CodeQL Analysis 55 | uses: github/codeql-action/analyze@v2 56 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test Workflow 2 | # This workflow is just for testing techniques in GitHub Actions workflows 3 | # it is not part of the CI or CD of this repository 4 | 5 | on: 6 | push: 7 | branches: 8 | - 'test*' 9 | workflow_dispatch: 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v3 17 | with: 18 | fetch-depth: 0 19 | - name: Hack around https://github.com/actions/checkout/issues/290 20 | run: | 21 | git fetch --tags --force 22 | 23 | - name: Some git info 24 | run: | 25 | git pull 26 | git show-ref -d 27 | 28 | - name: Build on Ubuntu Linux 29 | run: | 30 | sudo apt-get install -y build-essential git cmake libxml2-dev python3-docutils zip checkinstall 31 | mkdir build 32 | cmake -S . -B ./build -DCMAKE_C_FLAGS="-Wall" -DCMAKE_VERBOSE_MAKEFILE=ON -DVSIM=ON 33 | cmake --build ./build 34 | 35 | - name: Set env vars 36 | run: | 37 | ARCH="$(dpkg --print-architecture)" 38 | echo "ARCH=${ARCH}">> ${GITHUB_ENV} 39 | BUILD_DIR="./build" 40 | echo "BUILD_DIR=${BUILD_DIR}" >> ${GITHUB_ENV} 41 | VERSION=$(sed -n -e '/^#define VERSION /{s/#define VERSION "\(.*\)"/\1/;s/unknown/'"$(date +0.0.%Y%m%d)"'/g;p}' ${BUILD_DIR}/version.h) 42 | echo "VERSION=${VERSION}" >> ${GITHUB_ENV} 43 | GH_REPO=$(echo -n "${GITHUB_REPOSITORY}" | cut -d "/" -f 2) 44 | echo "GH_REPO=${GH_REPO}" >> ${GITHUB_ENV} 45 | GH_USER=$(echo -n "${GITHUB_REPOSITORY}" | cut -d "/" -f 1) 46 | echo "GH_USER=${GH_USER}" >> ./build/env 47 | DEPLOYFILEPREFIX="${GH_REPO}_${VERSION}" 48 | echo DEPLOYFILEPREFIX="${DEPLOYFILEPREFIX}" >> ${GITHUB_ENV} 49 | DEPLOYFILEPREFIX_BIN="${DEPLOYFILEPREFIX}-${GITHUB_RUN_NUMBER}_${ARCH}" 50 | echo DEPLOYFILEPREFIX_BIN="${DEPLOYFILEPREFIX_BIN}" >> ${GITHUB_ENV} 51 | printenv 52 | git describe --tags --always --dirty 53 | cat ${GITHUB_ENV} 54 | 55 | - name: Collect files 56 | run: | 57 | PRIMARY_GROUP=$(id -g) 58 | sudo chown -R ${USER}:$(PRIMARY_GROUP) ./build/ 59 | mkdir artifacts 60 | for FILE in vcontrold vclient vsim version.h ; do cp -af ./build/${FILE} ./artifacts/ ; done 61 | 62 | - name: Upload artifacts 63 | uses: actions/upload-artifact@v3 64 | with: 65 | path: | 66 | artifacts/* 67 | if-no-files-found: error 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: none 2 | # 3 | # SPDX-License-Identifier: CC0-1.0 4 | 5 | build/ 6 | CMakeCache.txt 7 | CMakeFiles 8 | CMakeScripts 9 | Testing 10 | Makefile 11 | cmake_install.cmake 12 | install_manifest.txt 13 | compile_commands.json 14 | CTestTestfile.cmake 15 | *.o 16 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2022 Tobias Leupold 2 | # 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | cmake_minimum_required(VERSION 3.2.0) 6 | project(vcontrold C) 7 | 8 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 9 | # CMAKE_INSTALL_PREFIX defaults to /usr/local, but it should go to /usr 10 | set(CMAKE_INSTALL_PREFIX /usr) 11 | endif() 12 | 13 | option(MANPAGES "Build man pages via rst2man" ON) 14 | option(VCLIENT "Build the vclient helper program (for communication with vcontrold)" ON) 15 | option(VSIM "Build the vsim helper program (for development and testing purposes)" OFF) 16 | 17 | # additional define to compile on macOS Catalina by hmueller01 18 | if (APPLE) 19 | set (CMAKE_C_FLAGS "-D_DARWIN_C_SOURCE ${CMAKE_C_FLAGS}") 20 | endif (APPLE) 21 | 22 | find_package(LibXml2 REQUIRED) 23 | 24 | if(MANPAGES) 25 | find_program(RST2MAN NAMES rst2man rst2man.py) 26 | if(RST2MAN) 27 | message(STATUS "Found rst2man: ${RST2MAN}") 28 | else() 29 | message(FATAL_ERROR "Could not find a rst2man executable. Either set the \"MANPAGES\" " 30 | "option to \"OFF\" (via cmake -DMANPAGES=OFF) or install Python's " 31 | "Docutils (cf. http://docutils.sourceforge.net/).") 32 | endif() 33 | endif() 34 | 35 | add_custom_target( 36 | UpdateVersion ALL 37 | COMMAND ${CMAKE_COMMAND} 38 | -DBASE_DIR=${CMAKE_CURRENT_SOURCE_DIR} 39 | -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} 40 | -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/UpdateVersion.cmake 41 | COMMENT "Updating version header." 42 | BYPRODUCTS ${CMAKE_BINARY_DIR}/version.h 43 | ) 44 | include_directories(${CMAKE_BINARY_DIR}) 45 | 46 | add_definitions(-D_XOPEN_SOURCE=700) 47 | 48 | include_directories( 49 | ${LIBXML2_INCLUDE_DIR} 50 | ) 51 | 52 | set(vcontrold_SRCS 53 | ${CMAKE_CURRENT_SOURCE_DIR}/src/io.c 54 | ${CMAKE_CURRENT_SOURCE_DIR}/src/common.c 55 | ${CMAKE_CURRENT_SOURCE_DIR}/src/xmlconfig.c 56 | ${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c 57 | ${CMAKE_CURRENT_SOURCE_DIR}/src/socket.c 58 | ${CMAKE_CURRENT_SOURCE_DIR}/src/semaphore.c 59 | ${CMAKE_CURRENT_SOURCE_DIR}/src/framer.c 60 | ${CMAKE_CURRENT_SOURCE_DIR}/src/unit.c 61 | ${CMAKE_CURRENT_SOURCE_DIR}/src/arithmetic.c 62 | ${CMAKE_CURRENT_SOURCE_DIR}/src/vcontrold.c 63 | ) 64 | 65 | set(vclient_SRCS 66 | ${CMAKE_CURRENT_SOURCE_DIR}/src/common.c 67 | ${CMAKE_CURRENT_SOURCE_DIR}/src/socket.c 68 | ${CMAKE_CURRENT_SOURCE_DIR}/src/io.c 69 | ${CMAKE_CURRENT_SOURCE_DIR}/src/client.c 70 | ${CMAKE_CURRENT_SOURCE_DIR}/src/vclient.c 71 | ) 72 | 73 | set(vsim_SRCS 74 | ${CMAKE_CURRENT_SOURCE_DIR}/src/socket.c 75 | ${CMAKE_CURRENT_SOURCE_DIR}/src/vsim.c 76 | ) 77 | 78 | 79 | find_package(Threads) 80 | set(LIBS 81 | ${LIBS} 82 | ${LIBXML2_LIBRARIES} 83 | ${CMAKE_THREAD_LIBS_INIT} 84 | ${CMAKE_DL_LIBS} 85 | ) 86 | 87 | add_executable(vcontrold ${vcontrold_SRCS}) 88 | target_link_libraries(vcontrold ${LIBS}) 89 | add_dependencies(vcontrold UpdateVersion) 90 | 91 | if(VCLIENT) 92 | add_executable(vclient ${vclient_SRCS}) 93 | add_dependencies(vclient UpdateVersion) 94 | endif() 95 | 96 | if(VSIM) 97 | add_executable(vsim ${vsim_SRCS}) 98 | add_dependencies(vsim UpdateVersion) 99 | endif() 100 | 101 | if(MANPAGES) 102 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/doc/man) 103 | endif() 104 | 105 | install(TARGETS vcontrold DESTINATION ${CMAKE_INSTALL_PREFIX}/sbin) 106 | if(VCLIENT) 107 | install(TARGETS vclient DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) 108 | endif() 109 | if(VSIM) 110 | install(TARGETS vsim DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) 111 | endif() 112 | -------------------------------------------------------------------------------- /LICENSES/BSD-3-Clause.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) . All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 26 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /LICENSES/CC-BY-SA-4.0.txt: -------------------------------------------------------------------------------- 1 | Attribution-ShareAlike 4.0 International 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution-ShareAlike 4.0 International Public 58 | License 59 | 60 | By exercising the Licensed Rights (defined below), You accept and agree 61 | to be bound by the terms and conditions of this Creative Commons 62 | Attribution-ShareAlike 4.0 International Public License ("Public 63 | License"). To the extent this Public License may be interpreted as a 64 | contract, You are granted the Licensed Rights in consideration of Your 65 | acceptance of these terms and conditions, and the Licensor grants You 66 | such rights in consideration of benefits the Licensor receives from 67 | making the Licensed Material available under these terms and 68 | conditions. 69 | 70 | 71 | Section 1 -- Definitions. 72 | 73 | a. Adapted Material means material subject to Copyright and Similar 74 | Rights that is derived from or based upon the Licensed Material 75 | and in which the Licensed Material is translated, altered, 76 | arranged, transformed, or otherwise modified in a manner requiring 77 | permission under the Copyright and Similar Rights held by the 78 | Licensor. For purposes of this Public License, where the Licensed 79 | Material is a musical work, performance, or sound recording, 80 | Adapted Material is always produced where the Licensed Material is 81 | synched in timed relation with a moving image. 82 | 83 | b. Adapter's License means the license You apply to Your Copyright 84 | and Similar Rights in Your contributions to Adapted Material in 85 | accordance with the terms and conditions of this Public License. 86 | 87 | c. BY-SA Compatible License means a license listed at 88 | creativecommons.org/compatiblelicenses, approved by Creative 89 | Commons as essentially the equivalent of this Public License. 90 | 91 | d. Copyright and Similar Rights means copyright and/or similar rights 92 | closely related to copyright including, without limitation, 93 | performance, broadcast, sound recording, and Sui Generis Database 94 | Rights, without regard to how the rights are labeled or 95 | categorized. For purposes of this Public License, the rights 96 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 97 | Rights. 98 | 99 | e. Effective Technological Measures means those measures that, in the 100 | absence of proper authority, may not be circumvented under laws 101 | fulfilling obligations under Article 11 of the WIPO Copyright 102 | Treaty adopted on December 20, 1996, and/or similar international 103 | agreements. 104 | 105 | f. Exceptions and Limitations means fair use, fair dealing, and/or 106 | any other exception or limitation to Copyright and Similar Rights 107 | that applies to Your use of the Licensed Material. 108 | 109 | g. License Elements means the license attributes listed in the name 110 | of a Creative Commons Public License. The License Elements of this 111 | Public License are Attribution and ShareAlike. 112 | 113 | h. Licensed Material means the artistic or literary work, database, 114 | or other material to which the Licensor applied this Public 115 | License. 116 | 117 | i. Licensed Rights means the rights granted to You subject to the 118 | terms and conditions of this Public License, which are limited to 119 | all Copyright and Similar Rights that apply to Your use of the 120 | Licensed Material and that the Licensor has authority to license. 121 | 122 | j. Licensor means the individual(s) or entity(ies) granting rights 123 | under this Public License. 124 | 125 | k. Share means to provide material to the public by any means or 126 | process that requires permission under the Licensed Rights, such 127 | as reproduction, public display, public performance, distribution, 128 | dissemination, communication, or importation, and to make material 129 | available to the public including in ways that members of the 130 | public may access the material from a place and at a time 131 | individually chosen by them. 132 | 133 | l. Sui Generis Database Rights means rights other than copyright 134 | resulting from Directive 96/9/EC of the European Parliament and of 135 | the Council of 11 March 1996 on the legal protection of databases, 136 | as amended and/or succeeded, as well as other essentially 137 | equivalent rights anywhere in the world. 138 | 139 | m. You means the individual or entity exercising the Licensed Rights 140 | under this Public License. Your has a corresponding meaning. 141 | 142 | 143 | Section 2 -- Scope. 144 | 145 | a. License grant. 146 | 147 | 1. Subject to the terms and conditions of this Public License, 148 | the Licensor hereby grants You a worldwide, royalty-free, 149 | non-sublicensable, non-exclusive, irrevocable license to 150 | exercise the Licensed Rights in the Licensed Material to: 151 | 152 | a. reproduce and Share the Licensed Material, in whole or 153 | in part; and 154 | 155 | b. produce, reproduce, and Share Adapted Material. 156 | 157 | 2. Exceptions and Limitations. For the avoidance of doubt, where 158 | Exceptions and Limitations apply to Your use, this Public 159 | License does not apply, and You do not need to comply with 160 | its terms and conditions. 161 | 162 | 3. Term. The term of this Public License is specified in Section 163 | 6(a). 164 | 165 | 4. Media and formats; technical modifications allowed. The 166 | Licensor authorizes You to exercise the Licensed Rights in 167 | all media and formats whether now known or hereafter created, 168 | and to make technical modifications necessary to do so. The 169 | Licensor waives and/or agrees not to assert any right or 170 | authority to forbid You from making technical modifications 171 | necessary to exercise the Licensed Rights, including 172 | technical modifications necessary to circumvent Effective 173 | Technological Measures. For purposes of this Public License, 174 | simply making modifications authorized by this Section 2(a) 175 | (4) never produces Adapted Material. 176 | 177 | 5. Downstream recipients. 178 | 179 | a. Offer from the Licensor -- Licensed Material. Every 180 | recipient of the Licensed Material automatically 181 | receives an offer from the Licensor to exercise the 182 | Licensed Rights under the terms and conditions of this 183 | Public License. 184 | 185 | b. Additional offer from the Licensor -- Adapted Material. 186 | Every recipient of Adapted Material from You 187 | automatically receives an offer from the Licensor to 188 | exercise the Licensed Rights in the Adapted Material 189 | under the conditions of the Adapter's License You apply. 190 | 191 | c. No downstream restrictions. You may not offer or impose 192 | any additional or different terms or conditions on, or 193 | apply any Effective Technological Measures to, the 194 | Licensed Material if doing so restricts exercise of the 195 | Licensed Rights by any recipient of the Licensed 196 | Material. 197 | 198 | 6. No endorsement. Nothing in this Public License constitutes or 199 | may be construed as permission to assert or imply that You 200 | are, or that Your use of the Licensed Material is, connected 201 | with, or sponsored, endorsed, or granted official status by, 202 | the Licensor or others designated to receive attribution as 203 | provided in Section 3(a)(1)(A)(i). 204 | 205 | b. Other rights. 206 | 207 | 1. Moral rights, such as the right of integrity, are not 208 | licensed under this Public License, nor are publicity, 209 | privacy, and/or other similar personality rights; however, to 210 | the extent possible, the Licensor waives and/or agrees not to 211 | assert any such rights held by the Licensor to the limited 212 | extent necessary to allow You to exercise the Licensed 213 | Rights, but not otherwise. 214 | 215 | 2. Patent and trademark rights are not licensed under this 216 | Public License. 217 | 218 | 3. To the extent possible, the Licensor waives any right to 219 | collect royalties from You for the exercise of the Licensed 220 | Rights, whether directly or through a collecting society 221 | under any voluntary or waivable statutory or compulsory 222 | licensing scheme. In all other cases the Licensor expressly 223 | reserves any right to collect such royalties. 224 | 225 | 226 | Section 3 -- License Conditions. 227 | 228 | Your exercise of the Licensed Rights is expressly made subject to the 229 | following conditions. 230 | 231 | a. Attribution. 232 | 233 | 1. If You Share the Licensed Material (including in modified 234 | form), You must: 235 | 236 | a. retain the following if it is supplied by the Licensor 237 | with the Licensed Material: 238 | 239 | i. identification of the creator(s) of the Licensed 240 | Material and any others designated to receive 241 | attribution, in any reasonable manner requested by 242 | the Licensor (including by pseudonym if 243 | designated); 244 | 245 | ii. a copyright notice; 246 | 247 | iii. a notice that refers to this Public License; 248 | 249 | iv. a notice that refers to the disclaimer of 250 | warranties; 251 | 252 | v. a URI or hyperlink to the Licensed Material to the 253 | extent reasonably practicable; 254 | 255 | b. indicate if You modified the Licensed Material and 256 | retain an indication of any previous modifications; and 257 | 258 | c. indicate the Licensed Material is licensed under this 259 | Public License, and include the text of, or the URI or 260 | hyperlink to, this Public License. 261 | 262 | 2. You may satisfy the conditions in Section 3(a)(1) in any 263 | reasonable manner based on the medium, means, and context in 264 | which You Share the Licensed Material. For example, it may be 265 | reasonable to satisfy the conditions by providing a URI or 266 | hyperlink to a resource that includes the required 267 | information. 268 | 269 | 3. If requested by the Licensor, You must remove any of the 270 | information required by Section 3(a)(1)(A) to the extent 271 | reasonably practicable. 272 | 273 | b. ShareAlike. 274 | 275 | In addition to the conditions in Section 3(a), if You Share 276 | Adapted Material You produce, the following conditions also apply. 277 | 278 | 1. The Adapter's License You apply must be a Creative Commons 279 | license with the same License Elements, this version or 280 | later, or a BY-SA Compatible License. 281 | 282 | 2. You must include the text of, or the URI or hyperlink to, the 283 | Adapter's License You apply. You may satisfy this condition 284 | in any reasonable manner based on the medium, means, and 285 | context in which You Share Adapted Material. 286 | 287 | 3. You may not offer or impose any additional or different terms 288 | or conditions on, or apply any Effective Technological 289 | Measures to, Adapted Material that restrict exercise of the 290 | rights granted under the Adapter's License You apply. 291 | 292 | 293 | Section 4 -- Sui Generis Database Rights. 294 | 295 | Where the Licensed Rights include Sui Generis Database Rights that 296 | apply to Your use of the Licensed Material: 297 | 298 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 299 | to extract, reuse, reproduce, and Share all or a substantial 300 | portion of the contents of the database; 301 | 302 | b. if You include all or a substantial portion of the database 303 | contents in a database in which You have Sui Generis Database 304 | Rights, then the database in which You have Sui Generis Database 305 | Rights (but not its individual contents) is Adapted Material, 306 | 307 | including for purposes of Section 3(b); and 308 | c. You must comply with the conditions in Section 3(a) if You Share 309 | all or a substantial portion of the contents of the database. 310 | 311 | For the avoidance of doubt, this Section 4 supplements and does not 312 | replace Your obligations under this Public License where the Licensed 313 | Rights include other Copyright and Similar Rights. 314 | 315 | 316 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 317 | 318 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 319 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 320 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 321 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 322 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 323 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 324 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 325 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 326 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 327 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 328 | 329 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 330 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 331 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 332 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 333 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 334 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 335 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 336 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 337 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 338 | 339 | c. The disclaimer of warranties and limitation of liability provided 340 | above shall be interpreted in a manner that, to the extent 341 | possible, most closely approximates an absolute disclaimer and 342 | waiver of all liability. 343 | 344 | 345 | Section 6 -- Term and Termination. 346 | 347 | a. This Public License applies for the term of the Copyright and 348 | Similar Rights licensed here. However, if You fail to comply with 349 | this Public License, then Your rights under this Public License 350 | terminate automatically. 351 | 352 | b. Where Your right to use the Licensed Material has terminated under 353 | Section 6(a), it reinstates: 354 | 355 | 1. automatically as of the date the violation is cured, provided 356 | it is cured within 30 days of Your discovery of the 357 | violation; or 358 | 359 | 2. upon express reinstatement by the Licensor. 360 | 361 | For the avoidance of doubt, this Section 6(b) does not affect any 362 | right the Licensor may have to seek remedies for Your violations 363 | of this Public License. 364 | 365 | c. For the avoidance of doubt, the Licensor may also offer the 366 | Licensed Material under separate terms or conditions or stop 367 | distributing the Licensed Material at any time; however, doing so 368 | will not terminate this Public License. 369 | 370 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 371 | License. 372 | 373 | 374 | Section 7 -- Other Terms and Conditions. 375 | 376 | a. The Licensor shall not be bound by any additional or different 377 | terms or conditions communicated by You unless expressly agreed. 378 | 379 | b. Any arrangements, understandings, or agreements regarding the 380 | Licensed Material not stated herein are separate from and 381 | independent of the terms and conditions of this Public License. 382 | 383 | 384 | Section 8 -- Interpretation. 385 | 386 | a. For the avoidance of doubt, this Public License does not, and 387 | shall not be interpreted to, reduce, limit, restrict, or impose 388 | conditions on any use of the Licensed Material that could lawfully 389 | be made without permission under this Public License. 390 | 391 | b. To the extent possible, if any provision of this Public License is 392 | deemed unenforceable, it shall be automatically reformed to the 393 | minimum extent necessary to make it enforceable. If the provision 394 | cannot be reformed, it shall be severed from this Public License 395 | without affecting the enforceability of the remaining terms and 396 | conditions. 397 | 398 | c. No term or condition of this Public License will be waived and no 399 | failure to comply consented to unless expressly agreed to by the 400 | Licensor. 401 | 402 | d. Nothing in this Public License constitutes or may be interpreted 403 | as a limitation upon, or waiver of, any privileges and immunities 404 | that apply to the Licensor or You, including from the legal 405 | processes of any jurisdiction or authority. 406 | 407 | 408 | ======================================================================= 409 | 410 | Creative Commons is not a party to its public 411 | licenses. Notwithstanding, Creative Commons may elect to apply one of 412 | its public licenses to material it publishes and in those instances 413 | will be considered the “Licensor.” The text of the Creative Commons 414 | public licenses is dedicated to the public domain under the CC0 Public 415 | Domain Dedication. Except for the limited purpose of indicating that 416 | material is shared under a Creative Commons public license or as 417 | otherwise permitted by the Creative Commons policies published at 418 | creativecommons.org/policies, Creative Commons does not authorize the 419 | use of the trademark "Creative Commons" or any other trademark or logo 420 | of Creative Commons without its prior written consent including, 421 | without limitation, in connection with any unauthorized modifications 422 | to any of its public licenses or any other arrangements, 423 | understandings, or agreements concerning use of licensed material. For 424 | the avoidance of doubt, this paragraph does not form part of the 425 | public licenses. 426 | 427 | Creative Commons may be contacted at creativecommons.org. 428 | -------------------------------------------------------------------------------- /LICENSES/CC0-1.0.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :fire: vcontrold 2 | 3 | _vcontrold_ is a software daemon written in C for communication with the "Optolink" interface of Viessmann Vito heating controllers. 4 | 5 | For building and installation instructions see `doc/INSTALL.md`. 6 | 7 | [Binary packages](https://github.com/openv/vcontrold/releases) are available for different platforms. 8 | 9 | Please visit the [OpenV Wiki](https://github.com/openv/openv/wiki/) for in-depth info and examples. 10 | 11 | ## DE 12 | 13 | _vcontrold_ ist ein in C geschriebener Software-Daemon zur Kommunikation mit der „Optolink“-Schnittstelle von Viessmann-Vito-Heizungssteuerungen. 14 | 15 | Der Build-Prozess und die Installation sind kurz unter `doc/INSTALL.md` beschrieben. 16 | 17 | Für einige Plattformen sind kompilierte [Installations-Pakete](https://github.com/openv/vcontrold/releases) verfügbar. 18 | 19 | Infos zur Einrichtung und Benutzung sind im [OpenV-Wiki](https://github.com/openv/openv/wiki/) beschrieben. 20 | -------------------------------------------------------------------------------- /cmake/GitDescription.cmake: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2012 Johannes Zarl 2 | # SPDX-FileCopyrightText: 2017-2022 Tobias Leupold 3 | # 4 | # SPDX-License-Identifier: BSD-3-Clause 5 | 6 | include (CMakeParseArguments) 7 | 8 | function (git_get_description DESCVAR) 9 | cmake_parse_arguments (_GGD "SEND_ERROR" "GIT_ARGS" "" "${ARGN}") 10 | if (SEND_ERROR) 11 | set (_severity SEND_ERROR) 12 | else() 13 | set (_severity WARNING) 14 | endif() 15 | 16 | find_package (Git QUIET) 17 | 18 | if (NOT GIT_FOUND) 19 | message (${severity} "git_get_description: could not find package git!") 20 | set (${DESCVAR} "-NOTFOUND" PARENT_SCOPE) 21 | return() 22 | endif() 23 | 24 | execute_process (COMMAND "${GIT_EXECUTABLE}" describe ${_GGD_GIT_ARGS} 25 | WORKING_DIRECTORY "${BASE_DIR}" 26 | RESULT_VARIABLE _gitresult 27 | OUTPUT_VARIABLE _gitdesc 28 | ERROR_VARIABLE _giterror 29 | OUTPUT_STRIP_TRAILING_WHITESPACE ) 30 | 31 | if (NOT _gitresult EQUAL 0) 32 | message (${_severity} "git_get_description: error during execution of git describe!") 33 | message ( ${_severity} "Error was: ${_giterror}" ) 34 | set (${DESCVAR} "-NOTFOUND" PARENT_SCOPE) 35 | else() 36 | set (${DESCVAR} "${_gitdesc}" PARENT_SCOPE) 37 | endif() 38 | 39 | endfunction() 40 | -------------------------------------------------------------------------------- /cmake/Toolchain-rpi.cmake: -------------------------------------------------------------------------------- 1 | # CMAKE_TOOLCHAIN_FILE for cross-compiling for RPi et al. 2 | 3 | SET(CMAKE_SYSTEM_NAME Linux) 4 | SET(CMAKE_SYSTEM_VERSION 1) 5 | 6 | if(DEFINED ENV{CHROOT_DIR}) 7 | SET(CHROOT_DIR $ENV{CHROOT_DIR}) 8 | else(DEFINED ENV{CHROOT_DIR}) 9 | SET(CHROOT_DIR /mnt/raspbian_lite) 10 | endif(DEFINED ENV{CHROOT_DIR}) 11 | 12 | SET(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) 13 | SET(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++) 14 | 15 | SET(CMAKE_SYSROOT ${CHROOT_DIR}) 16 | SET(CMAKE_FIND_ROOT_PATH ${CHROOT_DIR}) 17 | 18 | # don't search for programs on CHROOT_DIR, use those on build host 19 | SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 20 | 21 | # search libraries and headers on CHROOT_DIR 22 | SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 23 | SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 24 | 25 | 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") 26 | 27 | UNSET(CMAKE_C_FLAGS CACHE) 28 | UNSET(CMAKE_CXX_FLAGS CACHE) 29 | SET(CMAKE_C_FLAGS ${FLAGS} CACHE STRING "" FORCE) 30 | SET(CMAKE_CXX_FLAGS ${FLAGS} CACHE STRING "" FORCE) 31 | -------------------------------------------------------------------------------- /cmake/UpdateVersion.cmake: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2012 Johannes Zarl 2 | # SPDX-FileCopyrightText: 2017-2022 Tobias Leupold 3 | # 4 | # SPDX-License-Identifier: BSD-3-Clause 5 | 6 | if (NOT DEFINED BASE_DIR) 7 | message (FATAL_ERROR "UpdateVersion.cmake: BASE_DIR not set. " 8 | "Please supply base working directory!") 9 | endif() 10 | 11 | # Version header locations 12 | set(VERSION_H_IN ${BASE_DIR}/src/version.h.in) 13 | set(VERSION_H_CURRENT ${CMAKE_BINARY_DIR}/version.h.current) 14 | set(VERSION_H_GENERATED ${CMAKE_BINARY_DIR}/version.h) 15 | 16 | # git or tarball? 17 | if (EXISTS ${BASE_DIR}/.git) 18 | # --> git: 19 | include (${CMAKE_CURRENT_LIST_DIR}/GitDescription.cmake) 20 | git_get_description (VERSION GIT_ARGS --dirty) 21 | if (NOT VERSION) 22 | set (VERSION "unknown") 23 | else() 24 | # Remove a trailing "v" from the version. 25 | string(REGEX REPLACE "^v" "" VERSION ${VERSION}) 26 | endif() 27 | 28 | message (STATUS "Updating version information to ${VERSION} ...") 29 | 30 | else() 31 | # --> tarball 32 | if (EXISTS ${BASE_DIR}/src/version.h) 33 | # A released version.h file exists, we can exit here 34 | message(STATUS "Using the released version.h file") 35 | return() 36 | endif() 37 | 38 | message(WARNING "No \"src/version.h\" file found. Trying to determine the version from the " 39 | "project directory") 40 | get_filename_component(BASE_DIR_L "${BASE_DIR}" NAME) 41 | string(REGEX REPLACE "[^-]+-([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)" "\\1.\\2.\\3\\4" 42 | VERSION "${BASE_DIR_L}") 43 | if ("${VERSION}" STREQUAL "${BASE_DIR_L}") 44 | message(WARNING "Could not derive version from name of project directory. Setting the " 45 | "version to \"unknown\".") 46 | set (VERSION "unknown") 47 | else() 48 | message(WARNING "The Version guessed from project directory is \"${VERSION}\".") 49 | endif() 50 | message (WARNING "Generating an emergency version.h file.") 51 | 52 | endif() 53 | 54 | # write version info to a temporary file 55 | configure_file(${VERSION_H_IN} ${VERSION_H_CURRENT}) 56 | # update info if changed 57 | execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different 58 | ${VERSION_H_CURRENT} ${VERSION_H_GENERATED}) 59 | # make sure info doesn't get stale 60 | file(REMOVE ${VERSION_H_CURRENT}) 61 | -------------------------------------------------------------------------------- /doc/INSTALL.md: -------------------------------------------------------------------------------- 1 | # Building via cmake 2 | 3 | The `vcontrold` package depends on `libxml2`. 4 | 5 | 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. 6 | 7 | The package can be built with the normal cmake procedure. Simply execute the following steps in your source directory: 8 | 9 | ``` 10 | mkdir build 11 | cd build 12 | cmake .. 13 | make 14 | ``` 15 | 16 | ### Build options 17 | 18 | There are three options for the build process with their defaults: 19 | 20 | * _MANPAGES=ON_ Build man pages via `rst2man` 21 | * _VCLIENT=ON_ Build the `vclient` helper program (for communication with vcontrold) 22 | * _VSIM=OFF_ Build the `vsim` helper program (for development and testing purposes) 23 | 24 | The installation path can be altered by 25 | 26 | * _CMAKE_INSTALL_PREFIX=`/usr/local`_ 27 | This directory is prepended onto all install directories. This variable defaults to `/usr` on UNIX and `c:/Program Files` on Windows 28 | 29 | Invocation is e.g. as follows: 30 | 31 | ``` 32 | cmake -DVSIM=ON -DMANPAGES=OFF -DCMAKE_INSTALL_PREFIX=/usr/local .. 33 | ``` 34 | 35 | A common approach for a minimal installation (without manpages) would be: 36 | 37 | ``` 38 | cmake -DMANPAGES=OFF .. 39 | ``` 40 | 41 | ### Installation 42 | 43 | To install the package, execute as root: 44 | 45 | ``` 46 | make install 47 | ``` 48 | 49 | or, on systems that use this logic (e.g. Debian, Ubuntu etc.), use `sudo`: 50 | 51 | ``` 52 | sudo make install 53 | ``` 54 | 55 | The whole installation can be relocated to a different directory by supplying a `DESTDIR` variable: 56 | 57 | ``` 58 | make DESTDIR= install 59 | ``` 60 | 61 | or 62 | 63 | ``` 64 | sudo make DESTDIR= install 65 | ``` 66 | 67 | respectively. In this case, the entire package will be installed in a directory with the installation prefix prepended with the `DESTDIR` value, which finally gives `/`. 68 | -------------------------------------------------------------------------------- /doc/README-de.md: -------------------------------------------------------------------------------- 1 | *********************************************************** 2 | Aktuelle Informationen und Dokus finden sich im Wiki: 3 | https://github.com/openv/vcontrold 4 | *********************************************************** 5 | Die Software wird unter der GPL veroeffentlicht. 6 | *********************************************************** 7 | 8 | 9 | vcontrold ist ein in C geschriebener Daemon, der die Kommunikation mit 10 | der Vito-Steuerung übernimmt. 11 | 12 | Die Konfiguration erfolgt über XML-Dateien. 13 | Der Daemon bietet eine ASCII-Socketschnittstelle, die mit telnet oder 14 | dem vclient Programm angespochen werden kann. 15 | 16 | Der Quelltext kann im git Repository heruntergeladen werden. 17 | 18 | git clone https://github.com/openv/vcontrold.git vcontrold-code 19 | cd vcontrold-code 20 | mkdir ./build && cd ./build 21 | cmake .. 22 | make && make install 23 | 24 | 25 | Die Konfiguration des Programms wird in zwei XML-Dateien vorgenommen: 26 | vcontrold.xml : Programmspezifische Definitionen 27 | vito.xml: Definition der Kommandos und Devices 28 | 29 | -------------------------------------------------------------------------------- /doc/examples/README.txt: -------------------------------------------------------------------------------- 1 | *********************************************************** 2 | Aktuelle Informationen und Dokus finden sich im Wiki: 3 | https://github.com/openv/openv/wiki 4 | *********************************************************** 5 | Die Software wird unter der GPL veroeffentlicht. 6 | *********************************************************** 7 | 8 | Die Beispiel Scripte veranschaulichen das Loggen von Betriebsdaten in eine RRD. 9 | -------------------------------------------------------------------------------- /doc/examples/rrd.min.cmds: -------------------------------------------------------------------------------- 1 | getTempA 2 | getTempWWist 3 | getTempKist 4 | getTempKsoll 5 | getTempVListM2 6 | getTempKol 7 | getTempSpu 8 | getBrennerStatus 9 | getPumpeStatusA1M1 10 | getPumpeStatusM2 11 | getPumpeStatusSp 12 | getPumpeStatusZirku 13 | getPumpeStatusSolar 14 | getSolarStatusWW 15 | -------------------------------------------------------------------------------- /doc/examples/rrd.tmpl: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | # Script Template 3 | # solarix@pingos.de 4 | # 5 | db="/root/vitotools/vitodb.rrd" 6 | BrennerStatus=`expr \( $R8 \* 10 \)` 7 | PumpeStatusA1M1=`expr \( $R9 \* 20 \)` 8 | PumpeStatusM2=`expr \( $R10 \* 30 \)` 9 | PumpeStatusSp=`expr \( $R11 \* 40 \)` 10 | PumpeStatusZirku=`expr \( $R12 \* 50 \)` 11 | PumpeStatusSolar=`expr \( $R13 \* 60 \)` 12 | SolarStatusWW=`expr \( $R14 \* 70 \)` 13 | /opt/bin/rrdtool update \$db N:$1:$2:$3:$4:$5:$6:$7:$BrennerStatus:$PumpeStatusA1M1:$PumpeStatusM2:$PumpeStatusSp:$PumpeStatusZirku:$PumpeStatusSolar:$SolarStatusWW 14 | -------------------------------------------------------------------------------- /doc/examples/rrdb/createRRDB.sh: -------------------------------------------------------------------------------- 1 | /opt/usr/bin/rrdtool create /extern/rrdb/vito.rrd --step 300 \ 2 | DS:tempA:GAUGE:700:-50:100 \ 3 | DS:tempWWist:GAUGE:700:0:100 \ 4 | DS:tempWWsoll:GAUGE:700:0:100 \ 5 | DS:tempKist:GAUGE:700:0:100 \ 6 | DS:tempKsoll:GAUGE:700:0:100 \ 7 | DS:BetriebsArt:GAUGE:700:0:5 \ 8 | DS:PumpeSollM1:GAUGE:700:0:100 \ 9 | DS:ExtBA:GAUGE:700:0:1 \ 10 | DS:PumpeStatusM1:GAUGE:700:0:1 \ 11 | DS:BrennerStunden1:COUNTER:700:0:100000 \ 12 | DS:TempRaumNorSollM1:GAUGE:700:0:100 \ 13 | DS:TempRaumRedSollM1:GAUGE:700:0:100 \ 14 | DS:BrennerStatus:GAUGE:700:0:1 \ 15 | DS:PumpeStatusZirku:GAUGE:700:0:1 \ 16 | DS:getVentilStatus:GAUGE:700:0:1 \ 17 | RRA:AVERAGE:0.5:1:2020 \ 18 | RRA:MIN:0.5:12:2400 \ 19 | RRA:MAX:0.5:12:2400 \ 20 | RRA:AVERAGE:0.5:12:2400 21 | -------------------------------------------------------------------------------- /doc/examples/rrdb/graph.sh: -------------------------------------------------------------------------------- 1 | LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/usr/lib 2 | export LD_LIBRARY_PATH 3 | 4 | /opt/usr/bin/rrdtool graph /tmp/vito.png \ 5 | --start end-1d --end now --width 800 --height 300 \ 6 | --title 'Vito-Messwerte' \ 7 | DEF:tempA=/extern/rrdb/vito.rrd:tempA:AVERAGE \ 8 | DEF:tempWWist=/extern/rrdb/vito.rrd:tempWWist:AVERAGE \ 9 | DEF:tempKist=/extern/rrdb/vito.rrd:tempKist:AVERAGE \ 10 | DEF:tempKsoll=/extern/rrdb/vito.rrd:tempKsoll:AVERAGE \ 11 | DEF:PumpeSollM1=/extern/rrdb/vito.rrd:PumpeSollM1:AVERAGE \ 12 | DEF:PumpeStatusM1=/extern/rrdb/vito.rrd:PumpeStatusM1:AVERAGE \ 13 | DEF:BetriebsArt=/extern/rrdb/vito.rrd:BetriebsArt:AVERAGE \ 14 | DEF:ExtBA=/extern/rrdb/vito.rrd:ExtBA:AVERAGE \ 15 | DEF:BrennerStatus=/extern/rrdb/vito.rrd:BrennerStatus:AVERAGE \ 16 | DEF:PumpeStatusZirku=/extern/rrdb/vito.rrd:PumpeStatusZirku:AVERAGE \ 17 | DEF:VentilStatus=/extern/rrdb/vito.rrd:getVentilStatus:AVERAGE \ 18 | CDEF:PSM1=PumpeStatusM1,30,* \ 19 | CDEF:BA=BetriebsArt,10,* \ 20 | CDEF:EBA=ExtBA,25,* \ 21 | CDEF:BS=BrennerStatus,40,* \ 22 | CDEF:VS=VentilStatus,60,* \ 23 | CDEF:PS=PumpeStatusZirku,70,* \ 24 | LINE1:tempA#0000FF:tempA \ 25 | LINE1:tempWWist#FF00FF:tempWWist \ 26 | LINE1:tempKist#00FFFF:tempKist \ 27 | LINE1:tempKsoll#CCCCCC:tempKsoll \ 28 | LINE1:BA#555555:Betriebsart \ 29 | LINE1:EBA#779922:Ext.Umschaltung \ 30 | LINE1:BS#11ABCD:Brennerstatus \ 31 | LINE1:VS#23AA77:Ventilstatus \ 32 | LINE1:PS#880044:Zirku-Pumpe \ 33 | VDEF:tempAmax=tempA,MAXIMUM \ 34 | VDEF:tempAmin=tempA,MINIMUM \ 35 | VDEF:tempWWmax=tempWWist,MAXIMUM \ 36 | VDEF:tempWWmin=tempWWist,MINIMUM \ 37 | VDEF:BSmax=BS,MAXIMUM \ 38 | VDEF:VSmax=VS,MAXIMUM \ 39 | COMMENT:"\l" \ 40 | COMMENT:"Aussentemp." \ 41 | GPRINT:tempAmin:" Min. %02.1lf Grad C" \ 42 | GPRINT:tempAmax:"Max. %02.1lf Grad C" \ 43 | COMMENT:"\l" \ 44 | COMMENT:"Warmwassertemp." \ 45 | GPRINT:tempWWmin:"Min. %02.1lf Grad C" \ 46 | GPRINT:tempWWmax:"Max. %02.1lf Grad C" \ 47 | COMMENT:"\l" \ 48 | GPRINT:BSmax:"Brenner %02lf" \ 49 | GPRINT:VSmax:"Venitl %02lf" 50 | 51 | -------------------------------------------------------------------------------- /doc/examples/rrdb/rrdb-update.sh: -------------------------------------------------------------------------------- 1 | if [ "x" != x ]; then 2 | echo -n `date` >>/tmp/vc-err.txt 3 | echo "es ist ein Fehler aufgetreten: getDevType:" >>/tmp/vc-err.txt 4 | exit 1; 5 | fi 6 | if [ "x" != x ]; then 7 | echo -n `date` >>/tmp/vc-err.txt 8 | echo "es ist ein Fehler aufgetreten: getTempA:" >>/tmp/vc-err.txt 9 | exit 1; 10 | fi 11 | if [ "x" != x ]; then 12 | echo -n `date` >>/tmp/vc-err.txt 13 | echo "es ist ein Fehler aufgetreten: getTempWWist:" >>/tmp/vc-err.txt 14 | exit 1; 15 | fi 16 | if [ "x" != x ]; then 17 | echo -n `date` >>/tmp/vc-err.txt 18 | echo "es ist ein Fehler aufgetreten: getTempWWsoll:" >>/tmp/vc-err.txt 19 | exit 1; 20 | fi 21 | if [ "x" != x ]; then 22 | echo -n `date` >>/tmp/vc-err.txt 23 | echo "es ist ein Fehler aufgetreten: getTempKist:" >>/tmp/vc-err.txt 24 | exit 1; 25 | fi 26 | if [ "x" != x ]; then 27 | echo -n `date` >>/tmp/vc-err.txt 28 | echo "es ist ein Fehler aufgetreten: getTempKsoll:" >>/tmp/vc-err.txt 29 | exit 1; 30 | fi 31 | if [ "x" != x ]; then 32 | echo -n `date` >>/tmp/vc-err.txt 33 | echo "es ist ein Fehler aufgetreten: unit off:" >>/tmp/vc-err.txt 34 | exit 1; 35 | fi 36 | if [ "x" != x ]; then 37 | echo -n `date` >>/tmp/vc-err.txt 38 | echo "es ist ein Fehler aufgetreten: getBetriebArtM1:" >>/tmp/vc-err.txt 39 | exit 1; 40 | fi 41 | if [ "x" != x ]; then 42 | echo -n `date` >>/tmp/vc-err.txt 43 | echo "es ist ein Fehler aufgetreten: unit on:" >>/tmp/vc-err.txt 44 | exit 1; 45 | fi 46 | if [ "x" != x ]; then 47 | echo -n `date` >>/tmp/vc-err.txt 48 | echo "es ist ein Fehler aufgetreten: getPumpeSollM1:" >>/tmp/vc-err.txt 49 | exit 1; 50 | fi 51 | BA=`echo 03 |cut -d ' ' -f 1` 52 | ST=`echo 21639.000000 h|cut -d '.' -f 1` 53 | 54 | LD_LIBRARY_PATH=':/opt/lib:/opt/usr/lib:/opt/usr/lib:/opt/usr/lib' 55 | export LD_LIBRARY_PATH 56 | 57 | 58 | rrdtool update /home/marcus/rrdb/vito.rrd N:15.500000:56.500000:50.000000:33.500000:39.000000:$BA:33.000000:0:0:$ST 59 | -------------------------------------------------------------------------------- /doc/examples/rrdb/rrdb-update.tmpl: -------------------------------------------------------------------------------- 1 | if [ "x$E1" != x ]; then 2 | echo -n `date` >>/tmp/vc-err.txt 3 | echo "es ist ein Fehler aufgetreten: $C1:$E1" >>/tmp/vc-err.txt 4 | exit 1; 5 | fi 6 | if [ "x$E2" != x ]; then 7 | echo -n `date` >>/tmp/vc-err.txt 8 | echo "es ist ein Fehler aufgetreten: $C2:$E2" >>/tmp/vc-err.txt 9 | exit 1; 10 | fi 11 | if [ "x$E3" != x ]; then 12 | echo -n `date` >>/tmp/vc-err.txt 13 | echo "es ist ein Fehler aufgetreten: $C3:$E3" >>/tmp/vc-err.txt 14 | exit 1; 15 | fi 16 | if [ "x$E4" != x ]; then 17 | echo -n `date` >>/tmp/vc-err.txt 18 | echo "es ist ein Fehler aufgetreten: $C4:$E4" >>/tmp/vc-err.txt 19 | exit 1; 20 | fi 21 | if [ "x$E5" != x ]; then 22 | echo -n `date` >>/tmp/vc-err.txt 23 | echo "es ist ein Fehler aufgetreten: $C5:$E5" >>/tmp/vc-err.txt 24 | exit 1; 25 | fi 26 | if [ "x$E6" != x ]; then 27 | echo -n `date` >>/tmp/vc-err.txt 28 | echo "es ist ein Fehler aufgetreten: $C6:$E6" >>/tmp/vc-err.txt 29 | exit 1; 30 | fi 31 | if [ "x$E7" != x ]; then 32 | echo -n `date` >>/tmp/vc-err.txt 33 | echo "es ist ein Fehler aufgetreten: $C7:$E7" >>/tmp/vc-err.txt 34 | exit 1; 35 | fi 36 | if [ "x$E8" != x ]; then 37 | echo -n `date` >>/tmp/vc-err.txt 38 | echo "es ist ein Fehler aufgetreten: $C8:$E8" >>/tmp/vc-err.txt 39 | exit 1; 40 | fi 41 | if [ "x$E9" != x ]; then 42 | echo -n `date` >>/tmp/vc-err.txt 43 | echo "es ist ein Fehler aufgetreten: $C9:$E9" >>/tmp/vc-err.txt 44 | exit 1; 45 | fi 46 | if [ "x$E10" != x ]; then 47 | echo -n `date` >>/tmp/vc-err.txt 48 | echo "es ist ein Fehler aufgetreten: $C10:$E10" >>/tmp/vc-err.txt 49 | exit 1; 50 | fi 51 | if [ "x$E11" != x ]; then 52 | echo -n `date` >>/tmp/vc-err.txt 53 | echo "es ist ein Fehler aufgetreten: $C11:$E11" >>/tmp/vc-err.txt 54 | exit 1; 55 | fi 56 | if [ "x$E12" != x ]; then 57 | echo -n `date` >>/tmp/vc-err.txt 58 | echo "es ist ein Fehler aufgetreten: $C12:$E12" >>/tmp/vc-err.txt 59 | exit 1; 60 | fi 61 | if [ "x$E13" != x ]; then 62 | echo -n `date` >>/tmp/vc-err.txt 63 | echo "es ist ein Fehler aufgetreten: $C13:$E13" >>/tmp/vc-err.txt 64 | exit 1; 65 | fi 66 | if [ "x$E14" != x ]; then 67 | echo -n `date` >>/tmp/vc-err.txt 68 | echo "es ist ein Fehler aufgetreten: $C14:$E14" >>/tmp/vc-err.txt 69 | exit 1; 70 | fi 71 | if [ "x$E15" != x ]; then 72 | echo -n `date` >>/tmp/vc-err.txt 73 | echo "es ist ein Fehler aufgetreten: $C15:$E15" >>/tmp/vc-err.txt 74 | exit 1; 75 | fi 76 | if [ "x$E16" != x ]; then 77 | echo -n `date` >>/tmp/vc-err.txt 78 | echo "es ist ein Fehler aufgetreten: $C16:$E16" >>/tmp/vc-err.txt 79 | exit 1; 80 | fi 81 | if [ "x$E17" != x ]; then 82 | echo -n `date` >>/tmp/vc-err.txt 83 | echo "es ist ein Fehler aufgetreten: $C17:$E17" >>/tmp/vc-err.txt 84 | exit 1; 85 | fi 86 | if [ "x$E18" != x ]; then 87 | echo -n `date` >>/tmp/vc-err.txt 88 | echo "es ist ein Fehler aufgetreten: $C18:$E18" >>/tmp/vc-err.txt 89 | exit 1; 90 | fi 91 | BA=`echo $R8|cut -d ' ' -f 1` 92 | ST=`echo $R13|cut -d '.' -f 1` 93 | 94 | LD_LIBRARY_PATH=':/opt/lib:/opt/usr/lib:/opt/usr/lib:/opt/usr/lib' 95 | export LD_LIBRARY_PATH 96 | 97 | 98 | /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 99 | -------------------------------------------------------------------------------- /doc/examples/rrdb/vc-aufruf.txt: -------------------------------------------------------------------------------- 1 | vclient -h 192.168.1.4:3002 -f ./vc-commands.txt -t ./rrdb-update.tmpl -x ./rrdb-update.sh 2 | 3 | -------------------------------------------------------------------------------- /doc/examples/rrdb/vc-commands.txt: -------------------------------------------------------------------------------- 1 | getDevType 2 | getTempA 3 | getTempWWist 4 | getTempWWsoll 5 | getTempKist 6 | getTempKsoll 7 | unit off 8 | getBetriebArtM1 9 | unit on 10 | getPumpeSollM1 11 | getExtBA 12 | getPumpeStatusM1 13 | getBrennerStunden1 14 | getTempRaumNorSollM1 15 | getTempRaumRedSollM1 16 | getBrennerStatus 17 | getPumpeStatusZirku 18 | getVentilStatus 19 | 20 | -------------------------------------------------------------------------------- /doc/examples/sim-2098.ini: -------------------------------------------------------------------------------- 1 | [DATA] 2 | ;getTempA 3 | 04 = 05 4 | 01 F7 08 00 02 = 3C 00 5 | ;getTempWWist 6 | 04 = 05 7 | 01 F7 08 04 02 = 1E 02 8 | ;getTempWWsoll 9 | 04 = 05 10 | 01 F7 63 00 01 = 37 11 | ;getTempKist 12 | 04 = 05 13 | 01 F7 08 02 02 = BF 01 14 | ;getTempKsoll 15 | 04 = 05 16 | 01 F7 55 02 02 = 46 00 17 | ;getTempVListM2 18 | 04 = 05 19 | 01 F7 08 0C 02 = E0 00 20 | ;getTempVLsollA1M1 21 | 04 = 05 22 | 01 F7 25 44 02 = FF FF 23 | ;getTempVLsollM2 24 | 04 = 05 25 | 01 F7 35 44 02 = FF FF 26 | ;getTempVLsollM3 27 | 04 = 05 28 | 01 F7 45 44 02 = FF FF 29 | ;getTempKol 30 | 04 = 05 31 | 01 F7 65 64 02 = 3A 00 32 | ;getTempSpu 33 | 04 = 05 34 | 01 F7 65 66 02 = A5 00 35 | ;getTempRaumNorSoll1 36 | 04 = 05 37 | 01 F7 23 06 01 = 16 38 | ;getTempRaumNorSoll2 39 | 04 = 05 40 | 01 F7 33 06 01 = 16 41 | ;getTempRaumRedSoll1 42 | 04 = 05 43 | 01 F7 23 07 01 = 03 44 | ;getTempRaumRedSoll2 45 | 04 = 05 46 | 01 F7 33 07 01 = 03 47 | ;getBrennerStatus 48 | 04 = 05 49 | 01 F7 55 1E 01 = 00 50 | ;getBrennerStarts 51 | 04 = 05 52 | 01 F7 08 8A 02 = 5E 06 53 | ;getBrennerStunden 54 | 04 = 05 55 | 01 F7 08 A7 04 = 87 03 1A 00 56 | ;getPumpeStatusA1M1 57 | 04 = 05 58 | 01 F7 29 06 01 = 00 59 | ;getPumpeStatusSp 60 | 04 = 05 61 | 01 F7 08 45 01 = 00 62 | ;getPumpeStatusZirku 63 | 04 = 05 64 | 01 F7 08 46 01 = 00 65 | ;getPumpeStatusSolar 66 | 04 = 05 67 | 01 F7 65 52 01 = 00 68 | ;getPumpeStatusM2 69 | 04 = 05 70 | 01 F7 39 06 01 = 00 71 | ;getMischerA1M1 72 | 04 = 05 73 | 01 F7 25 4C 01 = FF 74 | ;getMischerM2 75 | 04 = 05 76 | 01 F7 35 4C 01 = FF 77 | ;getMischerM3 78 | 04 = 05 79 | 01 F7 45 4C 01 = FF 80 | ;getSolarStatusWW 81 | 04 = 05 82 | 01 F7 65 51 01 = 00 83 | ;getTimerM1Mo 84 | 04 = 05 85 | 01 F7 20 00 08 = 93 A0 FF FF FF FF FF FF 86 | ;getTimerM1Di 87 | 04 = 05 88 | 01 F7 20 08 08 = 93 A0 FF FF FF FF FF FF 89 | ;getTimerM1Mi 90 | 04 = 05 91 | 01 F7 20 10 08 = 93 A0 FF FF FF FF FF FF 92 | ;getTimerM1Do 93 | 04 = 05 94 | 01 F7 20 18 08 = 93 A0 FF FF FF FF FF FF 95 | ;getTimerM1Fr 96 | 04 = 05 97 | 01 F7 20 20 08 = 93 A0 FF FF FF FF FF FF 98 | ;getTimerM1Sa 99 | 04 = 05 100 | 01 F7 20 28 08 = 93 A0 FF FF FF FF FF FF 101 | ;getTimerM1So 102 | 04 = 05 103 | 01 F7 20 30 08 = 93 A0 FF FF FF FF FF FF 104 | ;getTimerM2Mo 105 | 04 = 05 106 | 01 F7 30 00 08 = 30 48 FF FF FF FF FF FF 107 | ;getTimerM2Di 108 | 04 = 05 109 | 01 F7 30 08 08 = 30 48 FF FF FF FF FF FF 110 | ;getTimerM2Mi 111 | 04 = 05 112 | 01 F7 30 10 08 = 30 48 FF FF FF FF FF FF 113 | ;getTimerM2Do 114 | 04 = 05 115 | 01 F7 30 18 08 = 30 48 FF FF FF FF FF FF 116 | ;getTimerM2Fr 117 | 04 = 05 118 | 01 F7 30 20 08 = 30 48 FF FF FF FF FF FF 119 | ;getTimerM2Sa 120 | 04 = 05 121 | 01 F7 30 28 08 = 88 9B FF FF FF FF FF FF 122 | ;getTimerM2So 123 | 04 = 05 124 | 01 F7 30 30 08 = FF FF FF FF FF FF FF FF 125 | ;getTimerWWMo 126 | 04 = 05 127 | 01 F7 21 00 08 = 30 48 93 9B FF FF FF FF 128 | ;getTimerWWDi 129 | 04 = 05 130 | 01 F7 21 08 08 = 30 48 93 9B FF FF FF FF 131 | ;getTimerWWMi 132 | 04 = 05 133 | 01 F7 21 10 08 = 30 48 93 9B FF FF FF FF 134 | ;getTimerWWDo 135 | 04 = 05 136 | 01 F7 21 18 08 = 30 48 93 9B FF FF FF FF 137 | ;getTimerWWFr 138 | 04 = 05 139 | 01 F7 21 20 08 = 30 48 93 9B FF FF FF FF 140 | ;getTimerWWSa 141 | 04 = 05 142 | 01 F7 21 28 08 = 38 48 90 9B FF FF FF FF 143 | ;getTimerWWSo 144 | 04 = 05 145 | 01 F7 21 30 08 = 38 48 93 9B FF FF FF FF 146 | ;getTimerZirkuMo 147 | 04 = 05 148 | 01 F7 22 00 08 = 28 2A 58 5D 95 A2 FF FF 149 | ;getTimerZirkuDi 150 | 04 = 05 151 | 01 F7 22 08 08 = 28 2A 58 5D 95 A2 FF FF 152 | ;getTimerZirkuMi 153 | 04 = 05 154 | 01 F7 22 10 08 = 28 2A 58 5D 95 A2 FF FF 155 | ;getTimerZirkuDo 156 | 04 = 05 157 | 01 F7 22 18 08 = 28 2A 58 5D 95 A2 FF FF 158 | ;getTimerZirkuFr 159 | 04 = 05 160 | 01 F7 22 20 08 = 28 2A 58 5D 95 A2 FF FF 161 | ;getTimerZirkuSa 162 | 04 = 05 163 | 01 F7 22 28 08 = 3B 45 58 5D 92 A2 FF FF 164 | ;getTimerZirkuSo 165 | 04 = 05 166 | 01 F7 22 30 08 = 40 45 58 5D 95 A2 FF FF 167 | ;getBetriebArtM1 168 | 04 = 05 169 | 01 F7 23 01 01 = 04 170 | ;getBetriebArtM2 171 | 04 = 05 172 | 01 F7 33 01 01 = 04 173 | ;getBetriebSparM1 174 | 04 = 05 175 | 01 F7 23 02 01 = 00 176 | ;getBetriebSparM2 177 | 04 = 05 178 | 01 F7 33 02 01 = 00 179 | ;getBetriebPartyM1 180 | 04 = 05 181 | 01 F7 23 03 01 = 00 182 | ;getBetriebPartyM2 183 | 04 = 05 184 | 01 F7 33 03 01 = 00 185 | ;getSolarStunden 186 | 04 = 05 187 | 01 F7 65 68 02 = D1 05 188 | ;getSolarLeistung 189 | 04 = 05 190 | 01 F7 65 60 04 = A0 06 00 00 191 | ;getStatusFrostM1 192 | 04 = 05 193 | 01 F7 25 00 01 = 02 194 | ;getStatusFrostM2 195 | 04 = 05 196 | 01 F7 35 00 01 = 02 197 | ;getStatusStoerung 198 | 04 = 05 199 | 01 F7 75 79 01 = 00 200 | ;getTempPartyM1 201 | 04 = 05 202 | 01 F7 23 08 01 = 18 203 | ;getTempPartyM2 204 | 04 = 05 205 | 01 F7 33 08 01 = 16 206 | -------------------------------------------------------------------------------- /doc/examples/sql.tmpl: -------------------------------------------------------------------------------- 1 | INSERT INTO messwerte values (CURRENT_DATE,$1,$2); 2 | -------------------------------------------------------------------------------- /doc/examples/vcontrold.initd.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: vcontrold 4 | # Required-Start: $remote_fs $syslog 5 | # Required-Stop: $remote_fs $syslog 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: Initscript to start Viessmann vcontrold deamon 9 | # Description: This file should be used to construct scripts to be 10 | # placed in /etc/init.d. 11 | ### END INIT INFO 12 | 13 | # Author: Michael Pucher 14 | # 15 | # Please remove the "Author" lines above and replace them 16 | # with your own name if you copy and modify this script. 17 | 18 | # Do NOT "set -e" 19 | 20 | # PATH should only include /usr/* if it runs after the mountnfs.sh script 21 | PATH=/sbin:/usr/sbin:/bin:/usr/bin 22 | DESC="Viessmann vcontrold deamon" 23 | NAME=vcontrold 24 | DAEMON=/usr/local/sbin/$NAME 25 | #DAEMON_ARGS="--options args" 26 | DAEMON_ARGS="" 27 | PIDFILE=/var/run/$NAME.pid 28 | SCRIPTNAME=/etc/init.d/$NAME 29 | 30 | # Exit if the package is not installed 31 | [ -x "$DAEMON" ] || exit 0 32 | 33 | # Read configuration variable file if it is present 34 | [ -r /etc/default/$NAME ] && . /etc/default/$NAME 35 | 36 | # Load the VERBOSE setting and other rcS variables 37 | . /lib/init/vars.sh 38 | 39 | # Define LSB log_* functions. 40 | # Depend on lsb-base (>= 3.2-14) to ensure that this file is present 41 | # and status_of_proc is working. 42 | . /lib/lsb/init-functions 43 | 44 | # 45 | # Function that starts the daemon/service 46 | # 47 | do_start() 48 | { 49 | # Return 50 | # 0 if daemon has been started 51 | # 1 if daemon was already running 52 | # 2 if daemon could not be started 53 | start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ 54 | || return 1 55 | start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ 56 | $DAEMON_ARGS \ 57 | || return 2 58 | # Add code here, if necessary, that waits for the process to be ready 59 | # to handle requests from services started subsequently which depend 60 | # on this one. As a last resort, sleep for some time. 61 | } 62 | 63 | # 64 | # Function that stops the daemon/service 65 | # 66 | do_stop() 67 | { 68 | # Return 69 | # 0 if daemon has been stopped 70 | # 1 if daemon was already stopped 71 | # 2 if daemon could not be stopped 72 | # other if a failure occurred 73 | start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME 74 | RETVAL="$?" 75 | [ "$RETVAL" = 2 ] && return 2 76 | # Wait for children to finish too if this is a daemon that forks 77 | # and if the daemon is only ever run from this initscript. 78 | # If the above conditions are not satisfied then add some other code 79 | # that waits for the process to drop all resources that could be 80 | # needed by services started subsequently. A last resort is to 81 | # sleep for some time. 82 | start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON 83 | [ "$?" = 2 ] && return 2 84 | # Many daemons don't delete their pidfiles when they exit. 85 | rm -f $PIDFILE 86 | return "$RETVAL" 87 | } 88 | 89 | # 90 | # Function that sends a SIGHUP to the daemon/service 91 | # 92 | do_reload() { 93 | # 94 | # If the daemon can reload its configuration without 95 | # restarting (for example, when it is sent a SIGHUP), 96 | # then implement that here. 97 | # 98 | start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME 99 | return 0 100 | } 101 | 102 | case "$1" in 103 | start) 104 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" 105 | do_start 106 | case "$?" in 107 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 108 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 109 | esac 110 | ;; 111 | stop) 112 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" 113 | do_stop 114 | case "$?" in 115 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 116 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 117 | esac 118 | ;; 119 | status) 120 | status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? 121 | ;; 122 | #reload|force-reload) 123 | # 124 | # If do_reload() is not implemented then leave this commented out 125 | # and leave 'force-reload' as an alias for 'restart'. 126 | # 127 | #log_daemon_msg "Reloading $DESC" "$NAME" 128 | #do_reload 129 | #log_end_msg $? 130 | #;; 131 | restart|force-reload) 132 | # 133 | # If the "reload" option is implemented then remove the 134 | # 'force-reload' alias 135 | # 136 | log_daemon_msg "Restarting $DESC" "$NAME" 137 | do_stop 138 | case "$?" in 139 | 0|1) 140 | do_start 141 | case "$?" in 142 | 0) log_end_msg 0 ;; 143 | 1) log_end_msg 1 ;; # Old process is still running 144 | *) log_end_msg 1 ;; # Failed to start 145 | esac 146 | ;; 147 | *) 148 | # Failed to stop 149 | log_end_msg 1 150 | ;; 151 | esac 152 | ;; 153 | *) 154 | #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 155 | echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 156 | exit 3 157 | ;; 158 | esac 159 | 160 | : 161 | -------------------------------------------------------------------------------- /doc/examples/vcontrold.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Viessmann heating systems interface 3 | Documentation=https://github.com/openv/vcontrold 4 | After=syslog.target systemd-udev-settle.service 5 | 6 | [Service] 7 | Type=forking 8 | User=vcontrol 9 | Group=vcontrol 10 | ExecStart=/usr/sbin/vcontrold -x /etc/vcontrold/vcontrold.xml 11 | ExecReload=/bin/kill -HUP $MAINPID 12 | Restart=on-failure 13 | RestartSec=120 14 | StandardOutput=null 15 | 16 | [Install] 17 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /doc/examples/vcontrold.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 192.168.1.112:3000 7 | 8 | 9 | 3002 10 | 11 | 12 | /tmp/vcontrold.log 13 | n 14 | y 15 | 16 | 17 | 18 | 19 | 20 | 21 | UT 22 | 23 | short 24 | Grad Celsius 25 | 26 | 27 | ST 28 | 29 | char 30 | 31 | 32 | 33 | CO 34 | 35 | int 36 | 37 | 38 | 39 | PR 40 | 41 | short 42 | % 43 | 44 | 45 | CS 46 | 47 | int 48 | Stunden 49 | 50 | 51 | CT 52 | cycletime 53 | 54 | 55 | RT 56 | enum 57 | 58 | 59 | 60 | 61 | 62 | BA 63 | enum 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | SR 73 | enum 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | SEND 04;WAIT 05 84 | 85 | 86 | SEND 01 F7 87 | 88 | 89 | SEND 01 F4 90 | 91 | 92 | 93 | 94 | SYNC;GETADDR $addr $len;RECV $len $unit 95 | 96 | 97 | SYNC;SETADDR $addr $len;SEND BYTES $unit;RECV 1 SR 98 | 99 | 100 | 101 | 102 | 103 | 104 | SEND 04;WAIT 05 105 | 106 | 107 | SEND 01 CB 108 | 109 | 110 | 111 | 112 | SYNC;GETADDR $addr $len;RECV $len $unit 113 | 114 | 115 | SYNC;RECV 1 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /doc/examples/vupdate.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | # RDD Update V200KW2 3 | # solarix@pingos.de 4 | # 5 | /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 6 | exit 7 | -------------------------------------------------------------------------------- /doc/man/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017-2022 Tobias Leupold 2 | # 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | 5 | # Generate classic *roff manual pages from ReStructuredText. 6 | # This requires Python's Docutils (http://docutils.sourceforge.net/) 7 | 8 | cmake_minimum_required(VERSION 3.2.0) 9 | 10 | set(RST2MAN_OPTS) 11 | 12 | set(MANUALS vcontrold) 13 | if(VCLIENT) 14 | list(APPEND MANUALS vclient) 15 | endif(VCLIENT) 16 | if(VSIM) 17 | list(APPEND MANUALS vsim) 18 | endif(VSIM) 19 | 20 | foreach(MANUAL IN LISTS MANUALS) 21 | set(MANPAGE_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${MANUAL}.1) 22 | set(MANPAGE_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/${MANUAL}.rst) 23 | add_custom_command(OUTPUT ${MANPAGE_OUTPUT} 24 | COMMAND ${RST2MAN} ${RST2MAN_OPTS} ${MANPAGE_SOURCE} ${MANPAGE_OUTPUT} 25 | DEPENDS ${MANPAGE_SOURCE} 26 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 27 | COMMENT "Converting ${MANUAL}.rst from ReStructuredText into manpage ${MANUAL}.1" 28 | VERBATIM 29 | ) 30 | list(APPEND MANPAGES_LIST ${MANPAGE_OUTPUT}) 31 | endforeach() 32 | 33 | add_custom_target(man ALL DEPENDS ${MANPAGES_LIST}) 34 | install(FILES ${MANPAGES_LIST} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1) 35 | -------------------------------------------------------------------------------- /doc/man/vclient.rst: -------------------------------------------------------------------------------- 1 | .. 2 | SPDX-FileCopyrightText: 2012 Frank Nobis 3 | 4 | SPDX-License-Identifier: CC-BY-SA-4.0 5 | 6 | ======= 7 | vclient 8 | ======= 9 | 10 | -------------------------------------- 11 | tool for getting values from vcontrold 12 | -------------------------------------- 13 | 14 | :Manual section: 1 15 | 16 | SYNOPSIS 17 | ======== 18 | 19 | vclient [-h ] [-c ] [-f ] [-s ] [-t ] [-o ] [-x ] [-k] [-m] [-v] [-j] [-J] 20 | 21 | DESCRIPTION 22 | =========== 23 | 24 | vclient is the client program to communicate with the vcontrold daemon. 25 | It features a template mode to prepare received data for logging or database input. 26 | 27 | OPTIONS 28 | ======= 29 | 30 | -h, \--host 31 | or of vcontrold. Defaults to localhost 32 | 33 | -p, \--port 34 | of vcontrold when using IPv6. Defaults to 3002 35 | 36 | -c, \--command 37 | comma-separated list of commands 38 | 39 | -f, \-commandfile 40 | optional file with commands, one command per line 41 | 42 | -s, \--csvfile 43 | output results in CSV format 44 | 45 | -t, \--template 46 | template file, variables get replaced by returned values 47 | 48 | -o, \--output 49 | redirect stdout into 50 | 51 | -x, \--execute 52 | write template output to , then run the generated 53 | 54 | -m, \--munin 55 | Munin datalogger compatible output, omits units and error details 56 | 57 | -k, \--cacti 58 | Cacti datalogger compatible output, omits units and error details 59 | 60 | -j, \--json-short 61 | JSON output short format (object with cmd as key and result as value) 62 | 63 | -J, \--json-long 64 | JSON output long (list with objects per command, contains cmd, raw, value and error) 65 | 66 | -v, \--verbose 67 | verbose mode 68 | 69 | -V, \--Version 70 | print version info, then exit 71 | 72 | -4, \--inet4 73 | IPv4 preferred 74 | 75 | -6, \--inet6 76 | IPv6 preferred. If no option provided, use OS defaults. 77 | 78 | \--help 79 | usage information 80 | 81 | TEMPLATE MODE 82 | ============= 83 | 84 | In template mode, variables contained in the get 85 | replaced with the values returned by a command issued in vclient. 86 | 87 | Variables $1, $2, ..., $n gets replaced with 1st, 2nd, ..., nth return value. 88 | 89 | The following variable types exist for conversion of return values: 90 | 91 | +------------+-----------------------------------+ 92 | | variable | function | 93 | +------------+-----------------------------------+ 94 | | $1..$n | return value converted to float | 95 | +------------+-----------------------------------+ 96 | | $R1..$Rn | return value converted to text | 97 | +------------+-----------------------------------+ 98 | | $C1..$Cn | issued command | 99 | +------------+-----------------------------------+ 100 | | $E1..$En | error message of command | 101 | +------------+-----------------------------------+ 102 | 103 | EXAMPLES 104 | ======== 105 | 106 | Preparation of a simple template for a database statement to insert some values in database: 107 | 108 | :: 109 | 110 | $ cat > sql.tmpl </dev/null | mysql -D vito`` 125 | 126 | The -o option writes (overwrites, not appends) the 127 | output to the given file. 128 | 129 | With the option -x sh-example.tmpl <`__ 157 | -------------------------------------------------------------------------------- /doc/man/vcontrold.rst: -------------------------------------------------------------------------------- 1 | .. 2 | SPDX-FileCopyrightText: 2012 Frank Nobis 3 | 4 | SPDX-License-Identifier: CC-BY-SA-4.0 5 | 6 | ========= 7 | vcontrold 8 | ========= 9 | 10 | ---------------------------------------------------------- 11 | Unix daemon for communication with Viessmann Vito heatings 12 | ---------------------------------------------------------- 13 | 14 | :Manual section: 1 15 | 16 | SYNOPSIS 17 | ======== 18 | 19 | *vcontrold* [`OPTIONS`...] 20 | [-x\|\--xmlfile xml-file] [-d\|\--device ] 21 | [-l\|\--logfile ] [-s\|\--syslog] 22 | [-p\|\--port ] [-L\|\--listen
] 23 | [-n\|\--nodaemon] [-v\|\--verbose] [-V\|\--Version] 24 | [-c\|\--commandfile ] [-P\|\--pidfile ] 25 | [-U\|\--username ] [-G\|\--groupname ] 26 | [-?\|\--help] [-i\|\--vsim] [-g\|\--debug] 27 | [-4\|\--inet4] [-6\|\--inet6] 28 | 29 | 30 | DESCRIPTION 31 | =========== 32 | 33 | vcontrold uses a serial optical link or an IP connection to communicate with 34 | a Viessmann vito heating controller. 35 | 36 | OPTIONS 37 | ======= 38 | 39 | -x , \--xmlfile 40 | location of the main config file 41 | 42 | -d , \--device 43 | serial device to use. 44 | This option overrides corresponding entry in the config file. 45 | 46 | -l , \--logfile 47 | use instead of syslog. 48 | 49 | -s, \--syslog 50 | use syslog 51 | 52 | -p , \--port 53 | TCP to use for remote connections. 54 | The default is 3002 and can be specified in the config file. 55 | This option overrides the corresponding entry in the config file. 56 | 57 | -L
, \--listen
58 | Address to listen for incoming connections. 59 | Use e.g. ``localhost`` or ``127.0.0.1`` to bind to the loopback interface only. 60 | Default is to bind to all addresses (``0.0.0.0`` in case of IPv4) 61 | 62 | -n, \--nodaemon 63 | do not fork. This is for testing purpose only. Normaly vcontrold 64 | will detach from the controlling terminal and put itself into the 65 | background. 66 | 67 | -c , \--commandfile 68 | file with lines containing sequences of icmds (WAIT, SEND, RECV, PAUSE) 69 | as used in protocol definitions. 70 | Lines get executed in order 71 | (developer option) 72 | 73 | -P , \--pidfile 74 | write process id to when started as a daemon. 75 | When started as root, is written prior to dropping privileges. 76 | This overrides the corresponding entry in the config file. 77 | 78 | -U , \--username 79 | when started by root, drop privileges to user 80 | instead of user nobody. This overrides the corresponding entry in the config file. 81 | If using a serial link, ensure that user or group has access rights to the serial device. 82 | 83 | -G , \--groupname 84 | when started by root, drop privileges to group 85 | instead of group dialout. This overrides the corresponding entry in the config file. 86 | If using a serial link, ensure that user or group has access rights to the serial device. 87 | 88 | -i, \--vsim 89 | use a temp file in ``/tmp/sim-devid.ini`` for use with the vsim simulator 90 | (developer option) 91 | 92 | -g, \--debug 93 | enable debug mode 94 | 95 | -4, --inet4 96 | use IP v4 socket 97 | 98 | -6, --inet6 99 | use IP v6 socket 100 | 101 | -v, \--verbose 102 | verbose mode 103 | 104 | -V, \--Version 105 | print version information, then exit 106 | 107 | -?, \--help 108 | usage information 109 | 110 | FILES 111 | ===== 112 | 113 | ``/etc/vcontrold/vcontrold.xml`` 114 | These are the programm specific configurations. E.g. device, baudrate, 115 | IP etc. 116 | 117 | ``/etc/vcontrold/vito.xml`` 118 | These are the command definitions for the devices in use. 119 | This file is included by the default xml config above via an xml include statement. 120 | 121 | SEE ALSO 122 | ======== 123 | 124 | * man 1 vclient 125 | * vcontrold @GitHub: `https://github.com/openv/vcontrold `__ 126 | -------------------------------------------------------------------------------- /doc/man/vsim.rst: -------------------------------------------------------------------------------- 1 | .. 2 | SPDX-FileCopyrightText: 2012 Frank Nobis 3 | 4 | SPDX-License-Identifier: CC-BY-SA-4.0 5 | 6 | ==== 7 | vsim 8 | ==== 9 | 10 | ----------------------------- 11 | simulation tool for vcontrold 12 | ----------------------------- 13 | 14 | :Manual section: 1 15 | 16 | DESCRIPTION 17 | =========== 18 | 19 | ``vsim`` is a simulation tool for the ``vcontrold`` daemon to simulate a connected Viessmann device. 20 | 21 | It is a simple developer tool, and features only a limited commandset which is not runtime configurable. 22 | 23 | SEE ALSO 24 | ======== 25 | 26 | * man 1 vcontrold 27 | * man 1 vclient 28 | * vcontrold @GitHub: `https://github.com/openv/vcontrold `__ 29 | -------------------------------------------------------------------------------- /doc/original_authors.txt: -------------------------------------------------------------------------------- 1 | Listed below is the original "AUTHORS" file from SourceForge before the move to GitHub and the new 2 | maintainer team. Even after consulting the only original author with a known email address (Frank 3 | Nobis a.k.a. fnobis), the other original authors remain unknown except for their nickname at the 4 | time. If you are one of them reading this, please contact us to let us know who you are, so that we 5 | can mention you as the original copyright holder correctly! 6 | 7 | The listed persons are referenced as the "The original vcontrold authors" in the sources. 8 | 9 | ------------------------------ 10 | 11 | This software has many authors. See the source and the repository for some infos. 12 | 13 | Original authors: 14 | * marcust 15 | * brainhunter 16 | * vheat 17 | * fnobis 18 | -------------------------------------------------------------------------------- /doc/original_authors.txt.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: none 2 | 3 | SPDX-License-Identifier: CC0-1.0 4 | -------------------------------------------------------------------------------- /src/arithmetic.c: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | // Calculation of arithmetic expressions 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define HEX 8 13 | #define HEXDIGIT 10 14 | #define DIGIT 11 15 | #define PUNKT 12 16 | #define END 0 17 | #define ERROR -100 18 | #define PLUS 100 19 | #define MINUS 101 20 | #define MAL 102 21 | #define GETEILT 103 22 | #define MODULO 104 23 | #define KAUF 110 24 | #define KZU 111 25 | #define BYTE0 200 26 | #define BYTE1 201 27 | #define BYTE2 202 28 | #define BYTE3 203 29 | #define BYTE4 204 30 | #define BYTE5 205 31 | #define BYTE6 206 32 | #define BYTE7 207 33 | #define BYTE8 208 34 | #define BYTE9 209 35 | #define BYTEA 210 36 | #define BYTEB 211 37 | #define BYTEC 212 38 | #define BYTED 213 39 | #define BYTEE 214 40 | #define BYTEF 215 41 | #define PBYTE0 216 42 | #define PBYTE1 217 43 | #define PBYTE2 218 44 | #define PBYTE3 219 45 | #define PBYTE4 220 46 | #define PBYTE5 221 47 | #define PBYTE6 222 48 | #define PBYTE7 223 49 | #define PBYTE8 224 50 | #define PBYTE9 225 51 | #define PBYTEA 226 52 | #define PBYTEB 227 53 | #define PBYTEC 228 54 | #define PBYTED 229 55 | #define PBYTEE 230 56 | #define PBYTEF 231 57 | #define BITPOS 232 58 | #define VALUE 300 59 | #define NICHT 400 60 | #define UND 401 61 | #define ODER 402 62 | #define XOR 403 63 | #define SHL 404 64 | #define SHR 405 65 | 66 | int nextToken(char **str, char **c, int *count); 67 | void pushBack(char **str, int n); 68 | float execExpression(char **str, unsigned char *bPtr, float floatV, char *err); 69 | float execTerm(char **str, unsigned char *bPtr, float floatV, char *err); 70 | float execFactor(char **str, unsigned char *bPtr, float floatV, char *err); 71 | int execIExpression(char **str, unsigned char *bPtr, char bitpos, char *pPtr, char *err); 72 | int execITerm(char **str, unsigned char *bPtr, char bitpos, char *pPtr, char *err); 73 | int execIFactor(char **str, unsigned char *bPtr, char bitpos, char *pPtr, char *err); 74 | 75 | float execExpression(char **str, unsigned char *bInPtr, float floatV, char *err) 76 | { 77 | int f = 1; 78 | float term1, term2; 79 | //float exp1,exp2; 80 | char *item; 81 | //unsigned char bPtr[10]; 82 | unsigned char bPtr[16]; 83 | int n; 84 | 85 | //printf("execExpression: %s\n",*str); 86 | 87 | // Tweak bPtr Bytes 0..9 and copy them to nPtr 88 | // We did not receive characters 89 | for (n = 0; n <= 15; n++) { 90 | //bPtr[n]=*bInPtr++ & 255; 91 | bPtr[n] = *bInPtr++; 92 | } 93 | 94 | switch (nextToken(str, &item, &n)) { 95 | case PLUS: 96 | f = 1; 97 | break; 98 | case MINUS: 99 | f = -1; 100 | break; 101 | default: 102 | pushBack(str, n); 103 | break; 104 | } 105 | 106 | term1 = execTerm(str, bPtr, floatV, err) * f; 107 | if (*err) { 108 | return 0; 109 | } 110 | //printf(" T1=%f\n",term1); 111 | 112 | int t; 113 | while ((t = nextToken(str, &item, &n)) != END) { 114 | f = 1; 115 | switch (t) { 116 | case PLUS: 117 | f = 1; 118 | break; 119 | case MINUS: 120 | f = -1; 121 | break; 122 | default: 123 | //printf(" Exp=%f\n",term1); 124 | pushBack(str, n); 125 | return term1; 126 | } 127 | 128 | term2 = execTerm(str, bPtr, floatV, err); 129 | if (*err) { 130 | return 0; 131 | } 132 | //printf(" T2=%f\n",term2); 133 | term1 += term2 * f; 134 | } 135 | 136 | //printf(" Exp=%f\n",term1); 137 | return term1; 138 | } 139 | 140 | float execTerm(char **str, unsigned char *bPtr, float floatV, char *err) 141 | { 142 | float factor1, factor2; 143 | int op; 144 | char *item; 145 | int n; 146 | 147 | //printf("execTerm: %s\n",*str); 148 | 149 | factor1 = execFactor(str, bPtr, floatV, err); 150 | if (*err) { 151 | return 0; 152 | } 153 | 154 | //printf(" F1=%f\n",factor1); 155 | while (1) { 156 | switch (nextToken(str, &item, &n)) { 157 | case MAL: 158 | op = MAL; 159 | break; 160 | case GETEILT: 161 | op = GETEILT; 162 | break; 163 | default: 164 | pushBack(str, n); 165 | //printf(" ret(%f)\n",factor1); 166 | return factor1; 167 | } 168 | factor2 = execFactor(str, bPtr, floatV, err); 169 | //printf(" F2=%f\n",factor2); 170 | if (*err) { 171 | return 0; 172 | } 173 | if (op == MAL) { 174 | factor1 *= factor2; 175 | } else { 176 | factor1 /= factor2; 177 | } 178 | } 179 | } 180 | 181 | float execFactor(char **str, unsigned char *bPtr, float floatV, char *err) 182 | { 183 | char nstring[100]; 184 | float expression; 185 | float factor; 186 | char *nPtr; 187 | char *item; 188 | char token; 189 | int n; 190 | 191 | //printf("execFactor: %s\n",*str); 192 | 193 | switch (nextToken(str, &item, &n)) { 194 | case BYTE0: 195 | return bPtr[0]; 196 | case BYTE1: 197 | return bPtr[1]; 198 | case BYTE2: 199 | return bPtr[2]; 200 | case BYTE3: 201 | return bPtr[3]; 202 | case BYTE4: 203 | return bPtr[4]; 204 | case BYTE5: 205 | return bPtr[5]; 206 | case BYTE6: 207 | return bPtr[6]; 208 | case BYTE7: 209 | return bPtr[7]; 210 | case BYTE8: 211 | return bPtr[8]; 212 | case BYTE9: 213 | return bPtr[9]; 214 | case BYTEA: 215 | return bPtr[10]; 216 | case BYTEB: 217 | return bPtr[11]; 218 | case BYTEC: 219 | return bPtr[12]; 220 | case BYTED: 221 | return bPtr[13]; 222 | case BYTEE: 223 | return bPtr[14]; 224 | case BYTEF: 225 | return bPtr[15]; 226 | case VALUE: 227 | return floatV; 228 | case HEX: 229 | nPtr = nstring; 230 | memset(nstring, 0, sizeof(nstring)); 231 | strcpy(nstring, "0x"); 232 | nPtr += 2; 233 | token = nextToken(str, &item, &n); 234 | while ((token == DIGIT) || (token == HEXDIGIT)) { 235 | *nPtr++ = *item; 236 | token = nextToken(str, &item, &n); 237 | } 238 | pushBack(str, n); 239 | sscanf(nstring, "%f", &factor); 240 | return factor; 241 | case DIGIT: 242 | nPtr = nstring; 243 | do { 244 | *nPtr++ = *item; 245 | } while ((token = nextToken(str, &item, &n)) == DIGIT); 246 | // If a . follows, we have a decimal number 247 | if (token == PUNKT) { 248 | do { 249 | *nPtr++ = *item; 250 | } while ((token = nextToken(str, &item, &n)) == DIGIT); 251 | } 252 | pushBack(str, n); 253 | *nPtr = '\0'; 254 | factor = atof(nstring); 255 | //printf(" Zahl: %s (f:%f)\n",nstring,factor); 256 | return factor; 257 | case KAUF: 258 | expression = execExpression(str, bPtr, floatV, err); 259 | if (*err) { 260 | return 0; 261 | } 262 | if (nextToken(str, &item, &n) != KZU) { 263 | sprintf(err, "expected factor:) [%c]\n", *item); 264 | return 0; 265 | } 266 | return expression; 267 | default: 268 | sprintf(err, "expected factor: B0..BF number ( ) [%c]\n", *item); 269 | return 0; 270 | } 271 | } 272 | 273 | int execIExpression(char **str, unsigned char *bInPtr, char bitpos, char *pPtr, char *err) 274 | { 275 | int f = 1; 276 | int term1, term2; 277 | //int exp1, exp2; 278 | int op; 279 | char *item; 280 | unsigned char bPtr[16]; 281 | int n; 282 | 283 | //printf("execExpression: %s\n", *str); 284 | 285 | // Tweak bPtr bytes 0..9 and copy them to nPtr 286 | // We have received characters 287 | for (n = 0; n <= 15; n++) { 288 | //bPtr[n]=*bInPtr++ & 255; 289 | bPtr[n] = *bInPtr++; 290 | } 291 | 292 | op = ERROR; 293 | switch (nextToken(str, &item, &n)) { 294 | case PLUS: 295 | op = PLUS; 296 | break; 297 | case MINUS: 298 | op = MINUS; 299 | break; 300 | case NICHT: 301 | op = NICHT; 302 | break; 303 | default: 304 | pushBack(str, n); 305 | break; 306 | } 307 | 308 | if (op == MINUS) { 309 | term1 = execITerm(str, bPtr, bitpos, pPtr, err) * -1; 310 | } else if (op == NICHT) { 311 | term1 = ~(execITerm(str, bPtr, bitpos, pPtr, err)); 312 | } else { 313 | term1 = execITerm(str, bPtr, bitpos, pPtr, err); 314 | } 315 | 316 | if (*err) { 317 | return 0; 318 | } 319 | //printf(" T1=%d\n",term1); 320 | 321 | int t; 322 | op = ERROR; 323 | while ((t = nextToken(str, &item, &n)) != END) { 324 | f = 1; 325 | switch (t) { 326 | case PLUS: 327 | op = PLUS; 328 | break; 329 | case MINUS: 330 | op = MINUS; 331 | break; 332 | case NICHT: 333 | op = NICHT; 334 | break; 335 | default: 336 | //printf(" Exp=%d\n",term1); 337 | pushBack(str, n); 338 | return term1; 339 | } 340 | 341 | if (op == MINUS) { 342 | term2 = execITerm(str, bPtr, bitpos, pPtr, err) * -1; 343 | } else if (op == NICHT) { 344 | term2 = ~(execITerm(str, bPtr, bitpos, pPtr, err)); 345 | } else if (op == PLUS) { 346 | term2 = execITerm(str, bPtr, bitpos, pPtr, err); 347 | } if (*err) { 348 | return 0; 349 | } 350 | //printf(" T2=%d\n",term2); 351 | term1 += term2; 352 | } 353 | 354 | //printf(" Exp=%d\n",term1); 355 | return term1; 356 | } 357 | 358 | int execITerm(char **str, unsigned char *bPtr, char bitpos, char *pPtr, char *err) 359 | { 360 | int factor1, factor2; 361 | int op; 362 | char *item; 363 | int n; 364 | 365 | //printf("execTerm: %s\n",*str); 366 | 367 | factor1 = execIFactor(str, bPtr, bitpos, pPtr, err); 368 | if (*err) { 369 | return 0; 370 | } 371 | 372 | while (1) { 373 | switch (nextToken(str, &item, &n)) { 374 | case MAL: 375 | op = MAL; 376 | break; 377 | case GETEILT: 378 | op = GETEILT; 379 | break; 380 | case MODULO: 381 | op = MODULO; 382 | break; 383 | case UND: 384 | op = UND; 385 | break; 386 | case ODER: 387 | op = ODER; 388 | break; 389 | case XOR: 390 | op = XOR; 391 | break; 392 | case SHL: 393 | op = SHL; 394 | break; 395 | case SHR: 396 | op = SHR; 397 | break; 398 | default: 399 | pushBack(str, n); 400 | //printf(" ret(%d)\n",factor1); 401 | return factor1; 402 | } 403 | 404 | factor2 = execIFactor(str, bPtr, bitpos, pPtr, err); 405 | 406 | if (*err) { 407 | return 0; 408 | } 409 | 410 | if (op == MAL) { 411 | factor1 *= factor2; 412 | } else if (op == GETEILT) { 413 | factor1 /= factor2; 414 | } else if (op == MODULO) { 415 | factor1 %= factor2; 416 | } else if (op == UND) { 417 | factor1 &= factor2; 418 | } else if (op == ODER) { 419 | factor1 |= factor2; 420 | } else if (op == XOR) { 421 | factor1 ^= factor2; 422 | } else if (op == SHL) { 423 | factor1 <<= factor2; 424 | } else if (op == SHR) { 425 | factor1 >>= factor2; 426 | } else { 427 | sprintf(err, "Error exec ITerm: Unknown token %d", op); 428 | return 0; 429 | } 430 | } 431 | } 432 | 433 | int execIFactor(char **str, unsigned char *bPtr, char bitpos, char *pPtr, char *err) 434 | { 435 | char nstring[100]; 436 | int expression; 437 | int factor; 438 | char *nPtr; 439 | char *item; 440 | char token; 441 | int n; 442 | 443 | //printf("execFactor: %s\n",*str); 444 | 445 | switch (nextToken(str, &item, &n)) { 446 | case BYTE0: 447 | return ((int)bPtr[0]) & 0xff; 448 | case BYTE1: 449 | return ((int)bPtr[1]) & 0xff; 450 | case BYTE2: 451 | return ((int)bPtr[2]) & 0xff; 452 | case BYTE3: 453 | return ((int)bPtr[3]) & 0xff; 454 | case BYTE4: 455 | return ((int)bPtr[4]) & 0xff; 456 | case BYTE5: 457 | return ((int)bPtr[5]) & 0xff; 458 | case BYTE6: 459 | return ((int)bPtr[6]) & 0xff; 460 | case BYTE7: 461 | return ((int)bPtr[7]) & 0xff; 462 | case BYTE8: 463 | return ((int)bPtr[8]) & 0xff; 464 | case BYTE9: 465 | return ((int)bPtr[9]) & 0xff; 466 | case BYTEA: 467 | return ((int)bPtr[10]) & 0xff; 468 | case BYTEB: 469 | return ((int)bPtr[11]) & 0xff; 470 | case BYTEC: 471 | return ((int)bPtr[12]) & 0xff; 472 | case BYTED: 473 | return ((int)bPtr[13]) & 0xff; 474 | case BYTEE: 475 | return ((int)bPtr[14]) & 0xff; 476 | case BYTEF: 477 | return ((int)bPtr[15]) & 0xff; 478 | case BITPOS: 479 | return ((int)bitpos) & 0xff; 480 | case PBYTE0: 481 | return ((int)pPtr[0]) & 0xff; 482 | case PBYTE1: 483 | return ((int)pPtr[1]) & 0xff; 484 | case PBYTE2: 485 | return ((int)pPtr[2]) & 0xff; 486 | case PBYTE3: 487 | return ((int)pPtr[3]) & 0xff; 488 | case PBYTE4: 489 | return ((int)pPtr[4]) & 0xff; 490 | case PBYTE5: 491 | return ((int)pPtr[5]) & 0xff; 492 | case PBYTE6: 493 | return ((int)pPtr[6]) & 0xff; 494 | case PBYTE7: 495 | return ((int)pPtr[7]) & 0xff; 496 | case PBYTE8: 497 | return ((int)pPtr[8]) & 0xff; 498 | case PBYTE9: 499 | return ((int)pPtr[9]) & 0xff; 500 | case PBYTEA: 501 | return ((int)pPtr[10]) & 0xff; 502 | case PBYTEB: 503 | return ((int)pPtr[11]) & 0xff; 504 | case PBYTEC: 505 | return ((int)pPtr[12]) & 0xff; 506 | case PBYTED: 507 | return ((int)pPtr[13]) & 0xff; 508 | case PBYTEE: 509 | return ((int)pPtr[14]) & 0xff; 510 | case PBYTEF: 511 | return ((int)pPtr[15]) & 0xff; 512 | case HEX: 513 | nPtr = nstring; 514 | memset(nstring, 0, sizeof(nstring)); 515 | strcpy(nstring, "0x"); 516 | nPtr += 2; 517 | token = nextToken(str, &item, &n); 518 | while ((token == DIGIT) || (token == HEXDIGIT)) { 519 | *nPtr++ = *item; 520 | token = nextToken(str, &item, &n); 521 | } 522 | pushBack(str, n); 523 | sscanf(nstring, "%i", &factor); 524 | return factor; 525 | case DIGIT: 526 | nPtr = nstring; 527 | do { 528 | *nPtr++ = *item; 529 | } while ((token = nextToken(str, &item, &n)) == DIGIT); 530 | // If a . follows, we have a decimal number 531 | if (token == PUNKT) { 532 | do { 533 | *nPtr++ = *item; 534 | } while ((token = nextToken(str, &item, &n)) == DIGIT); 535 | } 536 | pushBack(str, n); 537 | *nPtr = '\0'; 538 | factor = atof(nstring); 539 | return factor; 540 | case KAUF: 541 | expression = execIExpression(str, bPtr, bitpos, pPtr, err); 542 | if (*err) { 543 | return 0; 544 | } 545 | if (nextToken(str, &item, &n) != KZU) { 546 | sprintf(err, "expected factor:) [%c]\n", *item); 547 | return 0; 548 | } 549 | return expression; 550 | case NICHT: 551 | return ~execIFactor(str, bPtr, bitpos, pPtr, err); 552 | default: 553 | sprintf(err, "expected factor: B0..BF P0..PF BP number ( ) [%c]\n", *item); 554 | return 0; 555 | } 556 | } 557 | 558 | int nextToken(char **str, char **c, int *count) 559 | { 560 | char item; 561 | 562 | //printf("\tInput String:%s\n",*str); 563 | 564 | item = **str; 565 | while (isblank(item)) { 566 | item = *(++*str); 567 | } 568 | 569 | *c = *str; 570 | (*str)++; 571 | //printf("\t Token: %c [ %s ] \n",**c,*str); 572 | *count = 1; 573 | 574 | switch (**c) { 575 | case '+': 576 | return PLUS; 577 | case '-': 578 | return MINUS; 579 | case '*': 580 | return MAL; 581 | case '/': 582 | return GETEILT; 583 | case '%': 584 | return MODULO; 585 | case '(': 586 | return KAUF; 587 | case ')': 588 | return KZU; 589 | case 'V': 590 | return VALUE; 591 | case '^': 592 | return XOR; 593 | case '&': 594 | return UND; 595 | case '|': 596 | return ODER; 597 | case '~': 598 | return NICHT; 599 | case '0': 600 | if (*(*str) == 'x') { 601 | (*str)++; 602 | *count = 2; 603 | return HEX; 604 | } 605 | return DIGIT; 606 | case '<': 607 | *count = 2; 608 | switch (*(*str)++) { 609 | case '<' : 610 | return SHL; 611 | } 612 | case '>': 613 | *count = 2; 614 | switch (*(*str)++) { 615 | case '>': 616 | return SHR; 617 | } 618 | case 'B': 619 | *count = 2; 620 | switch (*(*str)++) { 621 | case '0': 622 | return BYTE0; 623 | case '1': 624 | return BYTE1; 625 | case '2': 626 | return BYTE2; 627 | case '3': 628 | return BYTE3; 629 | case '4': 630 | return BYTE4; 631 | case '5': 632 | return BYTE5; 633 | case '6': 634 | return BYTE6; 635 | case '7': 636 | return BYTE7; 637 | case '8': 638 | return BYTE8; 639 | case '9': 640 | return BYTE9; 641 | case 'A': 642 | return BYTEA; 643 | case 'B': 644 | return BYTEB; 645 | case 'C': 646 | return BYTEC; 647 | case 'D': 648 | return BYTED; 649 | case 'E': 650 | return BYTEE; 651 | case 'F': 652 | return BYTEF; 653 | case 'P': 654 | return BITPOS; 655 | } 656 | case 'P': 657 | *count = 2; 658 | switch (*(*str)++) { 659 | case '0': 660 | return PBYTE0; 661 | case '1': 662 | return PBYTE1; 663 | case '2': 664 | return PBYTE2; 665 | case '3': 666 | return PBYTE3; 667 | case '4': 668 | return PBYTE4; 669 | case '5': 670 | return PBYTE5; 671 | case '6': 672 | return PBYTE6; 673 | case '7': 674 | return PBYTE7; 675 | case '8': 676 | return PBYTE8; 677 | case '9': 678 | return PBYTE9; 679 | case 'A': 680 | return PBYTEA; 681 | case 'B': 682 | return PBYTEB; 683 | case 'C': 684 | return PBYTEC; 685 | case 'D': 686 | return PBYTED; 687 | case 'E': 688 | return PBYTEE; 689 | case 'F': 690 | return PBYTEF; 691 | } 692 | case '1': 693 | case '2': 694 | case '3': 695 | case '4': 696 | case '5': 697 | case '6': 698 | case '7': 699 | case '8': 700 | case '9': 701 | return DIGIT; 702 | case 'a': 703 | case 'b': 704 | case 'c': 705 | case 'd': 706 | case 'e' : 707 | case 'f': 708 | return HEXDIGIT; 709 | case '.': 710 | return PUNKT; 711 | case '\0': 712 | return END; 713 | default: 714 | return ERROR; 715 | } 716 | } 717 | 718 | void pushBack(char **str, int count) 719 | { 720 | (*str) -= count; 721 | //printf("\t<<::%s\n",*str); 722 | } 723 | -------------------------------------------------------------------------------- /src/arithmetic.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | // Calculation of arithmetic expressions 6 | 7 | #ifndef ARITHMETIC_H 8 | #define ARITHMETIC_H 9 | 10 | float execExpression(char **str, char *bPtr, float floatV, char *err); 11 | int execIExpression(char **str, char *bPtr, char bitpos, char *pPtr, char *err); 12 | 13 | #endif // ARITHMETIC_H 14 | -------------------------------------------------------------------------------- /src/client.c: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | // Client routines for vcontrold queries 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "client.h" 19 | #include "prompt.h" 20 | #include "common.h" 21 | #include "socket.h" 22 | 23 | static void sig_alrm(int); 24 | static jmp_buf env_alrm; 25 | 26 | int sendTrList(int sockfd, trPtr ptr); 27 | 28 | trPtr newTrNode(trPtr ptr) 29 | { 30 | trPtr nptr; 31 | 32 | if (ptr && ptr->next) { 33 | return newTrNode(ptr->next); 34 | } 35 | 36 | nptr = calloc(1, sizeof(*ptr)); 37 | if (! nptr) { 38 | fprintf(stderr, "malloc failed\n"); 39 | exit(1); 40 | } 41 | 42 | if (ptr) { 43 | ptr->next = nptr; 44 | } 45 | 46 | return nptr; 47 | } 48 | 49 | ssize_t recvSync(int fd, char *wait, char **recv) 50 | { 51 | char *rptr; 52 | char *pptr; 53 | char c; 54 | ssize_t count; 55 | int rcount = 1; 56 | 57 | if (signal(SIGALRM, sig_alrm) == SIG_ERR) { 58 | logIT1(LOG_ERR, "SIGALRM error"); 59 | } 60 | 61 | if (setjmp(env_alrm) != 0) { 62 | logIT(LOG_ERR, "timeout wait:%s", wait); 63 | return -1; 64 | } 65 | 66 | alarm(CL_TIMEOUT); 67 | 68 | if (! (*recv = calloc(ALLOCSIZE, sizeof(char)))) { 69 | logIT1(LOG_ERR, "calloc error"); 70 | exit(1); 71 | } 72 | 73 | rptr = *recv; 74 | size_t i = 0; 75 | while ((count = readn(fd, &c, 1))) { 76 | alarm(0); 77 | if (count < 0) { 78 | continue; 79 | } 80 | 81 | *rptr++ = c; 82 | *(rptr + 1) = '\0'; 83 | i++; 84 | if (! ((rptr - *recv + 1) % ALLOCSIZE)) { 85 | char *tmp = realloc(*recv, ALLOCSIZE * sizeof(char) * ++rcount); 86 | if (tmp == NULL) { 87 | logIT1(LOG_ERR, "realloc error"); 88 | exit(1); 89 | } else { 90 | *recv = tmp; 91 | rptr = *recv + i; 92 | } 93 | } 94 | 95 | if ((pptr = strstr(*recv, wait))) { 96 | *pptr = '\0'; 97 | logIT(LOG_INFO, "recv:%s", *recv); 98 | break; 99 | } 100 | 101 | alarm(CL_TIMEOUT); 102 | 103 | } 104 | 105 | char *tmp = realloc(*recv, strlen(*recv) + 1); 106 | if (tmp == NULL) { 107 | logIT1(LOG_ERR, "realloc error"); 108 | exit(1); 109 | } else { 110 | *recv = tmp; 111 | } 112 | 113 | if (count <= 0) { 114 | logIT(LOG_ERR, "exit with count=%ld", count);; 115 | } 116 | 117 | return count; 118 | } 119 | 120 | // port is never 0, which is a bad number for a tcp port 121 | int connectServer(char *host, int port) 122 | { 123 | int sockfd; 124 | 125 | if (host[0] != '/' ) { 126 | sockfd = openCliSocket(host, port, 0); 127 | if (sockfd) { 128 | logIT(LOG_INFO, "Setup connection to %s port %d", host, port); 129 | } else { 130 | logIT(LOG_INFO, "Setting up connection to %s port %d failed", host, port); 131 | return -1; 132 | } 133 | } else { 134 | logIT(LOG_ERR, "Host format: IP|Name:Port"); 135 | return -1; 136 | } 137 | return sockfd; 138 | } 139 | 140 | void disconnectServer(int sockfd) 141 | { 142 | char string[8]; 143 | char *ptr; 144 | 145 | snprintf(string, sizeof(string), "quit\n"); 146 | sendServer(sockfd, string, strlen(string)); 147 | recvSync(sockfd, BYE, &ptr); 148 | free(ptr); 149 | close(sockfd); 150 | } 151 | 152 | size_t sendServer(int fd, char *s_buf, size_t len) 153 | { 154 | char string[256]; 155 | 156 | // Empty buffer 157 | // As tcflush does not work correctly, we use nonblocking read 158 | fcntl(fd, F_SETFL, O_NONBLOCK); 159 | while (readn(fd, string, sizeof(string)) > 0) { } 160 | fcntl(fd, F_SETFL, ! O_NONBLOCK); 161 | return Writen(fd, s_buf, len); 162 | } 163 | 164 | trPtr sendCmdFile(int sockfd, const char *filename) 165 | { 166 | FILE *filePtr; 167 | char line[MAXBUF]; 168 | trPtr ptr; 169 | trPtr startPtr = NULL; 170 | 171 | if (! (filePtr = fopen(filename, "r"))) { 172 | return NULL; 173 | } else { 174 | logIT(LOG_INFO, "Opened command file %s", filename); 175 | } 176 | 177 | memset(line, 0, sizeof(line)); 178 | while (fgets(line, MAXBUF - 1, filePtr)) { 179 | ptr = newTrNode(startPtr); 180 | if (! startPtr) { 181 | startPtr = ptr; 182 | } 183 | ptr->cmd = calloc(strlen(line), sizeof(char)); 184 | strncpy(ptr->cmd, line, strlen(line) - 1); 185 | } 186 | 187 | if (! sendTrList(sockfd, startPtr)) { 188 | // Something with the communication went wrong 189 | return NULL; 190 | } 191 | 192 | return startPtr; 193 | } 194 | 195 | trPtr sendCmds(int sockfd, char *commands) 196 | { 197 | char *sptr; 198 | trPtr ptr; 199 | trPtr startPtr = NULL; 200 | 201 | sptr = strtok(commands, ","); 202 | do { 203 | ptr = newTrNode(startPtr); 204 | if (! startPtr) { 205 | startPtr = ptr; 206 | } 207 | ptr->cmd = calloc(strlen(sptr) + 1, sizeof(char)); 208 | strncpy(ptr->cmd, sptr, strlen(sptr)); 209 | } while ((sptr = strtok(NULL, ",")) != NULL); 210 | 211 | if (! sendTrList(sockfd, startPtr)) 212 | { 213 | // Something with the communication went wrong 214 | return NULL; 215 | } 216 | 217 | return startPtr; 218 | } 219 | 220 | int sendTrList(int sockfd, trPtr ptr) 221 | { 222 | char string[1000 + 1]; 223 | char prompt[] = PROMPT; 224 | char errTXT[] = ERR; 225 | char *sptr; 226 | char *dumPtr; 227 | 228 | if (recvSync(sockfd, prompt, &sptr) <= 0) { 229 | free(sptr); 230 | return 0; 231 | } 232 | 233 | while (ptr) { 234 | //memset(string, 0,sizeof(string)); 235 | snprintf(string, sizeof(string), "%s\n", ptr->cmd); 236 | 237 | if (sendServer(sockfd, string, strlen(string)) <= 0) { 238 | return 0; 239 | } 240 | 241 | //memset(string, 0,sizeof(string)); 242 | logIT(LOG_INFO, "SEND:%s", ptr->cmd); 243 | if (recvSync(sockfd, prompt, &sptr) <= 0) { 244 | free(sptr); 245 | return 0; 246 | } 247 | 248 | ptr->raw = sptr; 249 | if (iscntrl(*(ptr->raw + strlen(ptr->raw) - 1))) { 250 | *(ptr->raw + strlen(ptr->raw) - 1) = '\0'; 251 | } 252 | 253 | dumPtr = calloc(strlen(sptr) + 20, sizeof(char)); 254 | snprintf(dumPtr, (strlen(sptr) + 20) * sizeof(char), "RECV:%s", sptr); 255 | logIT1(LOG_INFO, dumPtr); 256 | free(dumPtr); 257 | 258 | // We fill errors and result 259 | if (strstr(ptr->raw, errTXT) == ptr->raw) { 260 | ptr->err = ptr->raw; 261 | fprintf(stderr, "SRV %s\n", ptr->err); 262 | } else { 263 | // Here, we search the first word in raw and save it as result 264 | char *rptr; 265 | char len; 266 | rptr = strchr(ptr->raw, ' '); 267 | if (! rptr) { 268 | rptr = ptr->raw + strlen(ptr->raw); 269 | } 270 | 271 | len = rptr - ptr->raw; 272 | ptr->result = atof(ptr->raw); 273 | ptr->err = NULL; 274 | } 275 | 276 | ptr = ptr->next; 277 | } 278 | 279 | return 1; 280 | } 281 | 282 | static void sig_alrm(int signo) 283 | { 284 | longjmp(env_alrm, 1); 285 | } 286 | -------------------------------------------------------------------------------- /src/client.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | #ifndef CLIENT_H 6 | #define CLIENT_H 7 | 8 | #define CL_TIMEOUT 25 9 | 10 | #ifndef MAXBUF 11 | #define MAXBUF 4096 12 | #endif 13 | 14 | #define ALLOCSIZE 256 15 | 16 | typedef struct txRx *trPtr; 17 | 18 | ssize_t recvSync(int fd, char *wait, char **recv); 19 | int connectServer(char *host, int port); 20 | void disconnectServer(int sockfd); 21 | size_t sendServer(int fd, char *s_buf, size_t len); 22 | trPtr sendCmdFile(int sockfd, const char *tmpfile); 23 | trPtr sendCmds(int sockfd, char *commands); 24 | 25 | typedef struct txRx { 26 | char *cmd; 27 | float result; 28 | char *err; 29 | char *raw; 30 | time_t timestamp; 31 | trPtr next; 32 | } TxRx; 33 | 34 | #endif // CLIENT_H 35 | -------------------------------------------------------------------------------- /src/common.c: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | // Common functions for vcontrold like logging and converting 6 | 7 | #define _GNU_SOURCE 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "common.h" 20 | 21 | int syslogger = 0; 22 | int debug = 0; 23 | FILE *logFD; 24 | char errMsg[2000]; 25 | int errClass = 99; 26 | int dbgFD = -1; 27 | 28 | int initLog(int useSyslog, char *logfile, int debugSwitch) 29 | { 30 | // If needed, opes the syslog or log file 31 | if (useSyslog) { 32 | syslogger = 1; 33 | openlog("vito", LOG_PID, LOG_LOCAL0); 34 | syslog(LOG_LOCAL0, "vito started"); 35 | } 36 | 37 | if (logfile) { 38 | // Log file is not NULL and not empty 39 | if (strcmp(logfile, "") == 0) { 40 | return 0; 41 | } 42 | 43 | logFD = fopen(logfile, "a"); 44 | if (! logFD) { 45 | printf("Could not open %s: %s", logfile, strerror (errno)); 46 | return 0 ; 47 | } 48 | } 49 | 50 | debug = debugSwitch; 51 | memset(errMsg, 0, sizeof(errMsg)); 52 | 53 | return 1; 54 | } 55 | 56 | void logIT (int class, char *string, ...) 57 | { 58 | va_list arguments; 59 | time_t t; 60 | char *tPtr; 61 | char *cPtr; 62 | time(&t); 63 | tPtr = ctime(&t); 64 | char *print_buffer; 65 | int pid; 66 | long avail; 67 | 68 | va_start(arguments, string); 69 | vasprintf(&print_buffer, string, arguments); 70 | va_end(arguments); 71 | 72 | if (class <= LOG_ERR) { 73 | avail = sizeof(errMsg) - strlen(errMsg) - 2; 74 | if ( avail > 0 ) { 75 | strncat(errMsg, print_buffer, avail); 76 | strcat(errMsg, "\n"); 77 | } else { 78 | strcpy(&errMsg[sizeof(errMsg) - 12], "OVERFLOW\n"); 79 | // Should solve the semop error 80 | } 81 | } 82 | 83 | errClass = class; 84 | // Remove control characters 85 | cPtr = tPtr; 86 | while (*cPtr) { 87 | if (iscntrl(*cPtr)) { 88 | *cPtr = ' '; 89 | } 90 | cPtr++; 91 | } 92 | 93 | if (dbgFD >= 0) { 94 | // The debug FD is set and we firstly send the info there 95 | dprintf(dbgFD, "DEBUG:%s: %s\n", tPtr, print_buffer); 96 | } 97 | 98 | if (! debug && (class > LOG_NOTICE)) { 99 | free(print_buffer); 100 | return; 101 | } 102 | 103 | pid = getpid(); 104 | 105 | if (syslogger) { 106 | syslog(class, "%s", print_buffer); 107 | } 108 | 109 | if (logFD) { 110 | fprintf(logFD, "[%d] %s: %s\n", pid, tPtr, print_buffer); 111 | fflush(logFD); 112 | } 113 | 114 | // Output only if 2 is open as STDERR 115 | if (isatty(2)) { 116 | fprintf(stderr, "[%d] %s: %s\n", pid, tPtr, print_buffer); 117 | } 118 | 119 | free(print_buffer); 120 | } 121 | 122 | void sendErrMsg(int fd) 123 | { 124 | char string[256]; 125 | 126 | if ((fd >= 0) && (errClass <= 3)) { 127 | snprintf(string, sizeof(string), "ERR: %s", errMsg); 128 | write(fd, string, strlen(string)); 129 | errClass = 99; // Thus it's only displayed once 130 | memset(errMsg, 0, sizeof(errMsg)); 131 | } 132 | 133 | *errMsg = '\0'; 134 | // Back to start, no matter if we actually output 135 | // Can be commented out for debugging, then we get the errors in errMsg 136 | } 137 | 138 | void setDebugFD(int fd) 139 | { 140 | dbgFD = fd; 141 | } 142 | 143 | char hex2chr(char *hex) 144 | { 145 | char buffer[16]; 146 | int hex_value = -1; 147 | 148 | snprintf(buffer, sizeof(buffer), "0x%s", hex); 149 | if (sscanf(hex, "%x", &hex_value) != 1) { 150 | logIT(LOG_WARNING, "Invalid hex char in %s", hex); 151 | } 152 | 153 | return hex_value; 154 | } 155 | 156 | int char2hex(char *outString, const char *charPtr, int len) 157 | { 158 | int n; 159 | char string[MAXBUF]; 160 | 161 | memset(string, 0, sizeof(string)); 162 | for (n = 0; n < len; n++) { 163 | unsigned char byte = *charPtr++ & 255; 164 | snprintf(string, sizeof(string), "%02X ", byte); 165 | strcat(outString, string); 166 | } 167 | 168 | // Remove last space 169 | outString[strlen(outString) - 1] = '\0'; 170 | 171 | return len; 172 | } 173 | 174 | short string2chr(char *line, char *buf, short bufsize) 175 | { 176 | char *sptr; 177 | short count; 178 | 179 | count = 0; 180 | 181 | sptr = strtok(line, " "); 182 | do { 183 | if (*sptr == ' ') { 184 | continue; 185 | } 186 | buf[count++] = hex2chr(sptr); 187 | } while ((sptr = strtok(NULL, " ")) && (count < bufsize)); 188 | 189 | return count; 190 | } 191 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | #ifndef COMMON_H 6 | #define COMMON_H 7 | 8 | int initLog(int useSyslog, char *logfile, int debugSwitch); 9 | void logIT (int class, char *string, ...); 10 | char hex2chr(char *hex); 11 | int char2hex(char *outString, const char *charPtr, int len); 12 | short string2chr(char *line, char *buf, short bufsize); 13 | void sendErrMsg(int fd); 14 | void setDebugFD(int fd); 15 | ssize_t readn(int fd, void *vptr, size_t n); 16 | 17 | #ifndef MAXBUF 18 | #define MAXBUF 4096 19 | #endif 20 | 21 | #ifndef DEFAULT_PORT 22 | #define DEFAULT_PORT 3002 23 | #endif 24 | 25 | #define logIT1(class, string) logIT(class, "%s", string) 26 | 27 | #endif // COMMON_H 28 | -------------------------------------------------------------------------------- /src/framer.c: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | /* 6 | * Framer interface 7 | * 8 | * For P300 framing is supported here 9 | * 10 | * Control is by a controlling byte P300_LEADING = 0x41 11 | * 12 | * with open and close P300 Mode is switched on, there is new xml-tag with protocol 13 | * definition which controls the switching of vitotronic to P300 mode. 14 | * additional assuming PDUs start by P300_LEADIN, else transferred as send by client 15 | * TODO: when PID is set, there is no need for defining a controlling x41 in getaddr etc. 16 | * 17 | * semaphore handling in vcontrol.c is changed to cover all from open until close to avoid 18 | * disturbance by other client trying to do uncoordinated open/close 19 | * 20 | * 2013-01-31 vheat 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "common.h" 32 | #include "io.h" 33 | #include "framer.h" 34 | 35 | typedef unsigned short int uint16; 36 | 37 | // general marker of P300 protocol 38 | #define P300_LEADIN 0x41 39 | #define P300_RESET 0x04 40 | #define P300_ENABLE { 0x16, 0x00, 0x00 } 41 | 42 | // message type 43 | #define P300_REQUEST 0x00 44 | #define P300_RESPONSE 0x01 45 | #define P300_ERROR_REPORT 0x03 46 | #define P300X_LINK_MNT 0x0f 47 | 48 | // function 49 | #define P300_READ_DATA 0x01 50 | #define P300_WRITE_DATA 0x02 51 | #define P300_FUNCT_CALL 0x07 52 | 53 | #define P300X_OPEN 0x01 54 | #define P300X_CLOSE 0x00 55 | #define P300X_ATTEMPTS 3 56 | 57 | // response 58 | #define P300_ERROR 0x15 59 | #define P300_NOT_INIT 0x05 60 | #define P300_INIT_OK 0x06 61 | 62 | // message buffer structure 63 | #define P300_LEADIN_OFFSET 0 64 | #define P300_LEN_OFFSET 1 65 | #define P300_TYPE_OFFSET 2 66 | #define P300_FCT_OFFSET 3 67 | #define P300_ADDR_OFFSET 4 68 | #define P300_RESP_LEN_OFFSET 6 69 | #define P300_BUFFER_OFFSET 7 70 | 71 | #define P300_LEADIN_LEN 1 72 | #define P300_LEN_LEN 1 73 | #define P300_CRC_LEN 1 74 | #define P300_EXTRA_BYTES (P300_LEADIN_LEN + P300_LEN_LEN + P300_CRC_LEN) 75 | 76 | #define FRAMER_READ_ERROR (-1) 77 | #define FRAMER_LINK_STATUS(st) (0xFE00 + st) 78 | #define FRAMER_READ_TIMEOUT 0 79 | 80 | #define FRAMER_NO_ADDR ((uint16) (-1)) 81 | 82 | // current active command 83 | static uint16 framer_current_addr = FRAMER_NO_ADDR; // stored value depends on Endianess 84 | 85 | // current active protocol 86 | static char framer_pid = 0; 87 | 88 | // status handling of current command 89 | static void framer_set_actaddr(void *pdu) 90 | { 91 | uint16 framer_old_addr; 92 | 93 | if (framer_current_addr != FRAMER_NO_ADDR) { 94 | logIT(LOG_ERR, ">FRAMER: addr was still active %04X", 95 | framer_current_addr); 96 | } 97 | framer_old_addr = framer_current_addr; 98 | framer_current_addr = *(uint16 *) (((char *) pdu) + P300_ADDR_OFFSET); 99 | logIT(LOG_DEBUG, ">FRAMER: framer_set_actaddr framer_current_addr = %04X (was %04X)", 100 | framer_current_addr, framer_old_addr); 101 | } 102 | 103 | static void framer_reset_actaddr(void) 104 | { 105 | logIT(LOG_DEBUG, ">FRAMER: framer_reset_actaddr framer_current_addr = FRAMER_NO_ADDR (was %04X)", 106 | framer_current_addr); 107 | framer_current_addr = FRAMER_NO_ADDR; 108 | } 109 | 110 | static int framer_check_actaddr(void *pdu) 111 | { 112 | if (framer_current_addr != *(uint16 *) (((char *) pdu) + P300_ADDR_OFFSET)) { 113 | logIT(LOG_ERR, ">FRAMER: addr corrupted stored %04X, now %04X", 114 | framer_current_addr, 115 | *(uint16 *) (((char *) pdu) + P300_ADDR_OFFSET)); 116 | return -1; 117 | } 118 | return 0; 119 | } 120 | 121 | // TODO: could cause trouble on addr containing 0xFE 122 | static void framer_set_result(char result) 123 | { 124 | logIT(LOG_DEBUG, ">FRAMER: framer_reset_actaddr framer_current_addr = FRAMER_LINK_STATUS(%02X) (was %04X)", 125 | result, framer_current_addr); 126 | framer_current_addr = FRAMER_LINK_STATUS(result); 127 | } 128 | 129 | static int framer_preset_result(char *r_buf, int r_len, unsigned long *petime) 130 | { 131 | if ((framer_pid == P300_LEADIN) && 132 | ((framer_current_addr & FRAMER_LINK_STATUS(0)) == FRAMER_LINK_STATUS(0))) { 133 | r_buf[0] = (char) (framer_current_addr ^ FRAMER_LINK_STATUS(0)); 134 | logIT(LOG_INFO, ">FRAMER: preset result %02X", r_buf[0]); 135 | return FRAMER_SUCCESS; 136 | } 137 | 138 | logIT(LOG_INFO, ">FRAMER: no preset result"); 139 | return FRAMER_ERROR; 140 | } 141 | 142 | // Synchronization for P300 + switch to P300, back to normal for close -> repeating P300X_ATTEMPTS 143 | static int framer_close_p300(int fd) 144 | { 145 | int i; 146 | char wbuf = P300_RESET; 147 | char rbuf = 0; 148 | unsigned long etime; 149 | int rlen; 150 | 151 | for (i = 0; i < P300X_ATTEMPTS; i++) { 152 | if (! my_send(fd, &wbuf, 1)) { 153 | framer_set_result(P300_ERROR); 154 | logIT(LOG_ERR, ">FRAMER: reset not send"); 155 | return FRAMER_ERROR; 156 | } 157 | etime = 0; 158 | rlen = receive_nb(fd, &rbuf, 1, &etime); 159 | if (rlen < 0) { 160 | framer_set_result(P300_ERROR); 161 | logIT(LOG_ERR, ">FRAMER: close read failure for ack"); 162 | return FRAMER_ERROR; 163 | } else if (rlen == 0) { 164 | framer_set_result(P300_ERROR); 165 | logIT(LOG_ERR, ">FRAMER: close read timeout for ack"); 166 | return FRAMER_ERROR; 167 | } else if ((rbuf == P300_INIT_OK) || (rbuf == P300_NOT_INIT)) { 168 | framer_set_result(P300_NOT_INIT); 169 | logIT(LOG_INFO, ">FRAMER: closed"); 170 | return FRAMER_SUCCESS; 171 | } else { 172 | logIT(LOG_ERR, ">FRAMER: unexpected data 0x%02X", rbuf); 173 | // continue anyway 174 | } 175 | } 176 | 177 | framer_set_result(P300_ERROR); 178 | logIT(LOG_ERR, ">FRAMER: could not close (%d attempts)", P300X_ATTEMPTS); 179 | return FRAMER_ERROR; 180 | } 181 | 182 | static int framer_open_p300(int fd) 183 | { 184 | int i; 185 | char rbuf = 0; 186 | char enable[] = P300_ENABLE; 187 | unsigned long etime; 188 | int rlen; 189 | 190 | for (i = 0; i < P300X_ATTEMPTS; i++) { 191 | if (! framer_close_p300(fd)) { 192 | logIT(LOG_ERR, ">FRAMER: could not set start condition"); 193 | return FRAMER_ERROR; 194 | } 195 | 196 | if (! my_send(fd, enable, sizeof(enable))) { 197 | framer_set_result(P300_ERROR); 198 | logIT(LOG_ERR, ">FRAMER: enable not send"); 199 | return FRAMER_ERROR; 200 | } 201 | 202 | etime = 0; 203 | rlen = receive_nb(fd, &rbuf, 1, &etime); 204 | if (rlen < 0) { 205 | framer_set_result(P300_ERROR); 206 | logIT(LOG_ERR, ">FRAMER: enable read failure for ack"); 207 | return FRAMER_ERROR; 208 | } else if (rlen == 0) { 209 | framer_set_result(P300_ERROR); 210 | logIT(LOG_ERR, ">FRAMER: enable read timeout for ack"); 211 | return FRAMER_ERROR; 212 | } else if (rbuf == P300_INIT_OK) { 213 | // hmueller: Replaced framer_set_result(P300_INIT_OK) 214 | // by framer_reset_actaddr() to avoid error log 215 | // >FRAMER: addr was still active FE06 216 | framer_reset_actaddr(); 217 | logIT(LOG_INFO, ">FRAMER: opened"); 218 | return FRAMER_SUCCESS; 219 | } 220 | } 221 | 222 | framer_set_result(P300_ERROR); 223 | logIT(LOG_ERR, ">FRAMER: could not close (%d attempts)", P300X_ATTEMPTS); 224 | 225 | return FRAMER_ERROR; 226 | } 227 | 228 | // calculation check sum for P300, assuming buffer is frame and starts by P300_LEADIN 229 | static char framer_chksum(char *buf, int len) 230 | { 231 | char sum = 0; 232 | while (len) { 233 | sum += *buf; 234 | //printf("framer chksum %d %02X %02X\n", len, *buf, sum); 235 | buf++; 236 | len--; 237 | } 238 | //printf("framer chksum %02x\n", sum); 239 | return sum; 240 | } 241 | 242 | /* 243 | * Frame a message in case P300 protocol is indicated 244 | * 245 | * Return 0: Error, else length of written bytes 246 | * This routine reads the first response byte for success status 247 | * 248 | * Format 249 | * Downlink 250 | * to framer 251 | * | type | function | addr | exp len | 252 | * to Vitotronic 253 | * | LEADIN | payload len | type | function | addr | exp len | chk | 254 | */ 255 | int framer_send(int fd, char *s_buf, int len) 256 | { 257 | if ((len < 1) || (! s_buf)) { 258 | logIT(LOG_ERR, ">FRAMER: invalid buffer %d %p", len, s_buf); 259 | return FRAMER_ERROR; 260 | } 261 | 262 | if (framer_pid != P300_LEADIN) { 263 | return my_send(fd, s_buf, len); 264 | } else if (len < 3) { 265 | logIT(LOG_ERR, ">FRAMER: too few for P300"); 266 | return FRAMER_ERROR; 267 | } else { 268 | int pos = 0; 269 | char l_buf[256]; 270 | unsigned long etime; 271 | int rlen; 272 | 273 | // prepare a new message, fill buffer starting with leadin 274 | l_buf[P300_LEADIN_OFFSET] = P300_LEADIN; 275 | l_buf[P300_LEN_OFFSET] = len; // only payload but len may contain other bytes 276 | memcpy(&l_buf[P300_TYPE_OFFSET], s_buf, len); 277 | l_buf[P300_LEADIN_LEN + P300_LEN_LEN + len] = 278 | framer_chksum(l_buf + P300_LEADIN_LEN, len + P300_LEN_LEN); 279 | if (! my_send(fd, l_buf, len + P300_EXTRA_BYTES)) { 280 | logIT(LOG_ERR, ">FRAMER: write failure %d", 281 | len + P300_EXTRA_BYTES); 282 | return FRAMER_ERROR; 283 | } 284 | 285 | etime = 0; 286 | rlen = receive_nb(fd, l_buf, 1, &etime); 287 | if (rlen < 0) { 288 | logIT(LOG_ERR, ">FRAMER: read failure %d", pos + 1); 289 | return FRAMER_ERROR; 290 | } else if (rlen == 0) { 291 | logIT(LOG_ERR, ">FRAMER: timeout for ack %d", pos + 1); 292 | return FRAMER_ERROR; 293 | } else if (*l_buf != P300_INIT_OK) { 294 | logIT(LOG_ERR, ">FRAMER: Error 0x%02X != 0x%02X (P300_INIT_OK)", 295 | *l_buf, P300_INIT_OK); 296 | return FRAMER_ERROR; 297 | } 298 | 299 | framer_set_actaddr(l_buf); 300 | logIT(LOG_INFO, ">FRAMER: Command send"); 301 | 302 | return FRAMER_SUCCESS; 303 | } 304 | } 305 | 306 | /* 307 | * Read a framed message in case P300 protocol is indicated 308 | * 309 | * Return 0: Error, else length of written bytes 310 | * This routine reads the first response byte for success status 311 | * 312 | * Format 313 | * from Vitotronic 314 | * | LEADIN | payload len | type | function | addr | exp len | chk | 315 | * Uplink 316 | * from framer 317 | * | data | 318 | * This simulates KW return, respective checking of the frame is done in this function 319 | * 320 | * etime is forwarded 321 | * return is FRAMER_ERROR, FRAMER_TIMEOUT or read len 322 | * 323 | * WEAKNESS: 324 | * If any other protocol gets an answer beginning 0x41, then this will return erroneous 325 | * KW may have values returned starting 0x41 326 | */ 327 | int framer_receive(int fd, char *r_buf, int r_len, unsigned long *petime) 328 | { 329 | int rlen; 330 | int total; 331 | int rtmp; 332 | char l_buf[256]; 333 | unsigned long etime; 334 | char chk; 335 | 336 | // to identify TimerWWMi bug 337 | l_buf[P300_ADDR_OFFSET] = 0; 338 | l_buf[P300_ADDR_OFFSET + 1] = 0; 339 | 340 | if ((r_len < 1) || (! r_buf)) { 341 | logIT(LOG_ERR, ">FRAMER: invalid read buffer %d %p", r_len, r_buf); 342 | return FRAMER_ERROR; 343 | } 344 | 345 | if (framer_preset_result(r_buf, r_len, petime)) { 346 | framer_reset_actaddr(); 347 | return FRAMER_SUCCESS; 348 | } 349 | 350 | *petime = 0; 351 | rtmp = receive_nb(fd, l_buf, r_len, petime); 352 | if (rtmp < 0) { 353 | framer_reset_actaddr(); 354 | logIT(LOG_ERR, ">FRAMER: read failure"); 355 | return FRAMER_READ_ERROR; 356 | } else if (rtmp == 0) { 357 | framer_reset_actaddr(); 358 | logIT(LOG_ERR, ">FRAMER: read timeout"); 359 | return FRAMER_READ_TIMEOUT; 360 | } else if (framer_pid != P300_LEADIN) { 361 | // no P300 frame, just forward 362 | memcpy(r_buf, l_buf, r_len); 363 | return rtmp; 364 | } 365 | 366 | // this is not GWG / KW we know now 367 | etime = 0; 368 | // read at least the length info 369 | if (rtmp < 2) { 370 | rlen = receive_nb(fd, l_buf + 1, 1, &etime); 371 | *petime += etime; 372 | if (rlen < 0) { 373 | framer_reset_actaddr(); 374 | logIT(LOG_ERR, ">FRAMER: read failure"); 375 | return FRAMER_READ_ERROR; 376 | } else if (rlen == 0) { 377 | framer_reset_actaddr(); 378 | logIT(LOG_ERR, ">FRAMER: read timeout"); 379 | return FRAMER_READ_TIMEOUT; 380 | } 381 | rtmp += rlen; 382 | } 383 | 384 | total = l_buf[P300_LEN_OFFSET] + P300_EXTRA_BYTES; 385 | rlen = total - rtmp; 386 | if (rlen <= 0) { 387 | framer_reset_actaddr(); 388 | logIT(LOG_ERR, ">FRAMER: strange read %d", rlen); 389 | return rtmp; // strange should not happen here 390 | } 391 | 392 | // now read what is extra 393 | rtmp = receive_nb(fd, l_buf + rtmp, rlen, &etime); 394 | *petime += etime; 395 | 396 | // check for leadin 397 | if (l_buf[P300_LEADIN_OFFSET] != P300_LEADIN) { 398 | framer_reset_actaddr(); 399 | logIT(LOG_ERR, ">FRAMER: read leadin error received 0x%02X expected 0x%02X", 400 | l_buf[P300_LEADIN_OFFSET], P300_LEADIN); 401 | return FRAMER_READ_ERROR; 402 | } 403 | 404 | // bug in Vitotronic getTimerWWMi, we got it, but complete 405 | if ((l_buf[P300_ADDR_OFFSET] == 0x21) && 406 | (l_buf[P300_ADDR_OFFSET + 1] == 0x10) && 407 | (rtmp == -1)) { 408 | logIT(LOG_ERR, ">FRAMER: bug of getTimerWWMi - omit checksum"); 409 | } else { 410 | if (rtmp < 0) { 411 | framer_reset_actaddr(); 412 | logIT(LOG_ERR, ">FRAMER: read final failure"); 413 | return FRAMER_READ_ERROR; 414 | } else if (rtmp == 0) { 415 | framer_reset_actaddr(); 416 | logIT(LOG_ERR, ">FRAMER: read final timeout"); 417 | return FRAMER_READ_TIMEOUT; 418 | } 419 | 420 | chk = framer_chksum(l_buf + P300_LEADIN_LEN, total - 2); 421 | if (l_buf[total - 1] != chk) { 422 | framer_reset_actaddr(); 423 | logIT(LOG_ERR, ">FRAMER: read chksum error received 0x%02X calc 0x%02X", 424 | (unsigned char)l_buf[total - 1], (unsigned char)chk); 425 | return FRAMER_READ_ERROR; 426 | } 427 | } 428 | 429 | if (l_buf[P300_TYPE_OFFSET] == P300_ERROR_REPORT) { 430 | framer_reset_actaddr(); 431 | logIT(LOG_ERR, ">FRAMER: ERROR address %02X%02X code %d", 432 | l_buf[P300_ADDR_OFFSET], l_buf[P300_ADDR_OFFSET + 1], 433 | l_buf[P300_BUFFER_OFFSET]); 434 | return FRAMER_READ_ERROR; 435 | } 436 | 437 | // TODO: could add check for address receive matching address send before 438 | if (framer_check_actaddr(l_buf)) { 439 | framer_reset_actaddr(); 440 | logIT(LOG_ERR, ">FRAMER: not matching response addr"); 441 | return FRAMER_READ_ERROR; 442 | } 443 | 444 | if ((l_buf[P300_FCT_OFFSET] == P300_WRITE_DATA) && (r_len == 1)) { 445 | // TODO: could add check for length matching previously requested data length 446 | if (r_len != (l_buf[P300_LEN_OFFSET] - 4)) { 447 | logIT(LOG_ERR, ">FRAMER: unexpected length r_len=0x%02X != 0x%02X=l_buf[P300_LEN_OFFSET]-4", 448 | r_len, l_buf[P300_LEN_OFFSET] - 4); 449 | framer_reset_actaddr(); 450 | return FRAMER_READ_ERROR; 451 | } 452 | // if we have a P300 setaddr we do not get data back ... 453 | if (l_buf[P300_TYPE_OFFSET] == P300_RESPONSE) { 454 | // OK 455 | r_buf[rtmp] = 0x00; 456 | } else { 457 | // NOT OK 458 | r_buf[rtmp] = 0x01; 459 | } 460 | } else { 461 | if (r_len != (l_buf[P300_RESP_LEN_OFFSET])) { 462 | logIT(LOG_ERR, ">FRAMER: unexpected length r_len=0x%02X != 0x%02X=l_buf[P300_RESP_LEN_OFFSET]", 463 | r_len, l_buf[P300_RESP_LEN_OFFSET]); 464 | framer_reset_actaddr(); 465 | return FRAMER_READ_ERROR; 466 | } 467 | memcpy(r_buf, &l_buf[P300_BUFFER_OFFSET], r_len); 468 | } 469 | 470 | framer_reset_actaddr(); 471 | return r_len; 472 | } 473 | 474 | int framer_waitfor(int fd, char *w_buf, int w_len) 475 | { 476 | unsigned long etime; 477 | 478 | if (framer_preset_result(w_buf, w_len, &etime)) { 479 | framer_reset_actaddr(); 480 | return FRAMER_SUCCESS; 481 | } 482 | 483 | return waitfor(fd, w_buf, w_len); 484 | } 485 | 486 | // Device handling, with open and close the mode is also switched to P300/back 487 | int framer_openDevice(char *device, char pid) 488 | { 489 | int fd; 490 | 491 | logIT(LOG_INFO, ">FRAMER: open device %s ProtocolID %02X", device, pid); 492 | 493 | if ((fd = openDevice(device)) == -1) { 494 | return -1; 495 | } 496 | 497 | if (pid == P300_LEADIN) { 498 | if (! framer_open_p300(fd)) { 499 | closeDevice(fd); 500 | return -1; 501 | } 502 | } 503 | 504 | framer_pid = pid; 505 | return fd; 506 | } 507 | 508 | void framer_closeDevice(int fd) 509 | { 510 | if (framer_pid == P300_LEADIN) { 511 | framer_close_p300(fd); 512 | } 513 | 514 | framer_pid = 0; 515 | closeDevice(fd); 516 | } 517 | -------------------------------------------------------------------------------- /src/framer.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | /* 6 | * Framer interface 7 | * 8 | * For P300 framing is supported here 9 | * 10 | * Control is by a controlling byte defining the action 11 | * 12 | * 2013-01-31 vheat 13 | */ 14 | 15 | /* 16 | * Main indentification of P300 Protocol is about leadin 0x41 17 | */ 18 | 19 | #ifndef FRAMER_H 20 | #define FRAMER_H 21 | 22 | #define FRAMER_ERROR 0 23 | #define FRAMER_SUCCESS 1 24 | 25 | int framer_send(int fd, char *s_buf, int len); 26 | int framer_waitfor(int fd, char *w_buf, int w_len); 27 | int framer_receive(int fd, char *r_buf, int r_len, unsigned long *petime); 28 | int framer_openDevice(char *device, char pid); 29 | void framer_closeDevice(int fd); 30 | 31 | #endif // FRAMER_H 32 | -------------------------------------------------------------------------------- /src/io.c: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | // Communication with the vito controller 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "io.h" 25 | #include "socket.h" 26 | #include "common.h" 27 | 28 | #ifdef __CYGWIN__ 29 | // NCC is not defined under cygwin 30 | #define NCC NCCS 31 | #endif 32 | 33 | static void sig_alrm(int); 34 | static jmp_buf env_alrm; 35 | 36 | void closeDevice(int fd) 37 | { 38 | close(fd); 39 | } 40 | 41 | int openDevice(char *device) 42 | { 43 | // We differentiate TTY and Socket connections. 44 | // Socker: no / at the beginning and a : 45 | int fd; 46 | char *dptr; 47 | 48 | if (device[0] != '/' && (dptr = strchr(device, ':'))) { 49 | char host[MAXBUF]; 50 | int port; 51 | port = atoi(dptr + 1); 52 | // The dptr device gives us the length of the host 53 | memset(host, 0, sizeof(host)); 54 | strncpy(host, device, dptr - device); 55 | // Third parameter == 1 --> noTCPDelay set 56 | fd = openCliSocket(host, port, 1); 57 | } else { 58 | fd = opentty(device); 59 | } 60 | 61 | if (fd < 0) { 62 | // Here goes some error stuff 63 | return -1; 64 | } 65 | 66 | return fd; 67 | } 68 | 69 | int opentty(char *device) 70 | { 71 | int fd; 72 | 73 | logIT(LOG_LOCAL0, "Configuring serial interface %s", device); 74 | if ((fd = open(device, O_RDWR)) < 0) { 75 | logIT(LOG_ERR, "cannot open %s:%m", device); 76 | exit(1); 77 | } 78 | 79 | int s; 80 | struct termios oldsb, newsb; 81 | s = tcgetattr(fd, &oldsb); 82 | if (s < 0) { 83 | logIT(LOG_ERR, "error tcgetattr %s:%m", device); 84 | exit(1); 85 | } 86 | 87 | newsb = oldsb; 88 | 89 | #ifdef NCC 90 | // NCC is not always defined 91 | for (s = 0; s < NCC; s++) { 92 | newsb.c_cc[s] = 0; 93 | } 94 | #else 95 | memset(&newsb, 0, sizeof(newsb)); 96 | #endif 97 | 98 | newsb.c_iflag = IGNBRK | IGNPAR; 99 | newsb.c_oflag = 0; 100 | newsb.c_lflag = 0; // removed ISIG for susp=control-z problem; 101 | newsb.c_cflag = (CLOCAL | B4800 | CS8 | CREAD | PARENB | CSTOPB); 102 | newsb.c_cc[VMIN] = 1; 103 | newsb.c_cc[VTIME] = 0; 104 | 105 | tcsetattr(fd, TCSADRAIN, &newsb); 106 | 107 | // DTR High for voltage supply 108 | int modemctl = 0; 109 | ioctl(fd, TIOCMGET, &modemctl); 110 | modemctl |= TIOCM_DTR; 111 | s = ioctl(fd, TIOCMSET, &modemctl); 112 | if (s < 0) { 113 | logIT(LOG_ERR, "error ioctl TIOCMSET %s:%m", device); 114 | exit(1); 115 | } 116 | 117 | return fd; 118 | } 119 | 120 | int my_send(int fd, char *s_buf, int len) 121 | { 122 | int i; 123 | int wr; 124 | // Empty buffer 125 | tcflush(fd, TCIOFLUSH); 126 | // We use the socket fixed variant from socket.c 127 | wr = writen(fd, s_buf, len); 128 | for (i = 0; i < len; i++) { 129 | unsigned char byte = s_buf[i] & 255; 130 | logIT(LOG_INFO, ">SENT: %02X", (int)byte); 131 | } 132 | 133 | if (wr == len) { 134 | return wr; 135 | } else { 136 | logIT(LOG_ERR, ">ERROR: sent %d of %d bytes", wr, len); 137 | return 0; 138 | } 139 | } 140 | 141 | int receive(int fd, char *r_buf, int r_len, unsigned long *etime) 142 | { 143 | int i; 144 | struct tms tms_t; 145 | clock_t start, end, mid, mid1; 146 | unsigned long clktck; 147 | 148 | clktck = sysconf(_SC_CLK_TCK); 149 | start = times(&tms_t); 150 | mid1 = start; 151 | for (i = 0; i < r_len; i++) { 152 | if (signal(SIGALRM, sig_alrm) == SIG_ERR) { 153 | logIT1(LOG_ERR, "SIGALRM error"); 154 | } 155 | if (setjmp(env_alrm) != 0) { 156 | logIT1(LOG_ERR, "read timeout"); 157 | return -1; 158 | } 159 | alarm(TIMEOUT); 160 | // We use the socket fixed variant from socket.c 161 | if (readn(fd, &r_buf[i], 1) <= 0) { 162 | logIT1(LOG_ERR, "error read tty");; 163 | alarm(0); 164 | return -1; 165 | } 166 | 167 | alarm(0); 168 | unsigned char byte = r_buf[i] & 255; 169 | mid = times(&tms_t); 170 | logIT(LOG_INFO, " TIMEOUT) { 333 | logIT1(LOG_WARNING, "Timeout wait"); 334 | return 0; 335 | } 336 | } while (r_buf[0] != w_buf[0]); 337 | 338 | for (i = 1; i < w_len; i++) { 339 | etime = 0; 340 | if (receive(fd, r_buf, 1, &etime) < 0) { 341 | return 0; 342 | } 343 | if (time(NULL) - start > TIMEOUT) { 344 | logIT1(LOG_WARNING, "Timeout wait"); 345 | return 0; 346 | } 347 | if ( r_buf[0] != w_buf[i]) { 348 | logIT1(LOG_ERR, "Lost synchronization"); 349 | exit(1); 350 | } 351 | } 352 | 353 | // logIT1(LOG_INFO,"Recognized string"); 354 | return 1; 355 | } 356 | -------------------------------------------------------------------------------- /src/io.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | #ifndef IO_H 6 | #define IO_H 7 | 8 | int my_send(int fd, char *s_buf, int len); 9 | int receive(int fd, char *r_buf, int r_len, unsigned long *etime); 10 | int receive_nb(int fd, char *r_buf, int r_len, unsigned long *etime); 11 | int waitfor(int fd, char *w_buf, int w_len); 12 | int opentty(char *device); 13 | int openDevice(char *device); 14 | void closeDevice(int fd); 15 | 16 | // Interface parameters 17 | 18 | #define TTY "/dev/usb/tts/0" 19 | 20 | #ifndef MAXBUF 21 | #define MAXBUF 4096 22 | #endif 23 | #define TIMEOUT 5 24 | 25 | #endif // IO_H 26 | -------------------------------------------------------------------------------- /src/parser.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | #ifndef PARSER_H 6 | #define PARSER_H 7 | 8 | int parseLine(char *lineo, char *hex, int *hexlen, char *uSPtr, ssize_t uSPtrLen); 9 | int execCmd(char *cmd, int fd, char *result, int resultLen); 10 | void removeCompileList(compilePtr ptr); 11 | int execByteCode(compilePtr cmpPtr, int fd, char *recvBuf, short recvLen, char *sendBuf, 12 | short sendLen, short supressUnit, char bitpos, int retry, char *pRecvPtr, 13 | unsigned short recvTimeout); 14 | void compileCommand(devicePtr dPtr, unitPtr uPtr); 15 | 16 | // Token Definition 17 | #define WAIT 1 18 | #define RECV 2 19 | #define SEND 3 20 | #define PAUSE 4 21 | #define BYTES 5 22 | 23 | #ifndef MAXBUF 24 | #define MAXBUF 4096 25 | #endif 26 | 27 | #endif // PARSER_H 28 | -------------------------------------------------------------------------------- /src/prompt.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | /* Prompt Definition fuer die gemeinsame Nutzung in client und Server */ 6 | 7 | #ifndef PROMPT_H 8 | #define PROMPT_H 9 | 10 | #define PROMPT "vctrld>" 11 | #define BYE "good bye!\n" 12 | #define UNKNOWN "ERR: command unknown\n" 13 | #define ERR "ERR:" 14 | 15 | #endif // PROMPT_H 16 | -------------------------------------------------------------------------------- /src/semaphore.c: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "common.h" 17 | #include "semaphore.h" 18 | 19 | #define MAX_RETRIES 10 20 | 21 | #if !defined(__APPLE__) 22 | // on my mac this is a redefinition 23 | union semun { 24 | int val; 25 | struct semid_ds *buf; 26 | unsigned short *array; 27 | }; 28 | #endif 29 | 30 | /* 31 | * initsem() -- more-than-inspired by W. Richard Stevens' UNIX Network 32 | * Programming 2nd edition, volume 2, lockvsem.c, page 295. 33 | */ 34 | int initsem(key_t key, int nsems) 35 | { 36 | // key from ftok() 37 | int i; 38 | union semun arg; 39 | struct semid_ds buf; 40 | struct sembuf sb; 41 | int semid; 42 | 43 | semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666); 44 | 45 | if (semid >= 0) { // we got it first 46 | sb.sem_op = 1; 47 | sb.sem_flg = 0; 48 | arg.val = 1; 49 | 50 | for (sb.sem_num = 0; sb.sem_num < nsems; sb.sem_num++) { 51 | // do a semop() to "free" the semaphores. 52 | // this sets the sem_otime field, as needed below. 53 | if (semop(semid, &sb, 1) == -1) { 54 | int e = errno; 55 | semctl(semid, 0, IPC_RMID); // clean up 56 | errno = e; 57 | return -1; // error, check errno 58 | } 59 | } 60 | } else if (errno == EEXIST) { 61 | // someone else got it first 62 | int ready = 0; 63 | 64 | semid = semget(key, nsems, 0); // get the id 65 | if (semid < 0) { 66 | // error, check errno 67 | return semid; 68 | } 69 | 70 | // wait for other process to initialize the semaphore: 71 | arg.buf = &buf; 72 | for (i = 0; i < MAX_RETRIES && !ready; i++) { 73 | semctl(semid, nsems - 1, IPC_STAT, arg); 74 | if (arg.buf->sem_otime != 0) { 75 | ready = 1; 76 | } else { 77 | sleep(1); 78 | } 79 | } 80 | if (! ready) { 81 | errno = ETIME; 82 | return -1; 83 | } 84 | } else { 85 | return semid; 86 | // error, check errno 87 | } 88 | 89 | return semid; 90 | } 91 | 92 | int semid; 93 | char tmpfilename[MAXPATHLEN + 1]; // account for the leading '\0' 94 | 95 | int vcontrol_seminit() 96 | { 97 | key_t key; 98 | struct sembuf sb; 99 | 100 | int tmpfile; 101 | 102 | strncpy(tmpfilename, TMPFILENAME, sizeof(TMPFILENAME)); 103 | if ((tmpfile = mkstemp(tmpfilename)) < 0) { 104 | perror("mkstemp"); 105 | exit(1); 106 | } 107 | close(tmpfile); 108 | 109 | sb.sem_num = 0; 110 | sb.sem_op = -1; // set to allocate resource 111 | sb.sem_flg = SEM_UNDO; 112 | 113 | if ((key = ftok(tmpfilename, 'V')) == -1) { 114 | perror("ftok"); 115 | exit(1); 116 | } 117 | 118 | // grab the semaphore set created by seminit.c: 119 | if ((semid = initsem(key, 1)) == -1) { 120 | perror("initsem"); 121 | exit(1); 122 | } 123 | return 1; 124 | } 125 | 126 | int vcontrol_semfree() 127 | { 128 | // remove it: 129 | if (semctl(semid, 0, IPC_RMID) == -1) { 130 | perror("semctl"); 131 | exit(1); 132 | } 133 | unlink(tmpfilename); 134 | return 1; // what should we return? 135 | } 136 | 137 | int vcontrol_semget() 138 | { 139 | logIT(LOG_INFO, "Process %d tries to aquire lock", getpid()); 140 | 141 | struct sembuf sb; 142 | 143 | sb.sem_num = 0; 144 | sb.sem_op = -1; // set to allocate resource 145 | sb.sem_flg = SEM_UNDO; 146 | if (semop(semid, &sb, 1) == -1) { 147 | perror("semop"); 148 | exit(1); 149 | } 150 | logIT(LOG_INFO, "Process %d got lock", getpid()); 151 | return 1; 152 | } 153 | 154 | int vcontrol_semrelease() 155 | { 156 | struct sembuf sb; 157 | 158 | logIT(LOG_INFO, "Process %d released lock", getpid()); 159 | 160 | sb.sem_num = 0; 161 | sb.sem_op = 1; // free resource 162 | sb.sem_flg = SEM_UNDO; 163 | if (semop(semid, &sb, 1) == -1) { 164 | perror("semop"); 165 | exit(1); 166 | } 167 | 168 | return 1; 169 | } 170 | -------------------------------------------------------------------------------- /src/semaphore.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | #ifndef SEMAPHORE_H 6 | #define SEMAPHORE_H 7 | 8 | #include 9 | 10 | #ifdef _CYGWIN__ 11 | #define TMPFILENAME "vcontrol.lockXXXXXX" 12 | #else 13 | #define TMPFILENAME "/tmp/vcontrol.lockXXXXXX" 14 | #endif 15 | 16 | extern char tmpfilename[MAXPATHLEN + 1]; // account for the leading '\0' 17 | 18 | int vcontrol_seminit(); 19 | int vcontrol_semfree(); 20 | int vcontrol_semget(); 21 | int vcontrol_semrelease(); 22 | 23 | #endif // SEMAPHORE_H 24 | -------------------------------------------------------------------------------- /src/socket.c: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | #define _GNU_SOURCE 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include // TCP_NODELAY is defined there -fn- 25 | #if defined (__FreeBSD__) || defined(__APPLE__) 26 | #include 27 | #endif 28 | 29 | #include "socket.h" 30 | #include "common.h" 31 | #include "vclient.h" 32 | 33 | const int LISTEN_QUEUE = 128; 34 | 35 | int openSocket(int tcpport) 36 | { 37 | return openSocket2(tcpport, NULL); 38 | } 39 | int openSocket2(int tcpport, const char* listenAddress) 40 | { 41 | int listenfd; 42 | int n; 43 | char *port; 44 | struct addrinfo hints, *res, *ressave; 45 | 46 | memset(&hints, 0, sizeof(struct addrinfo)); 47 | 48 | switch (inetversion) { 49 | case 6: 50 | hints.ai_family = PF_INET6; 51 | break; 52 | case 4: 53 | // this is for backward compatibility. We can explictly 54 | // activate IPv6 with the -6 switch. Later we can use 55 | // PF_UNSPEC as default and let the OS decide 56 | default: 57 | hints.ai_family = PF_INET; 58 | } 59 | 60 | hints.ai_socktype = SOCK_STREAM; 61 | hints.ai_protocol = IPPROTO_TCP; 62 | hints.ai_flags = AI_PASSIVE; 63 | 64 | asprintf(&port, "%d", tcpport); 65 | 66 | n = getaddrinfo(listenAddress, port, &hints, &res); 67 | 68 | free(port); 69 | 70 | if (n != 0) { 71 | logIT(LOG_ERR, "getaddrinfo error: [%s]\n", gai_strerror(n)); 72 | return -1; 73 | } 74 | 75 | ressave = res; 76 | 77 | // Try open socket with each address getaddrinfo returned, 78 | // until getting a valid listening socket. 79 | 80 | listenfd = -1; 81 | while (res) { 82 | listenfd = socket(res->ai_family, 83 | res->ai_socktype, 84 | res->ai_protocol); 85 | int optval = 1; 86 | if (listenfd > 0 && setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, 87 | &optval, sizeof optval) < 0 ) { 88 | logIT1(LOG_ERR, "setsockopt failed!"); 89 | exit(1); 90 | } 91 | if (! (listenfd < 0)) { 92 | if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) { 93 | break; 94 | } 95 | close(listenfd); 96 | listenfd = -1; 97 | } 98 | res = res->ai_next; 99 | } 100 | 101 | if (listenfd < 0) { 102 | freeaddrinfo(ressave); 103 | fprintf(stderr, "socket error: could not open socket\n"); 104 | exit(1); 105 | } 106 | 107 | if (listen(listenfd, LISTEN_QUEUE) != 0) { 108 | freeaddrinfo(ressave); 109 | fprintf(stderr, "listen error: could not listen on %s:%d\n", listenAddress, tcpport); 110 | exit(1); 111 | } 112 | if (hints.ai_family == PF_INET6) { 113 | logIT(LOG_NOTICE, "TCP socket %s::%d opened", (listenAddress == NULL ? "" : listenAddress), tcpport); 114 | } else { 115 | logIT(LOG_NOTICE, "TCP socket %s:%d opened", (listenAddress == NULL ? "0.0.0.0" : listenAddress), tcpport); 116 | } 117 | 118 | freeaddrinfo(ressave); 119 | 120 | return listenfd; 121 | } 122 | 123 | int listenToSocket(int listenfd, int makeChild) 124 | { 125 | int connfd; 126 | pid_t childpid; 127 | struct sockaddr_storage cliaddr; 128 | socklen_t cliaddrlen = sizeof(cliaddr); 129 | char clienthost [NI_MAXHOST]; 130 | char clientservice[NI_MAXSERV]; 131 | 132 | signal(SIGCHLD, SIG_IGN); 133 | 134 | for (;;) { 135 | connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &cliaddrlen); 136 | getnameinfo((struct sockaddr *) &cliaddr, cliaddrlen, clienthost, sizeof(clienthost), 137 | clientservice, sizeof(clientservice), NI_NUMERICHOST); 138 | 139 | if (connfd < 0) { 140 | logIT(LOG_NOTICE, "accept on host %s: port %s", clienthost, clientservice); 141 | close(connfd); 142 | continue; 143 | } 144 | 145 | logIT(LOG_NOTICE, "Client connected %s:%s (FD:%d)", clienthost, clientservice, connfd); 146 | if (! makeChild) { 147 | return connfd; 148 | } else if ( (childpid = fork()) == 0) { 149 | // unser Kind 150 | close(listenfd); 151 | return connfd; 152 | } else { 153 | logIT(LOG_INFO, "Child process started with pid %d", childpid); 154 | } 155 | 156 | close(connfd); 157 | } 158 | } 159 | 160 | void closeSocket(int sockfd) 161 | { 162 | logIT(LOG_INFO, "Closed connection (fd:%d)", sockfd); 163 | close(sockfd); 164 | } 165 | 166 | int openCliSocket(char *host, int port, int noTCPdelay) 167 | { 168 | struct addrinfo hints; // use hints for ipv46 address resolution 169 | struct addrinfo *res; 170 | struct addrinfo *ressave; 171 | int n; 172 | int sockfd; 173 | char port_string[16]; // the IPv6 world use a char* instead of an int in getaddrinfo 174 | 175 | memset(&hints, 0, sizeof(struct addrinfo)); 176 | 177 | hints.ai_family = PF_UNSPEC; 178 | hints.ai_socktype = SOCK_STREAM; 179 | hints.ai_flags = AI_ALL | AI_V4MAPPED; 180 | 181 | snprintf(port_string, sizeof(port_string), "%d", port); 182 | n = getaddrinfo(host, port_string, &hints, &res); 183 | if (n < 0) { 184 | logIT(LOG_ERR, "Error in getaddrinfo: %s:%s", host, gai_strerror(n)); 185 | exit(1); 186 | } 187 | 188 | ressave = res; 189 | 190 | sockfd = -1; 191 | while (res) { 192 | sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 193 | if (! (sockfd < 0)) { 194 | if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0) { 195 | break; 196 | } 197 | // we have a succesfull connection 198 | close(sockfd); 199 | sockfd = -1; 200 | } 201 | res = res->ai_next; 202 | } 203 | 204 | freeaddrinfo(ressave); 205 | 206 | if (sockfd < 0) { 207 | logIT(LOG_ERR, "TTY Net: No connection to %s:%d", host, port); 208 | return -1; 209 | } 210 | logIT(LOG_INFO, "ClI Net: connected %s:%d (FD:%d)", host, port, sockfd); 211 | int flag = 1; 212 | if (noTCPdelay && (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)))) { 213 | logIT(LOG_ERR, "Error in setsockopt TCP_NODELAY (%s)", strerror(errno)); 214 | } 215 | 216 | return sockfd; 217 | } 218 | 219 | // Stuff aus Unix Network Programming Vol 1 220 | // include writen 221 | 222 | // Write "n" bytes to a descriptor. 223 | ssize_t writen(int fd, const void *vptr, size_t n) 224 | { 225 | size_t nleft; 226 | ssize_t nwritten; 227 | const char *ptr; 228 | 229 | ptr = vptr; 230 | nleft = n; 231 | while (nleft > 0) { 232 | if ((nwritten = write(fd, ptr, nleft)) <= 0) { 233 | if (errno == EINTR) { 234 | // and call write() again 235 | nwritten = 0; 236 | } else { 237 | // error 238 | return -1; 239 | } 240 | } 241 | nleft -= nwritten; 242 | ptr += nwritten; 243 | } 244 | return n; 245 | } 246 | 247 | // end writen 248 | 249 | ssize_t Writen(int fd, void *ptr, size_t nbytes) 250 | { 251 | if (writen(fd, ptr, nbytes) != nbytes) { 252 | logIT1(LOG_ERR, "Error writing to socket"); 253 | return 0; 254 | } 255 | return nbytes; 256 | } 257 | 258 | // include readn 259 | 260 | // Read "n" bytes from a descriptor. 261 | ssize_t readn(int fd, void *vptr, size_t n) 262 | { 263 | size_t nleft; 264 | ssize_t nread; 265 | char *ptr; 266 | 267 | ptr = vptr; 268 | nleft = n; 269 | while (nleft > 0) { 270 | if ((nread = read(fd, ptr, nleft)) < 0) { 271 | if (errno == EINTR) { 272 | // and call read() again 273 | nread = 0; 274 | } 275 | else { 276 | return -1; 277 | } 278 | } else if (nread == 0) { 279 | // EOF 280 | break; 281 | } 282 | 283 | #ifdef __CYGWIN__ 284 | // This is a workaround for Cygwin. 285 | // Here cygwins read(fd,buff,count) is reading more than count chars! this is bad! 286 | if (nread > nleft) { 287 | nleft = 0; 288 | } else { 289 | nleft -= nread; 290 | } 291 | #else 292 | nleft -= nread; 293 | #endif 294 | ptr += nread; 295 | } 296 | 297 | return n - nleft; //return >= 0 298 | } 299 | 300 | // end readn 301 | 302 | ssize_t Readn(int fd, void *ptr, size_t nbytes) 303 | { 304 | ssize_t n; 305 | if ((n = readn(fd, ptr, nbytes)) < 0) { 306 | logIT1(LOG_ERR, "Error reading from socket"); 307 | return 0; 308 | } 309 | return n; 310 | } 311 | 312 | // include readline 313 | 314 | static ssize_t my_read(int fd, char *ptr) 315 | { 316 | 317 | static ssize_t read_cnt = 0; 318 | static char *read_ptr; 319 | static char read_buf[MAXLINE]; 320 | 321 | if (read_cnt <= 0) { 322 | again: 323 | if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) { 324 | if (errno == EINTR) { 325 | goto again; 326 | } 327 | return -1; 328 | } else if (read_cnt == 0) { 329 | return 0; 330 | } 331 | read_ptr = read_buf; 332 | } 333 | 334 | read_cnt--; 335 | *ptr = *read_ptr++; 336 | return 1; 337 | } 338 | 339 | ssize_t readline(int fd, void *vptr, size_t maxlen) 340 | { 341 | int n; 342 | ssize_t rc; 343 | char c; 344 | char *ptr; 345 | 346 | ptr = vptr; 347 | for (n = 1; n < maxlen; n++) { 348 | if ( (rc = my_read(fd, &c)) == 1) { 349 | *ptr++ = c; 350 | if (c == '\n') { 351 | // newline is stored, like fgets() 352 | break; 353 | } 354 | } else if (rc == 0) { 355 | if (n == 1) { 356 | // EOF, no data read 357 | return 0; 358 | } 359 | else { 360 | // EOF, some data was read 361 | break; 362 | } 363 | } else { 364 | // error, errno set by read() 365 | return -1; 366 | } 367 | } 368 | 369 | *ptr = 0; // null terminate like fgets() 370 | return n; 371 | } 372 | 373 | // end readline 374 | 375 | ssize_t Readline(int fd, void *ptr, size_t maxlen) 376 | { 377 | ssize_t n; 378 | 379 | if ((n = readline(fd, ptr, maxlen)) < 0) { 380 | logIT1(LOG_ERR, "Error reading from socket"); 381 | return 0; 382 | } 383 | return n; 384 | } 385 | -------------------------------------------------------------------------------- /src/socket.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | #ifndef SOCKET_H 6 | #define SOCKET_H 7 | 8 | #include 9 | 10 | int openSocket(int tcpport); 11 | int openSocket2(int tcpport, const char* listenAddress); 12 | int listenToSocket(int listenfd, int makeChild); 13 | int openCliSocket(char *host, int port, int noTCPdelay); 14 | void closeSocket(int sockfd); 15 | 16 | ssize_t writen(int fd, const void *vptr, size_t n); 17 | ssize_t Writen(int fd, void *ptr, size_t nbytes); 18 | 19 | ssize_t readn(int fd, void *vptr, size_t n); 20 | ssize_t Readn(int fd, void *ptr, size_t nbytes); 21 | 22 | ssize_t readline(int fd, void *vptr, size_t maxlen); 23 | ssize_t Readline(int fd, void *ptr, size_t maxlen); 24 | 25 | #define LISTENQ 1024 26 | #define MAXLINE 1000 27 | 28 | #define CONNECT_TIMEOUT 3 29 | 30 | #endif // SOCKET_H 31 | -------------------------------------------------------------------------------- /src/unit.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | #ifndef UNIT_H 6 | #define UNIT_H 7 | 8 | int procGetUnit(unitPtr uPtr, char *recvBuf, int len, char *result, char bitpos, char *pRecvPtr); 9 | int procSetUnit(unitPtr uPtr, char *sendBuf, short *sendLen, char bitpos, char *pRecvPtr); 10 | 11 | #endif // UNIT_H 12 | -------------------------------------------------------------------------------- /src/vclient.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | #ifndef VCLIENT_H 6 | #define VCLIENT_H 7 | 8 | extern int inetversion; 9 | 10 | #endif // VCLIENT_H 11 | -------------------------------------------------------------------------------- /src/version.h.in: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2017-2022 Tobias Leupold 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | #ifndef VERSION_H 6 | #define VERSION_H 7 | 8 | #define VERSION "@VERSION@" 9 | 10 | #endif // VERSION_H 11 | -------------------------------------------------------------------------------- /src/vsim.c: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | #define _GNU_SOURCE 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "socket.h" 27 | #include "vclient.h" 28 | 29 | #define SERVERPORT 6578 30 | int makeDaemon = 0; 31 | int inetversion = 0; 32 | int readCmdFile(char *filename, char *result, int *resultLen, char *device ); 33 | int interactive(int socketfd, char *device); 34 | void printHelp(int socketfd); 35 | int rawModus (int socketfd, char *device); 36 | static void sigPipeHandler(int signo); 37 | 38 | void logIT (int class, char *string, ...) 39 | { 40 | va_list arguments; 41 | char *print_buffer; 42 | 43 | va_start(arguments, string); 44 | vasprintf(&print_buffer, string, arguments); 45 | va_end(arguments); 46 | printf("%s\n", print_buffer); 47 | free(print_buffer); 48 | } 49 | 50 | static void sigPipeHandler(int signo) 51 | { 52 | logIT(LOG_ERR, "Received SIGPIPE"); 53 | } 54 | 55 | static void dump(char *buf, int len, char *txt) 56 | { 57 | int i = 0; 58 | printf("%s:\n", txt); 59 | for (i = 0; i < len; i++) { 60 | printf(" %02x", (unsigned char)buf[i]); 61 | } 62 | printf("\n"); 63 | } 64 | 65 | typedef struct { 66 | int cmdlen; 67 | char cmd[20]; 68 | int rsplen; 69 | char rsp[20]; 70 | } ctable; 71 | 72 | int cmdc = 9; 73 | ctable cmds[] = { 74 | { 1, { 0x04 }, 1, { 0x05 } }, 75 | { 3, { 0x16, 0x00, 0x00 }, 1, { 0x06 } }, 76 | { 5, { 0x01, 0xf7, 0xcb, 0x70, 01 }, 2, {0x30, 0x00 } }, 77 | { 78 | 8, { 0x41, 0x05, 0x00, 0x01, 0x55, 0x25, 0x02, 0x82 }, 79 | 11, { 0x06, 0x41, 0x07, 0x01, 0x01, 0x55, 0x25, 0x02, 0x07, 0x01, 0x8D } 80 | }, 81 | { 82 | 8, { 0x41, 0x05, 0x00, 0x01, 0x08, 0x00, 0x02, 0x10 }, 83 | 11, { 0x06, 0x41, 0x07, 0x01, 0x01, 0x08, 0x00, 0x02, 0x07, 0x01, 0x1B } 84 | }, 85 | { 86 | 8, { 0x41, 0x05, 0x00, 0x01, 0x21, 0x10, 0x08, 0x3F }, 87 | 16, { 0x06, 0x41, 0x0D, 0x01, 0x01, 0x21, 0x10, 0x08, 0x28, 0xB0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } 88 | }, 89 | { 90 | 5, { 0x01, 0xf7, 0x08, 0x00, 0x02 }, 91 | 2, { 0x07, 0x01 } 92 | }, 93 | { 94 | 8, { 0x41, 0x05, 0x00, 0x01, 0x08, 0x04, 0x02, 0x14 }, 95 | 11, { 0x06, 0x41, 0x07, 0x01, 0x01, 0x08, 0x04, 0x02, 0x00, 0x00, 0x17 } 96 | }, 97 | }; 98 | 99 | char input[100]; 100 | char inpidx = 0; 101 | 102 | static void handle(int fd) 103 | { 104 | char buf[1] = "\0"; 105 | ssize_t len; 106 | 107 | while ( 1 ) { 108 | len = readn(fd, buf, 1); 109 | if (len < 0) { 110 | perror("read eror\n"); 111 | exit(-1); 112 | } else if (len == 0) { 113 | printf("eof read\n"); 114 | return; 115 | } else { 116 | int i = 0; 117 | int j = 0; 118 | while ( i < len ) { 119 | input[inpidx] = buf[i]; 120 | dump(&input[inpidx], 1, "received char:"); 121 | inpidx++; 122 | for ( j = 0 ; j < cmdc; j++) { 123 | if ( cmds[j].cmd[0] == input[0] ) { 124 | if (( cmds[j].cmdlen == inpidx) && (!memcmp(cmds[j].cmd, input, inpidx))) { 125 | dump(input, inpidx, "received cmd:"); 126 | dump(cmds[j].rsp, cmds[j].rsplen, "answer:"); 127 | if (writen(fd, cmds[j].rsp, cmds[j].rsplen) != cmds[j].rsplen) { 128 | printf("not completely written\n"); 129 | } 130 | inpidx = 0; 131 | } 132 | } 133 | } 134 | i++; 135 | } 136 | } 137 | } 138 | } 139 | 140 | int main(int argc, char *argv[]) 141 | { 142 | int sockfd = -1; 143 | int listenfd = -1; 144 | 145 | listenfd = openSocket(SERVERPORT); 146 | while (1) { 147 | sockfd = listenToSocket(listenfd, makeDaemon); 148 | if (signal(SIGPIPE, sigPipeHandler) == SIG_ERR) { 149 | logIT(LOG_ERR, "Signal error"); 150 | exit(1); 151 | } 152 | if (sockfd >= 0) { 153 | // Socket returned fd, the rest is done interactively 154 | logIT(LOG_INFO, "\nvcontrold connected"); 155 | handle(sockfd); 156 | logIT(LOG_INFO, "\nvcontrold disconnected"); 157 | closeSocket(sockfd); 158 | } else { 159 | logIT(LOG_ERR, "Error during connection setup"); 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/xmlconfig.h: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2007-2016 The original vcontrold authors (cf. doc/original_authors.txt) 2 | // 3 | // SPDX-License-Identifier: GPL-3.0-or-later 4 | 5 | #ifndef XMLCONFIG_H 6 | #define XMLCONFIG_H 7 | #include 8 | 9 | typedef struct config *configPtr; 10 | typedef struct protocol *protocolPtr; 11 | typedef struct unit *unitPtr; 12 | typedef struct macro *macroPtr; 13 | typedef struct command *commandPtr; 14 | typedef struct compile *compilePtr; 15 | typedef struct device *devicePtr; 16 | typedef struct icmd *icmdPtr; 17 | typedef struct allow *allowPtr; 18 | typedef struct enumerate *enumPtr; 19 | 20 | int parseXMLFile(char *filename); 21 | macroPtr getMacroNode(macroPtr ptr, const char *name); 22 | unitPtr getUnitNode(unitPtr ptr, const char *name); 23 | commandPtr getCommandNode(commandPtr ptr, const char *name); 24 | enumPtr getEnumNode(enumPtr prt, char *search, int len); 25 | icmdPtr getIcmdNode(icmdPtr ptr, const char *name); 26 | 27 | typedef struct compile { 28 | int token; 29 | char *send; 30 | int len; 31 | unitPtr uPtr; 32 | char *errStr; 33 | compilePtr next; 34 | } Compile; 35 | 36 | typedef struct config { 37 | char *tty; 38 | int port; 39 | char *listenAddress; 40 | char *logfile; 41 | char *pidfile; 42 | char *username; 43 | char *groupname; 44 | char *devID; 45 | devicePtr devPtr; 46 | int syslog; 47 | int debug; 48 | } Config; 49 | 50 | typedef struct protocol { 51 | char *name; 52 | char id; 53 | macroPtr mPtr; 54 | icmdPtr icPtr; 55 | protocolPtr next; 56 | } Protocol; 57 | 58 | typedef struct device { 59 | char *name; 60 | char *id; 61 | commandPtr cmdPtr; 62 | protocolPtr protoPtr; 63 | devicePtr next; 64 | } Device; 65 | 66 | typedef struct unit { 67 | char *name; 68 | char *abbrev; 69 | char *gCalc; 70 | char *sCalc; 71 | char *gICalc; 72 | char *sICalc; 73 | char *entity; 74 | char *type; 75 | enumPtr ePtr; 76 | unitPtr next; 77 | } Unit; 78 | 79 | typedef struct macro { 80 | char *name; 81 | char *command; 82 | macroPtr next; 83 | } Macro; 84 | 85 | typedef struct command { 86 | char *name; 87 | char *pcmd; 88 | char *send; 89 | char *addr; 90 | char *unit; 91 | char *errStr; 92 | char *precmd; 93 | unsigned char len; 94 | int retry; 95 | unsigned short recvTimeout; 96 | char bit; 97 | char nodeType; 98 | // 0: everything copied 99 | // 1: everything orig 100 | // 2: only address, unit len orig 101 | compilePtr cmpPtr; 102 | char *description; 103 | commandPtr next; 104 | } Command; 105 | 106 | typedef struct icmd { 107 | char *name; 108 | char *send; 109 | unsigned char retry; 110 | unsigned short recvTimeout; 111 | icmdPtr next; 112 | } iCmd; 113 | 114 | typedef struct enumerate { 115 | char *bytes; 116 | int len; 117 | char *text; 118 | enumPtr next; 119 | } Enumerate; 120 | 121 | #endif // XMLCONFIG_H 122 | -------------------------------------------------------------------------------- /xml/300/vcontrold.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | nobody 10 | dialout 11 | 12 | /dev/ttySAC1 13 | 14 | 15 | 16 | 17 | 3002 18 | 19 | 20 | vcontrold.log 21 | n 22 | n 23 | 24 | 25 | 26 | 27 | 28 | 29 | UT 30 | 31 | short 32 | Grad Celsius 33 | 34 | 35 | UTH 36 | 37 | short 38 | Grad Celsius 39 | 40 | 41 | UN 42 | 43 | short 44 | 45 | 46 | 47 | UT1 48 | 49 | char 50 | Grad Celsius 51 | 52 | 53 | UT1U 54 | 55 | uchar 56 | Grad Celsius 57 | 58 | 59 | UTI 60 | 61 | uchar 62 | Grad Celsius 63 | 64 | 65 | ST 66 | 67 | char 68 | 69 | 70 | 71 | CO 72 | 73 | int 74 | 75 | 76 | 77 | VS 78 | 79 | ushort 80 | l/h 81 | 82 | 83 | COL 84 | 85 | int 86 | 87 | 88 | 89 | PR 90 | 91 | short 92 | % 93 | 94 | 95 | PR1 96 | 97 | uchar 98 | % 99 | 100 | 101 | PR2 102 | 103 | uchar 104 | % 105 | 106 | 107 | PR3 108 | 109 | uchar 110 | % 111 | 112 | 113 | CS 114 | 115 | uint 116 | Stunden 117 | 118 | 119 | CT 120 | cycletime 121 | 122 | 123 | RT 124 | enum 125 | 126 | 127 | 129 | 130 | 131 | 132 | 133 | BA 134 | enum 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | SR 145 | enum 146 | 147 | 148 | 149 | 150 | 151 | TI 152 | systime 153 | 154 | 155 | ES 156 | errstate 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | DT 226 | enum 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | SN 235 | uint 236 | 237 | 238 | 239 | BH 240 | uchar 241 | 242 | h 243 | 244 | 245 | ESG 246 | enum 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | BST 259 | uchar 260 | 261 | 262 | 263 | 264 | 265 | 266 | HKT 267 | uchar 268 | 269 | 270 | 271 | 272 | 273 | 274 | USV 275 | enum 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 41 286 | 287 | 288 | SEND 00 01 289 | 290 | 291 | SEND 00 02 292 | 293 | 294 | 295 | 296 | GETADDR $addr $hexlen;RECV $len $unit 297 | 298 | 299 | SETADDR $addr $hexlen;SEND BYTES $unit;RECV 1 SR 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | SEND 04;WAIT 05 310 | 311 | 312 | SEND 01 F7 313 | 314 | 315 | SEND 01 F4 316 | 317 | 318 | 319 | 320 | 3 321 | 4000 322 | SYNC;GETADDR $addr $hexlen;RECV $len $unit 323 | 324 | 325 | SYNC;SETADDR $addr $hexlen;SEND BYTES $unit;RECV 1 SR 326 | 327 | 328 | 3 329 | 1500 330 | SYNC;GETADDR;SEND BYTES;SEND 02;RECV 02 331 | 332 | 333 | 334 | 335 | 336 | 337 | SEND 04;WAIT 05 338 | 339 | 340 | SEND 01 CB 341 | 342 | 343 | SEND 01 9E 344 | 345 | 346 | SEND 01 C7 347 | 348 | 349 | SEND 01 6E 350 | 351 | 352 | SEND 01 AE 353 | 354 | 355 | SEND 01 C5 356 | 357 | 358 | SEND 01 43 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 3 370 | 4000 371 | SYNC;GETADDR $addr $hexlen 04;RECV $len $unit 372 | 373 | 374 | 3 375 | 4000 376 | SYNC;GETADDR;SEND BYTES;SEND 01 04;RECV 1 377 | 378 | 379 | 3 380 | 4000 381 | SYNC;GETBADDR $addr $hexlen 04;RECV $len $unit 382 | 383 | 384 | 3 385 | 4000 386 | SYNC;GETBADDR;SEND BYTES;SEND 01 04;RECV 1 387 | 388 | 389 | 3 390 | 4000 391 | SYNC;GETPADDR $addr $hexlen 04;RECV $len $unit 392 | 393 | 394 | 3 395 | 4000 396 | SYNC;GETPADDR;SEND BYTES;SEND 01 04;RECV 1 397 | 398 | 399 | 3 400 | 4000 401 | SYNC;GETVADDR $addr $hexlen 04;RECV $len $unit 402 | 403 | 404 | 3 405 | 4000 406 | SYNC;GETVADDR;SEND BYTES;SEND 01 04;RECV 1 407 | 408 | 409 | 3 410 | 4000 411 | SYNC;GETEADDR $addr $hexlen 04;RECV $len $unit 412 | 413 | 414 | 3 415 | 150 416 | SYNC;GETEADDR;SEND BYTES;SEND 01 04;RECV 1 417 | 418 | 419 | 3 420 | 150 421 | SYNC;GETXADDR $addr $hexlen 04;RECV $len $unit 422 | 423 | 424 | 3 425 | 4000 426 | SYNC;GETXADDR;SEND BYTES;SEND 01 04;RECV 1 427 | 428 | 429 | SYNC;GETKMDDR $addr $hexlen 04;RECV $len $unit 430 | 3 431 | 4000 432 | 433 | 434 | 3 435 | 4000 436 | SYNC;GETKMADDR;SEND BYTES;SEND 01 04;RECV 1 437 | 438 | 439 | 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 440 | 3 441 | 442 | 443 | SYNC;SETADDR $addr $hexlen;SEND BYTES $unit;RECV 1 SR 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | -------------------------------------------------------------------------------- /xml/kw/vcontrold.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 192.168.1.153:3002 7 | 8 | 9 | 10 | 11 | 3002 12 | 13 | 14 | /tmp/vcontrold.log 15 | n 16 | n 17 | 18 | 19 | 20 | 21 | 22 | 23 | UT 24 | 25 | short 26 | Grad Celsius 27 | 28 | 29 | UN 30 | 31 | short 32 | 33 | 34 | 35 | UT1 36 | 37 | char 38 | Grad Celsius 39 | 40 | 41 | UT1U 42 | 43 | uchar 44 | Grad Celsius 45 | 46 | 47 | UTI 48 | 49 | uchar 50 | Grad Celsius 51 | 52 | 53 | ST 54 | 55 | char 56 | 57 | 58 | 59 | CO 60 | 61 | int 62 | 63 | 64 | 65 | PR 66 | 67 | short 68 | % 69 | 70 | 71 | PR1 72 | 73 | uchar 74 | % 75 | 76 | 77 | CS 78 | 79 | uint 80 | Stunden 81 | 82 | 83 | CT 84 | cycletime 85 | 86 | 87 | RT 88 | enum 89 | 90 | 91 | 92 | 93 | 94 | BA 95 | enum 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | SR 106 | enum 107 | 108 | 109 | 110 | 111 | 112 | TI 113 | systime 114 | 115 | 116 | ES 117 | errstate 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | DT 186 | enum 187 | 188 | 189 | 190 | 191 | 192 | 193 | BH 194 | uchar 195 | 196 | h 197 | 198 | 199 | ESG 200 | enum 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | BST 213 | uchar 214 | 215 | 216 | 217 | 218 | 219 | 220 | HKT 221 | uchar 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | SEND 04;WAIT 05 233 | 234 | 235 | SEND 01 F7 236 | 237 | 238 | SEND 01 F4 239 | 240 | 241 | 242 | 243 | SYNC;GETADDR $addr $hexlen;RECV $len $unit 244 | 245 | 246 | SYNC;SETADDR $addr $hexlen;SEND BYTES $unit;RECV 1 SR 247 | 248 | 249 | 250 | 251 | 252 | 253 | SEND 04;WAIT 05 254 | 255 | 256 | SEND 01 CB 257 | 258 | 259 | SEND 01 9E 260 | 261 | 262 | SEND 01 C7 263 | 264 | 265 | SEND 01 6E 266 | 267 | 268 | SEND 01 AE 269 | 270 | 271 | SEND 01 C5 272 | 273 | 274 | SEND 01 43 275 | 276 | 277 | 278 | 279 | 3 280 | 150 281 | SYNC;GETADDR $addr $hexlen 04;RECV $len $unit 282 | 283 | 284 | 3 285 | 150 286 | SYNC;GETADDR;SEND BYTES;SEND 01 04;RECV 1 287 | 288 | 289 | 3 290 | 150 291 | SYNC;GETBADDR $addr $hexlen 04;RECV $len $unit 292 | 293 | 294 | 3 295 | 150 296 | SYNC;GETBADDR;SEND BYTES;SEND 01 04;RECV 1 297 | 298 | 299 | 3 300 | 150 301 | SYNC;GETPADDR $addr $hexlen 04;RECV $len $unit 302 | 303 | 304 | 3 305 | 150 306 | SYNC;GETPADDR;SEND BYTES;SEND 01 04;RECV 1 307 | 308 | 309 | 3 310 | 150 311 | SYNC;GETVADDR $addr $hexlen 04;RECV $len $unit 312 | 313 | 314 | 3 315 | 150 316 | SYNC;GETVADDR;SEND BYTES;SEND 01 04;RECV 1 317 | 318 | 319 | 3 320 | 150 321 | SYNC;GETEADDR $addr $hexlen 04;RECV $len $unit 322 | 323 | 324 | 3 325 | 150 326 | SYNC;GETEADDR;SEND BYTES;SEND 01 04;RECV 1 327 | 328 | 329 | 3 330 | 150 331 | SYNC;GETXADDR $addr $hexlen 04;RECV $len $unit 332 | 333 | 334 | 3 335 | 150 336 | SYNC;GETXADDR;SEND BYTES;SEND 01 04;RECV 1 337 | 338 | 339 | SYNC;GETKMDDR $addr $hexlen 04;RECV $len $unit 340 | 3 341 | 150 342 | 343 | 344 | 3 345 | 150 346 | SYNC;GETKMADDR;SEND BYTES;SEND 01 04;RECV 1 347 | 348 | 349 | SEND 16 00 00;PAUSE 100;SEND 16 00 00;PAUSE 100;SEND 16 00 00;PAUSE 100;SEND 16 00 00;PAUSE 100 350 | 351 | 352 | SYNC;RECV 1 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | --------------------------------------------------------------------------------