srcpd-2.1.7/0000775000175000017500000000000014615104512007636 500000000000000srcpd-2.1.7/INSTALL0000644000175000017500000003662614370170730010625 00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2017, 2020-2021 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell command './configure && make && make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the 'README' file for instructions specific to this package. Some packages provide this 'INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The 'configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a 'Makefile' in each directory of the package. It may also create one or more '.h' files containing system-dependent definitions. Finally, it creates a shell script 'config.status' that you can run in the future to recreate the current configuration, and a file 'config.log' containing compiler output (useful mainly for debugging 'configure'). It can also use an optional file (typically called 'config.cache' and enabled with '--cache-file=config.cache' or simply '-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how 'configure' could check whether to do them, and mail diffs or instructions to the address given in the 'README' so they can be considered for the next release. If you are using the cache, and at some point 'config.cache' contains results you don't want to keep, you may remove or edit it. The file 'configure.ac' (or 'configure.in') is used to create 'configure' by a program called 'autoconf'. You need 'configure.ac' if you want to change it or regenerate 'configure' using a newer version of 'autoconf'. The simplest way to compile this package is: 1. 'cd' to the directory containing the package's source code and type './configure' to configure the package for your system. Running 'configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type 'make' to compile the package. 3. Optionally, type 'make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type 'make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the 'make install' phase executed with root privileges. 5. Optionally, type 'make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior 'make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing 'make clean'. To also remove the files that 'configure' created (so you can compile the package for a different kind of computer), type 'make distclean'. There is also a 'make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type 'make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide 'make distcheck', which can by used by developers to test that all other targets like 'make install' and 'make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the 'configure' script does not know about. Run './configure --help' for details on some of the pertinent environment variables. You can give 'configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU 'make'. 'cd' to the directory where you want the object files and executables to go and run the 'configure' script. 'configure' automatically checks for the source code in the directory that 'configure' is in and in '..'. This is known as a "VPATH" build. With a non-GNU 'make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use 'make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple '-arch' options to the compiler but only a single '-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the 'lipo' tool if you have problems. Installation Names ================== By default, 'make install' installs the package's commands under '/usr/local/bin', include files under '/usr/local/include', etc. You can specify an installation prefix other than '/usr/local' by giving 'configure' the option '--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option '--exec-prefix=PREFIX' to 'configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like '--bindir=DIR' to specify different values for particular kinds of files. Run 'configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of '${prefix}', so that specifying just '--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to 'configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the 'make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, 'make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of '${prefix}'. Any directories that were specified during 'configure', but not in terms of '${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the 'DESTDIR' variable. For example, 'make install DESTDIR=/alternate/directory' will prepend '/alternate/directory' before all installation names. The approach of 'DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of '${prefix}' at 'configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving 'configure' the option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'. Some packages pay attention to '--enable-FEATURE' options to 'configure', where FEATURE indicates an optional part of the package. They may also pay attention to '--with-PACKAGE' options, where PACKAGE is something like 'gnu-as' or 'x' (for the X Window System). The 'README' should mention any '--enable-' and '--with-' options that the package recognizes. For packages that use the X Window System, 'configure' can usually find the X include and library files automatically, but if it doesn't, you can use the 'configure' options '--x-includes=DIR' and '--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of 'make' will be. For these packages, running './configure --enable-silent-rules' sets the default to minimal output, which can be overridden with 'make V=1'; while running './configure --disable-silent-rules' sets the default to verbose, which can be overridden with 'make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX 'make' updates targets which have the same timestamps as their prerequisites, which makes it generally unusable when shipped generated files such as 'configure' are involved. Use GNU 'make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its '' header file. The option '-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put '/usr/ucb' early in your 'PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in '/usr/bin'. So, if you need '/usr/ucb' in your 'PATH', put it _after_ '/usr/bin'. On Haiku, software installed for all users goes in '/boot/common', not '/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features 'configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, 'configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the '--build=TYPE' option. TYPE can either be a short name for the system type, such as 'sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file 'config.sub' for the possible values of each field. If 'config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option '--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with '--host=TYPE'. Sharing Defaults ================ If you want to set default values for 'configure' scripts to share, you can create a site shell script called 'config.site' that gives default values for variables like 'CC', 'cache_file', and 'prefix'. 'configure' looks for 'PREFIX/share/config.site' if it exists, then 'PREFIX/etc/config.site' if it exists. Or, you can set the 'CONFIG_SITE' environment variable to the location of the site script. A warning: not all 'configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to 'configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the 'configure' command line, using 'VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified 'gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash 'configure' Invocation ====================== 'configure' recognizes the following options to control how it operates. '--help' '-h' Print a summary of all of the options to 'configure', and exit. '--help=short' '--help=recursive' Print a summary of the options unique to this package's 'configure', and exit. The 'short' variant lists options used only in the top level, while the 'recursive' variant lists options also present in any nested packages. '--version' '-V' Print the version of Autoconf used to generate the 'configure' script, and exit. '--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally 'config.cache'. FILE defaults to '/dev/null' to disable caching. '--config-cache' '-C' Alias for '--cache-file=config.cache'. '--quiet' '--silent' '-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to '/dev/null' (any error messages will still be shown). '--srcdir=DIR' Look for the package's source code in directory DIR. Usually 'configure' can determine that directory automatically. '--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. '--no-create' '-n' Run the configure checks, but stop before creating any output files. 'configure' also accepts some other, not widely useful, options. Run 'configure --help' for more details. srcpd-2.1.7/srcpd.spec0000644000175000017500000000651712300502067011550 00000000000000Summary: SRCP server daemon to control digital model railroads Summary(de): SRCP-Server zur Steuerung von digitalen Modelleisenbahnen Name: srcpd Version: 2.1.2 Release: 1%{?dist} Source0: %{name}-%{version}.tar.bz2 License: GPL-2 Group: Games/Daemon Vendor: the srcpd team URL: http://srcpd.sourceforge.net/ Prefix: /usr Buildroot: %{_tmppath}/%{name}-%{version}-buildroot # if you use the LSB compliant init.d script, add "insserv" here: Requires: libxml2 BuildRequires: libxml2-devel %if 0%{?suse_version} %if %suse_version >= 1100 BuildRequires: i2c-tools %endif %endif %description The srcpd is a server daemon that enables you to control and play with a digital model railroad using any SRCP client. Currently it supports many interface (both self made and commercally) and direct signal generation. More information about SRCP and links to many really cool clients (and other servers for different hardware) can be found at http://srcpd.sourceforge.net/ and http://www.der-moba.de/ %prep %setup -q %build CFLAGS=$RPM_OPT_FLAGS \ ./configure --prefix=%{_prefix} \ --mandir=%{_mandir} \ --sysconfdir=%{_sysconfdir} make %install [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT install -d $RPM_BUILD_ROOT%{_sysconfdir}/init.d make DESTDIR=$RPM_BUILD_ROOT install # to use the LSB compliant init.d script change "init.d.suse" to # "init.d.lsb": install -m 744 init.d.suse $RPM_BUILD_ROOT%{_sysconfdir}/init.d/%{name} ln -s %{_sysconfdir}/init.d/%{name} $RPM_BUILD_ROOT%{_sbindir}/rcsrcpd %clean [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf $RPM_BUILD_ROOT %post # Initialize runlevel links if [ -x /usr/lib/lsb/install_initd ] ; then /usr/lib/lsb/install_initd %{_sysconfdir}/init.d/%{name} fi %preun # stop running server daemon and remove runlevel links %{_sysconfdir}/init.d/%{name} stop if [ -x /usr/lib/lsb/install_initd ] ; then /usr/lib/lsb/remove_initd %{_sysconfdir}/init.d/%{name} fi %files %defattr(-,root,root) %{_sbindir}/%{name} %{_sbindir}/rcsrcpd %{_sysconfdir}/init.d/%{name} %{_sysconfdir}/udev/rules.d/* %config(noreplace) %{_sysconfdir}/%{name}.conf %docdir %{_mandir}/* %{_mandir}/man8/* %{_mandir}/de/man8/* %{_mandir}/man5/* %{_mandir}/de/man5/* %doc COPYING AUTHORS README NEWS DESIGN PROGRAMMING-HOWTO %doc README.freebsd README.selectrix README.loconet TODO %changelog * Wed Mar 03 2010 Guido Scholz 2.1.1-1 - Update to version 2.1.1 * Sat Dec 19 2009 Guido Scholz 2.1.0-1 - Update to version 2.1.0 * Wed Jan 21 2009 Guido Scholz 2.0.13-1 - Update to version 2.0.13 * Sat Dec 29 2007 Guido Scholz - update to version 2.0.11 - man page (man5) added - translated man pages added - udev rules file added * Sat Dec 09 2006 Guido Scholz - update to version 2.0.10 * Sun Dec 11 2005 Guido Scholz - dist tag added, hard coded packager removed * Mon Jul 11 2005 Guido Scholz - More documentation files added * Mon Nov 01 2004 Guido Scholz - Changed sysconfdir patch * Mon Oct 18 2004 Guido Scholz - Update to srcpd-2.0-6 * Thu Jan 08 2004 Guido Scholz - adaptation to SuSE 9.0 srcpd-2.1.7/depcomp0000755000175000017500000005602014370170730011137 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2021 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: srcpd-2.1.7/Makefile.in0000664000175000017500000006751414615104457011650 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Makefile.am for srcpd # version: $Revision: 1773 $ # last update: $Date: 2023-03-06 15:53:47 +0100 (Mo, 06. Mär 2023) $ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(dist_sysconf_DATA) $(dist_udev_DATA) \ $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/src/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(sysconfdir)" "$(DESTDIR)$(udevdir)" DATA = $(dist_sysconf_DATA) $(dist_udev_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir distdir-am dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in AUTHORS COPYING ChangeLog \ INSTALL NEWS README TODO compile config.guess config.sub \ depcomp install-sh missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2 $(distdir).tar.xz \ $(distdir).zip GZIP_ENV = --best DIST_TARGETS = dist-xz dist-bzip2 dist-gzip dist-zip # Exists only to be overridden by the user if desired. AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ XML2_CONFIG = @XML2_CONFIG@ XML_CPPFLAGS = @XML_CPPFLAGS@ XML_LIBS = @XML_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = src man EXTRA_DIST = AUTHORS COPYING TODO NEWS ChangeLog INSTALL DESIGN \ README README.freebsd README.loconet README.selectrix \ PROGRAMMING-HOWTO srcpd.lsm srcpd.spec srcpd.redhat.spec \ init.d.suse init.d.redhat init.d.lsb srcpd.service dist_sysconf_DATA = srcpd.conf udevdir = $(sysconfdir)/udev/rules.d dist_udev_DATA = 10-liusb.rules all: all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): install-dist_sysconfDATA: $(dist_sysconf_DATA) @$(NORMAL_INSTALL) @list='$(dist_sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sysconfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sysconfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(sysconfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(sysconfdir)" || exit $$?; \ done uninstall-dist_sysconfDATA: @$(NORMAL_UNINSTALL) @list='$(dist_sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(sysconfdir)'; $(am__uninstall_files_from_dir) install-dist_udevDATA: $(dist_udev_DATA) @$(NORMAL_INSTALL) @list='$(dist_udev_DATA)'; test -n "$(udevdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(udevdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(udevdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(udevdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(udevdir)" || exit $$?; \ done uninstall-dist_udevDATA: @$(NORMAL_UNINSTALL) @list='$(dist_udev_DATA)'; test -n "$(udevdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(udevdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-zstd: distdir tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ *.tar.zst*) \ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(DATA) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(sysconfdir)" "$(DESTDIR)$(udevdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dist_udevDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-dist_sysconfDATA install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-dist_sysconfDATA uninstall-dist_udevDATA .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ dist-zstd distcheck distclean distclean-generic distclean-tags \ distcleancheck distdir distuninstallcheck dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dist_sysconfDATA install-dist_udevDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-dist_sysconfDATA uninstall-dist_udevDATA .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: srcpd-2.1.7/init.d.redhat0000755000175000017500000000262310722223350012135 00000000000000#!/bin/bash # init file for srcpd # # Author: Guido Scholz # # chkconfig: - 50 50 # description: Simple Railroad Command Protocol (SRCP) Daemon # # processname: /usr/sbin/srcpd # config: /etc/srcpd.conf # pidfile: /var/run/srcpd.pid # source function library . /etc/init.d/functions OPTIONS="" RETVAL=0 prog="srcpd" start() { echo -n $"Starting $prog: " if [ $UID -ne 0 ]; then RETVAL=1 failure else daemon /usr/sbin/srcpd $OPTIONS RETVAL=$? [ $RETVAL -eq 0 ] && touch /var/lock/subsys/srcpd fi; echo return $RETVAL } stop() { echo -n $"Stopping $prog: " if [ $UID -ne 0 ]; then RETVAL=1 failure else killproc /usr/sbin/srcpd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/srcpd fi; echo return $RETVAL } reload(){ echo -n $"Reloading $prog: " killproc /usr/sbin/srcpd -HUP RETVAL=$? echo return $RETVAL } restart(){ stop start } case "$1" in start) start ;; stop) stop ;; restart) restart ;; reload) reload ;; status) status srcpd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|status|restart|reload}" RETVAL=1 esac exit $RETVAL srcpd-2.1.7/COPYING0000644000175000017500000003543410722223350010615 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS srcpd-2.1.7/config.guess0000755000175000017500000014051214370170730012102 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2022-01-09' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # Just in case it came from the environment. GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039,SC3028 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && command -v ldd >/dev/null && ldd --version 2>&1 | grep -q ^musl; then LIBC=musl fi # If the system lacks a compiler, then just pick glibc. # We could probably try harder. if [ "$LIBC" = unknown ]; then LIBC=gnu fi ;; esac # Note: order is significant - the case branches are not exclusive. case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case $UNAME_VERSION in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE ;; *:SecBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) GUESS=mips-dec-osf1 ;; alpha:OSF1:*:*) # Reset EXIT trap before exiting to avoid spurious non-zero exit code. trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` GUESS=$UNAME_MACHINE-dec-osf$OSF_REL ;; Amiga*:UNIX_System_V:4.0:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) GUESS=hppa1.1-hitachi-hiuxmpp ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) GUESS=i386-pc-auroraux$UNAME_RELEASE ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$SUN_ARCH-pc-solaris2$SUN_REL ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; sun4*:SunOS:*:*) case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case `/bin/arch` in sun3) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) GUESS=sparc-auspex-sunos$UNAME_RELEASE ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` GUESS=mips-sgi-irix$IRIX_REL ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if test "$HP_ARCH" = hppa2.0w then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` GUESS=ia64-hp-hpux$HPUX_REV ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=ymp-cray-unicos$CRAY_REL ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=craynv-cray-unicosmp$CRAY_REL ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL ;; *:GNU/*:*:*) # other systems with GNU libc and userland GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) GUESS=hppa64-unknown-linux-$LIBC ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_X32 >/dev/null then LIBCABI=${LIBC}x32 fi fi GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. GUESS=i386-sequent-sysv4 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) GUESS=$UNAME_MACHINE-pc-msdosdjgpp ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) GUESS=m68k-diab-dnix ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; x86_64:Haiku:*:*) GUESS=x86_64-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "${cputype-}" = 386; then UNAME_MACHINE=i386 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case $UNAME_MACHINE in A*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; esac # Do we have a guess based on uname results? if test "x$GUESS" != x; then echo "$GUESS" exit fi # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: srcpd-2.1.7/TODO0000644000175000017500000000024311107102064010234 00000000000000Bugs to fix ----------- Features to implement --------------------- * SRCP server reset * Event driven code for all modules using serial device communication srcpd-2.1.7/aclocal.m40000664000175000017500000012254514615104456011436 00000000000000# generated automatically by aclocal 1.16.5 -*- Autoconf -*- # Copyright (C) 1996-2021 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],, [m4_warning([this file was generated for autoconf 2.71. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # Copyright (C) 2002-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.16.5], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.16.5])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE="gmake" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking is enabled. # This creates each '.Po' and '.Plo' makefile fragment that we'll need in # order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl m4_ifdef([_$0_ALREADY_INIT], [m4_fatal([$0 expanded multiple times ]m4_defn([_$0_ALREADY_INIT]))], [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi AC_SUBST([CTAGS]) if test -z "$ETAGS"; then ETAGS=etags fi AC_SUBST([ETAGS]) if test -z "$CSCOPE"; then CSCOPE=cscope fi AC_SUBST([CSCOPE]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2021 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([acinclude.m4]) srcpd-2.1.7/README.freebsd0000644000175000017500000000441510722223350012046 00000000000000In diesem Dokument werde ich die Unterschiede der FreeBSD Portierung beschreiben. Da die einzelnen Module teilweise spezielle Kerneltreiber von Linux vorraussetzen, ist eine komplette Uebertragung nicht immer moeglich. Falls Aenderungen zum "Original" autauchen, werden sie bei den jeweiligen Modulen erwaehnt. MAM ------------------------------------------------------------------------- Hauptprogramm: Einige Headerdateien heissen anders, bzw. wurden hinzugefuegt. Im Makefile wird -lpthread automatisch ersetzt durch -pthread in io.c wird bei writeByte vor dem Schreiben ueberprueft, ob CTS anliegt. Wenn nicht, wir der Thread in den Schlafzustand versetzt, und nach einer Sekunde ein neuer Versuch unternommen. Ohne die Aenderung blockierten ALLE Threads. ------------------------------------------------------------------------- Intellibox Der Linux Device Treiber wird nicht benoetigt Das BREAK fuer die Baudratenumschaltung wird ueber den normalen Treiber gemacht. Ungetestet mangels Hardware ------------------------------------------------------------------------- M605x Andere Initialisierung der seriellen Schnittstelle ------------------------------------------------------------------------- DDL-S88 Die Linux Funktionen ioperm, inb und outb werden ueber das Device /dev/ppi[0|1|2] emuliert. In der Konfigurationsdatei wird allerdings nur der Eintrag mit der Portadresse ausgewertet, der Devicename wird automatisch generiert. Da das Schreiben/Lesen ueber ioctl Aufrufe simuliert wird, ist es gegenueber dem Original deutlich langsamer. Der Konfigurationsparameter "clockscale" wurde deshalb von 35 auf 2 Wiederholungen reduziert. Wenn das zu schnell fuer die Hardware sein sollte, bitte experimentell hochsetzen und mir Bescheid geben. Bei meinem 2*400Mhz Referenzrechner komme ich damit auf ein Auslesefrequenz von ca 40khz. ------------------------------------------------------------------------- I2C Bus NICHT FUNKTIONSFAEHIG Vor der Portierung soll das Modul erst einmal stabil unter Linux laufen. ------------------------------------------------------------------------- HSI-88 Keine Aenderung noetig gewesen. Ob's allerdings funktioniert, kann ich nicht ausprobieren. ------------------------------------------------------------------------- srcpd-2.1.7/install-sh0000755000175000017500000003577614370170730011605 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Email bug reports to bug-automake@gnu.org. Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: srcpd-2.1.7/srcpd.redhat.spec0000644000175000017500000000643712300502067013017 00000000000000Summary: srcpd is a SRCP server daemon to control digital model railroads Summary(de): srcpd ist ein SRCP-Server zur Steuerung von digitalen Modelleisenbahnen Name: srcpd Version: 2.1.2 Release: 1%{?dist} Source0: %{name}-%{version}.tar.bz2 License: GPL-2 Group: Games/Daemon Vendor: the srcpd team URL: http://srcpd.sourceforge.net/ Prefix: /usr Buildroot: %{_tmppath}/%{name}-%{version}-buildroot Provides: srcpd # if you use the LSB compliant init.d script, add "redhat-lsb" here: Requires: libxml2 BuildRequires: libxml2-devel %description The srcpd is a server daemon that enables you to control and play with a digital model railroad using any SRCP client. Currently it supports many interface (both self made and commercally) and direct signal generation. More information about SRCP and links to many really cool clients (and other servers for different hardware) can be found at http://srcpd.sourceforge.net/ and http://www.der-moba.de/ %prep %setup -q %build CFLAGS=$RPM_OPT_FLAGS \ ./configure --prefix=%{_prefix} \ --mandir=%{_mandir} \ --sysconfdir=%{_sysconfdir} make %install [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf $RPM_BUILD_ROOT install -d $RPM_BUILD_ROOT%{_sysconfdir}/init.d make DESTDIR=$RPM_BUILD_ROOT install # to use the LSB compliant init.d script change "init.d.redhat" to # "init.d.lsb": install -m 755 init.d.redhat $RPM_BUILD_ROOT%{_sysconfdir}/init.d/%{name} %clean [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf $RPM_BUILD_ROOT %post # Initialize runlevel links if [ -x /usr/lib/lsb/install_initd ] ; then /usr/lib/lsb/install_initd %{_sysconfdir}/init.d/%{name} fi %preun # stop running server daemon and remove runlevel links %{_sysconfdir}/init.d/%{name} stop if [ -x /usr/lib/lsb/install_initd ] ; then /usr/lib/lsb/remove_initd %{_sysconfdir}/init.d/%{name} fi %files %defattr(-,root,root) %{_sbindir}/%{name} %{_sysconfdir}/init.d/%{name} %{_sysconfdir}/udev/rules.d/* %docdir %{_mandir}/* %{_mandir}/man8/* %{_mandir}/de/man8/* %{_mandir}/man5/* %{_mandir}/de/man5/* %config(noreplace) %{_sysconfdir}/%{name}.conf %doc COPYING AUTHORS README NEWS DESIGN PROGRAMMING-HOWTO %doc README.freebsd README.selectrix README.loconet TODO %changelog * Wed Mar 03 2010 Guido Scholz 2.1.1-1 - Update to version 2.1.1 * Sat Dec 19 2009 Guido Scholz 2.1.0-1 - Update to version 2.1.0 * Wed Jan 21 2009 Guido Scholz 2.0.13-1 - Update to version 2.0.13 * Sat Dec 29 2007 Guido Scholz 2.0.11-1 - update to version 2.0.11 - man page (man5) added - translated man pages added - udev rules file added * Sat Dec 09 2006 Guido Scholz - update to version 2.0.10 * Mon Dec 26 2005 Guido Scholz - adaptation to redhat/fedora style * Sun Dec 11 2005 Guido Scholz - dist tag added, hard coded packager removed * Mon Jul 11 2005 Guido Scholz - More documentation files added * Mon Nov 01 2004 Guido Scholz - Changed sysconfdir patch * Mon Oct 18 2004 Guido Scholz - Update to srcpd-2.0-6 * Thu Jan 08 2004 Guido Scholz - adaptation to SuSE 9.0 srcpd-2.1.7/README.loconet0000644000175000017500000000440711242320130012070 00000000000000Author: Matthias Trute Date: Summer 2009 Version: srcpd 2.0.13+ Purpose: This document discusses the relationship between Loconet (R) and the srcpd / SRCP. The srcpd acts basically as a two-way gateway between the loconet bus and the SRCP world. It translates the loconet messages into SRCP events and emits loconet commands and queries to execute SRCP commands. The srcpd is not a loconet master, it acts as a loconet device via a locobuffer or similiar hardware gateways. 1. basic device support Generic Loco GL Loconet uses the NMRA DCC to communicate with the decoders. Since there are devices that operate with other rail signal types as well, the srcpd supports not only the procotol N but M and P too. The reserved protocol identifier L is used as well. The srcpd simply does not care. The loconet stores information about the mobile decoders in a fixed size list called slots. Every slot contains exactly 1 decoder address and may be consisted with another slot. The slot number is used by loconet messages to communicate with the decoder. The srcpd hides the existence of slots completly. In SRCP only the decoder addresses are used. Which slot is used, is maintained by the loconet master. The srcpd builds and maintaines a local copy. There is no way to get the slot number. Since SRCP does not have a consists model, consisting slots are neither used nor decoded. Upon startup the srcpd reads all slots. That may trigger some traffic however. Dispatching and LOCKs are currently not available. The following loconet message types are used (both direction) OPC_LOCO_SPD (0xA0) OPC_LOCO_DIRF (0xA1) OPC_LOCO_SND (0xA2) OPC_SLOT_STAT1 (0xB5) with status 2 a SRCP TERM message is generated Generic Accessoires GA They work with their decoder addresses. The switch request message OPC_SW_REQ is used. The OPC_SW_REP is currently not implemented. Feedback Sensors FB Sensor messages from the loconet are decoded. Sending those events _to_ the loconet is currently not implemented. The OPC_INPUT_REP is used. Service Mode SM not available Fast clock TIME The srcpd can be configured to synchronize the TIME device with a loconet master clock. Both the acceleration ratio and the day/hour/minute are used. The way back from the SRCP TIME to the loconet is not yet implemented. srcpd-2.1.7/src/0000775000175000017500000000000014615104512010425 500000000000000srcpd-2.1.7/src/m605x.c0000664000175000017500000004037414564575735011426 00000000000000/* cvs: $Id: m605x.c 1788 2024-02-19 06:57:33Z gscholz $ */ #include #include #include #include #include #ifdef __CYGWIN__ #include /*for FIONREAD */ #endif #ifdef __sun__ #include #endif #include "config-srcpd.h" #include "io.h" #include "m605x.h" #include "srcp-fb.h" #include "srcp-ga.h" #include "srcp-gl.h" #include "srcp-power.h" #include "srcp-info.h" #include "srcp-server.h" #include "srcp-error.h" #include "syslogmessage.h" #include "ttycygwin.h" #define __m6051 ((M6051_DATA*)buses[busnumber].driverdata) /** * readconfig_m605x: Liest den Teilbaum der xml Configuration und * parametriert den busspezifischen Datenteil, wird von register_bus() * aufgerufen. **/ int readconfig_m605x(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber) { buses[busnumber].driverdata = malloc(sizeof(struct _M6051_DATA)); if (buses[busnumber].driverdata == NULL) { syslog_bus(busnumber, DBG_ERROR, "Memory allocation error in module '%s'.", node->name); return 0; } buses[busnumber].type = SERVER_M605X; buses[busnumber].init_func = &init_bus_M6051; buses[busnumber].thr_func = &thr_sendrec_M6051; buses[busnumber].init_gl_func = &init_gl_M6051; buses[busnumber].init_ga_func = &init_ga_M6051; buses[busnumber].flags |= FB_16_PORTS; __m6051->number_fb = 0; /* max 31 */ __m6051->number_ga = 256; __m6051->number_gl = 80; __m6051->ga_min_active_time = 75; __m6051->pause_between_cmd = 200; __m6051->pause_between_bytes = 2; strcpy(buses[busnumber].description, "GA GL FB POWER LOCK DESCRIPTION"); xmlNodePtr child = node->children; xmlChar *txt = NULL; while (child != NULL) { if ((xmlStrncmp(child->name, BAD_CAST "text", 4) == 0) || (xmlStrncmp(child->name, BAD_CAST "comment", 7) == 0)) { /* just do nothing, it is only formatting text or a comment */ } else if (xmlStrcmp(child->name, BAD_CAST "number_fb") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __m6051->number_fb = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "number_gl") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __m6051->number_gl = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "number_ga") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __m6051->number_ga = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "mode_m6020") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { if (xmlStrcmp(txt, BAD_CAST "yes") == 0) __m6051->flags |= M6020_MODE; xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "fb_delay_time_0") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { set_min_time(busnumber, atoi((char *) txt)); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "ga_min_activetime") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __m6051->ga_min_active_time = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "pause_between_commands") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __m6051->pause_between_cmd = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "pause_between_bytes") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __m6051->pause_between_bytes = atoi((char *) txt); xmlFree(txt); } } else syslog_bus(busnumber, DBG_WARN, "WARNING, unknown tag found: \"%s\"!\n", child->name);; child = child->next; } if (init_GA(busnumber, __m6051->number_ga)) { __m6051->number_ga = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array for accessories"); } if (init_GL(busnumber, __m6051->number_gl)) { __m6051->number_gl = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array for locomotives"); } if (init_FB(busnumber, __m6051->number_fb * 16)) { __m6051->number_fb = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array for feedback"); } return 1; } /******************************************************* * configure serial line *******************************************************/ static int init_lineM6051(bus_t bus) { int fd; struct termios interface; if (buses[bus].debuglevel > 0) { syslog_bus(bus, DBG_INFO, "Opening 605x: %s", buses[bus].device.file.path); } fd = open(buses[bus].device.file.path, O_RDWR | O_NONBLOCK); if (fd == -1) { syslog_bus(bus, DBG_ERROR, "Open serial device '%s' failed: %s " "(errno = %d).\n", buses[bus].device.file.path, strerror(errno), errno); return -1; } tcgetattr(fd, &interface); #ifdef linux interface.c_cflag = CS8 | CRTSCTS | CREAD | CSTOPB; interface.c_oflag = ONOCR | ONLRET; interface.c_oflag &= ~(OLCUC | ONLCR | OCRNL); interface.c_iflag = IGNBRK | IGNPAR; interface.c_iflag &= ~(ISTRIP | IXON | IXOFF | IXANY); interface.c_lflag = NOFLSH | IEXTEN; interface.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | TOSTOP | PENDIN); #else cfmakeraw(&interface); interface.c_cflag = CREAD | HUPCL | CS8 | CSTOPB | CRTSCTS; #endif cfsetospeed(&interface, B2400); cfsetispeed(&interface, B2400); tcsetattr(fd, TCSANOW, &interface); syslog_bus(bus, DBG_INFO, "Opening 605x succeeded (fd = %d).", fd); return fd; } int init_bus_M6051(bus_t bus) { static char *protocols = "MP"; buses[bus].protocols = protocols; syslog_bus(bus, DBG_INFO, "M605x init: debug %d", buses[bus].debuglevel); if (buses[bus].debuglevel <= DBG_DEBUG) { buses[bus].device.file.fd = init_lineM6051(bus); } else { buses[bus].device.file.fd = -1; } syslog_bus(bus, DBG_INFO, "M605x init done, fd=%d", buses[bus].device.file.fd); syslog_bus(bus, DBG_INFO, "M605x: %s", buses[bus].description); syslog_bus(bus, DBG_INFO, "M605x flags: %d", buses[bus].flags & AUTO_POWER_ON); return 0; } /** * cacheInitGL: modifies the gl data used to initialize the device **/ int init_gl_M6051(gl_data_t *gl) { if (gl->protocol != 'M') return SRCP_UNSUPPORTEDDEVICEPROTOCOL; switch (gl->protocolversion) { case 1: return (gl->n_fs == 14) ? SRCP_OK : SRCP_WRONGVALUE; break; case 2: return ((gl->n_fs == 14) || (gl->n_fs == 27) || (gl->n_fs == 28)) ? SRCP_OK : SRCP_WRONGVALUE; break; } return SRCP_WRONGVALUE; } /** * initGA: modifies the ga data used to initialize the device **/ int init_ga_M6051(ga_data_t *ga) { if ((ga->protocol == 'M') || (ga->protocol == 'P')) return SRCP_OK; return SRCP_UNSUPPORTEDDEVICEPROTOCOL; } /*thread cleanup routine for this bus*/ static void end_bus_thread(bus_thread_t * btd) { int result; syslog_bus(btd->bus, DBG_INFO, "M605x bus terminated."); if (buses[btd->bus].device.file.fd != -1) close(buses[btd->bus].device.file.fd); result = pthread_mutex_destroy(&buses[btd->bus].transmit_mutex); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_destroy() failed: %s (errno = %d).", strerror(result), result); } result = pthread_cond_destroy(&buses[btd->bus].transmit_cond); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_init() failed: %s (errno = %d).", strerror(result), result); } free(buses[btd->bus].driverdata); free(btd); } void *thr_sendrec_M6051(void *v) { unsigned char SendByte; int akt_S88, addr, temp, number_fb; int result; char c; unsigned char rr; gl_data_t gltmp, glakt; ga_data_t gatmp; int last_cancel_state, last_cancel_type; bus_thread_t *btd = (bus_thread_t *) malloc(sizeof(bus_thread_t)); if (btd == NULL) pthread_exit((void *) 1); btd->bus = (bus_t) v; btd->fd = -1; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_cancel_state); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_cancel_type); /*register cleanup routine */ pthread_cleanup_push((void *) end_bus_thread, (void *) btd); syslog_bus(btd->bus, DBG_INFO, "M605x bus started (device = %s).", buses[btd->bus].device.file.path); int ga_min_active_time = ((M6051_DATA *) buses[btd->bus].driverdata)->ga_min_active_time; int pause_between_cmd = ((M6051_DATA *) buses[btd->bus].driverdata)->pause_between_cmd; int pause_between_bytes = ((M6051_DATA *) buses[btd->bus].driverdata)->pause_between_bytes; number_fb = ((M6051_DATA *) buses[btd->bus].driverdata)->number_fb; akt_S88 = 1; buses[btd->bus].watchdog = 1; result = ioctl(buses[btd->bus].device.file.fd, FIONREAD, &temp); if (result == -1) { syslog_bus(btd->bus, DBG_ERROR, "ioctl() failed: %s (errno = %d)\n", strerror(errno), errno); } if (((M6051_DATA *) buses[btd->bus].driverdata)->cmd32_pending) { SendByte = 32; writeByte(btd->bus, SendByte, pause_between_cmd); ((M6051_DATA *) buses[btd->bus].driverdata)->cmd32_pending = 0; } while (temp > 0) { readByte(btd->bus, 0, &rr); result = ioctl(buses[btd->bus].device.file.fd, FIONREAD, &temp); if (result == -1) { syslog_bus(btd->bus, DBG_ERROR, "ioctl() failed: %s (errno = %d)\n", strerror(errno), errno); } syslog_bus(btd->bus, DBG_INFO, "Emptying device buffer. Ignoring unread byte: %d ", rr); } while (true) { pthread_testcancel(); buses[btd->bus].watchdog = 2; /* Start/Stop */ if (buses[btd->bus].power_changed == 1) { char msg[1000]; SendByte = (buses[btd->bus].power_state) ? 96 : 97; /* zweimal, wir sind paranoid */ writeByte(btd->bus, SendByte, pause_between_cmd); writeByte(btd->bus, SendByte, pause_between_cmd); buses[btd->bus].power_changed = 0; infoPower(btd->bus, msg); enqueueInfoMessage(msg); } /* do nothing, if power off */ if (buses[btd->bus].power_state == 0) { if (usleep(1000) == -1) { syslog_bus(btd->bus, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } continue; } buses[btd->bus].watchdog = 3; /* locomotive decoder */ if (!((M6051_DATA *) buses[btd->bus].driverdata)->cmd32_pending) { if (!queue_GL_isempty(btd->bus)) { dequeueNextGL(btd->bus, &gltmp); addr = gltmp.id; cacheGetGL(btd->bus, addr, &glakt); if (gltmp.direction == 2) { gltmp.speed = 0; gltmp.direction = !glakt.direction; } /* forward/backward */ if (gltmp.direction != glakt.direction) { c = 15 + 16 * ((gltmp.funcs & 0x10) ? 1 : 0); writeByte(btd->bus, c, pause_between_bytes); SendByte = addr; writeByte(btd->bus, SendByte, pause_between_cmd); } /* Geschwindigkeit und Licht setzen, erst recht nach Richtungswechsel */ c = gltmp.speed + 16 * ((gltmp.funcs & 0x01) ? 1 : 0); /* jetzt aufpassen: n_fs erzwingt ggf. mehrfache Ansteuerungen des Dekoders, das Protokoll ist da wirklich eigenwillig, vorerst ignoriert! */ writeByte(btd->bus, c, pause_between_bytes); SendByte = addr; writeByte(btd->bus, SendByte, pause_between_cmd); /* Erweiterte Funktionen des 6021 senden, manchmal */ if (!((((M6051_DATA *) buses[btd->bus].driverdata)-> flags & M6020_MODE) == M6020_MODE) && (gltmp.funcs != glakt.funcs)) { c = ((gltmp.funcs >> 1) & 0x0f) + 64; writeByte(btd->bus, c, pause_between_bytes); SendByte = addr; writeByte(btd->bus, SendByte, pause_between_cmd); } cacheSetGL(btd->bus, addr, gltmp); } buses[btd->bus].watchdog = 4; } buses[btd->bus].watchdog = 5; /* Magnetantriebe, die muessen irgendwann sehr bald abgeschaltet werden */ if (!queue_GA_isempty(btd->bus)) { dequeueNextGA(btd->bus, &gatmp); addr = gatmp.id; if (gatmp.action == 1) { gettimeofday(&gatmp.tv[gatmp.port], NULL); setGA(btd->bus, addr, gatmp); if (gatmp.activetime >= 0) { gatmp.activetime = (gatmp.activetime > ga_min_active_time) ? ga_min_active_time : gatmp.activetime; /* next action is auto switch off */ gatmp.action = 0; } else { /* egal wieviel, mind. 75m ein */ gatmp.activetime = ga_min_active_time; } c = 33 + (gatmp.port ? 0 : 1); SendByte = gatmp.id; writeByte(btd->bus, c, pause_between_bytes); writeByte(btd->bus, SendByte, pause_between_bytes); if (usleep((unsigned long) gatmp.activetime * 1000) == -1) { syslog_bus(btd->bus, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } ((M6051_DATA *) buses[btd->bus].driverdata)-> cmd32_pending = 1; } if ((gatmp.action == 0) && ((M6051_DATA *) buses[btd->bus].driverdata)-> cmd32_pending) { SendByte = 32; writeByte(btd->bus, SendByte, pause_between_cmd); ((M6051_DATA *) buses[btd->bus].driverdata)-> cmd32_pending = 0; setGA(btd->bus, addr, gatmp); } buses[btd->bus].watchdog = 6; } buses[btd->bus].watchdog = 7; /* read every single S88 state */ if ((number_fb > 0) && !((M6051_DATA *) buses[btd->bus].driverdata)->cmd32_pending) { SendByte = 192 + akt_S88; writeByte(btd->bus, SendByte, pause_between_cmd); buses[btd->bus].watchdog = 8; readByte(btd->bus, 0, &rr); temp = rr; temp <<= 8; buses[btd->bus].watchdog = 9; readByte(btd->bus, 0, &rr); setFBmodul(btd->bus, akt_S88, temp | rr); akt_S88++; if (akt_S88 > number_fb) akt_S88 = 1; } buses[btd->bus].watchdog = 10; check_reset_fb(btd->bus); /* fprintf(stderr, " ende\n"); */ } /*run the cleanup routine */ pthread_cleanup_pop(1); return NULL; } srcpd-2.1.7/src/zimo.h0000644000175000017500000000063510731165204011476 00000000000000/* $Id: zimo.h 983 2007-12-16 09:06:42Z gscholz $ */ #ifndef _ZIMO_H #define _ZIMO_H #include /*xmlDocPtr, xmlNodePtr*/ typedef struct _zimo_DATA { int number_ga; int number_gl; int number_fb; } zimo_DATA; int readconfig_ZIMO(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber); int init_bus_ZIMO(bus_t); int getDescription_ZIMO(char *reply); void* thr_sendrec_ZIMO(void *); #endif srcpd-2.1.7/src/netservice.c0000644000175000017500000002303614564575735012710 00000000000000/* cvs: $Id: netservice.c 1788 2024-02-19 06:57:33Z gscholz $ */ /* * Vorliegende Software unterliegt der General Public License, * Version 2, 1991. (c) Matthias Trute, 2000-2001. * */ #include #include #include #include #include #include #include #include #include "netservice.h" #include "clientservice.h" #include "srcp-server.h" #include "syslogmessage.h" typedef struct _THREADS { unsigned short int port; int socket; } net_thread_t; static pthread_t netservice_tid; void change_privileges() { struct group *group; struct passwd *passwd; char *grp = ((SERVER_DATA *) buses[0].driverdata)->groupname; char *uid = ((SERVER_DATA *) buses[0].driverdata)->username; if (grp != NULL) { if ((group = getgrnam(grp)) != NULL || (group = getgrgid((gid_t) atoi(grp))) != NULL) { if (setegid(group->gr_gid) != 0) { syslog_bus(0, DBG_WARN, "Could not change to group %s: %s", group->gr_name, strerror(errno)); } else { syslog_bus(0, DBG_INFO, "Changed to group %s", group->gr_name); } } else { syslog_bus(0, DBG_WARN, "Could not change to group %s", grp); } } if (uid != NULL) { if ((passwd = getpwnam(uid)) != NULL || (passwd = getpwuid((uid_t) atoi(uid))) != NULL) { if (seteuid(passwd->pw_uid) != 0) { syslog_bus(0, DBG_INFO, "Could not change to user %s: %s", passwd->pw_name, strerror(errno)); } else { syslog_bus(0, DBG_INFO, "Changed to user %s", passwd->pw_name); } } else { syslog_bus(0, DBG_INFO, "Could not change to user %s", uid); } } } /*runtime check for ipv6 support */ int ipv6_supported() { #ifdef ENABLE_IPV6 int s = socket(AF_INET6, SOCK_STREAM, 0); if (s != -1) { close(s); return 1; } #endif return 0; } /*cleanup routine for network syn request thread*/ void end_netrequest_thread(net_thread_t * ntd) { if (ntd->socket != -1) { close(ntd->socket); } free(ntd); free(buses[0].driverdata); } /*handle incoming network syn requests*/ void *thr_handlePort(void *v) { int last_cancel_state, last_cancel_type; pthread_t ttid; int result; net_thread_t *ntd = (net_thread_t *) malloc(sizeof(net_thread_t)); if (ntd == NULL) pthread_exit((void *) 1); ntd->port = (unsigned long int) v; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_cancel_state); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_cancel_type); /*register cleanup routine */ pthread_cleanup_push((void *) end_netrequest_thread, (void *) ntd); #ifdef ENABLE_IPV6 struct sockaddr_in6 sin6; struct sockaddr_in6 fsin6; #endif struct sockaddr_in sin; struct sockaddr_in fsin; struct sockaddr *saddr, *fsaddr; socklen_t socklen; int sock_opt; bool has_ipv6_support = ipv6_supported(); #ifdef ENABLE_IPV6 if (has_ipv6_support) { memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(ntd->port); sin6.sin6_addr = in6addr_any; /* create a socket for listening */ ntd->socket = socket(AF_INET6, SOCK_STREAM, 0); if (ntd->socket == -1) { syslog_bus(0, DBG_ERROR, "Socket creation failed: %s (errno = %d). " "Terminating...\n", strerror(errno), errno); exit(EXIT_FAILURE); } saddr = (struct sockaddr *) &sin6; fsaddr = (struct sockaddr *) &fsin6; socklen = sizeof(sin6); } else #endif { /* Here would be the original IPv4 code as usual */ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; /* IPv4 address family */ sin.sin_port = htons(ntd->port); sin.sin_addr.s_addr = INADDR_ANY; /* Create the socket */ ntd->socket = socket(AF_INET, SOCK_STREAM, 0); if (ntd->socket == -1) { syslog_bus(0, DBG_ERROR, "Socket creation failed: %s (errno = %d). " "Terminating...\n", strerror(errno), errno); exit(EXIT_FAILURE); } saddr = (struct sockaddr *) &sin; fsaddr = (struct sockaddr *) &fsin; socklen = sizeof(sin); } if (getuid() == 0) { change_privileges(); } sock_opt = 1; if (setsockopt(ntd->socket, SOL_SOCKET, SO_REUSEADDR, &sock_opt, sizeof(sock_opt)) == -1) { syslog_bus(0, DBG_ERROR, "setsockopt() failed: %s (errno = %d). " "Terminating...\n", strerror(errno), errno); close(ntd->socket); exit(EXIT_FAILURE); } /* saddr=(sockaddr_in) if ntd.socket is of type AF_INET else its (sockaddr_in6) */ if (bind(ntd->socket, (struct sockaddr *) saddr, socklen) == -1) { syslog_bus(0, DBG_ERROR, "bind() failed: %s (errno = %d). " "Terminating...\n", strerror(errno), errno); close(ntd->socket); exit(EXIT_FAILURE); } if (listen(ntd->socket, 1) == -1) { syslog_bus(0, DBG_ERROR, "Listen failed: %s (errno = %d). " "Terminating...\n", strerror(errno), errno); close(ntd->socket); exit(EXIT_FAILURE); } /* Wait for connection requests */ for (;;) { pthread_testcancel(); int clientsocket = accept(ntd->socket, (struct sockaddr *) fsaddr, &socklen); if (clientsocket == -1) { /* Possibly the connection got aborted */ syslog_bus(0, DBG_WARN, "accept() failed: %s (errno = %d)\n", strerror(errno), errno); continue; } syslog_bus(0, DBG_INFO, "New connection received.\n"); /* Now process the connection as per the protocol */ #ifdef ENABLE_IPV6 if (has_ipv6_support) { /* This casting must work as we have taken care of the * appropriate data structures */ struct sockaddr_in6 *sin6_ptr = (struct sockaddr_in6 *) fsaddr; char addrbuf[INET6_ADDRSTRLEN]; if (IN6_IS_ADDR_V4MAPPED(&(sin6_ptr->sin6_addr))) { syslog_bus(0, DBG_INFO, "Connection from an IPv4 client\n"); } syslog_bus(0, DBG_INFO, "Connection from %s/%d\n", inet_ntop(AF_INET6, (void *) &(sin6_ptr->sin6_addr), addrbuf, sizeof(addrbuf)), ntohs(sin6_ptr->sin6_port)); } else #endif { struct sockaddr_in *sin_ptr = (struct sockaddr_in *) fsaddr; syslog_bus(0, DBG_INFO, "Connection from %s/%d\n", inet_ntoa(sin_ptr->sin_addr), ntohs(sin_ptr->sin_port)); } sock_opt = 1; if (setsockopt(clientsocket, SOL_SOCKET, SO_KEEPALIVE, &sock_opt, sizeof(sock_opt)) == -1) { syslog_bus(0, DBG_ERROR, "Setsockopt failed: %s (errno = %d)\n", strerror(errno), errno); close(clientsocket); continue; } /* create an anonymous session with a valid socket */ session_node_t *asn = create_anonymous_session(clientsocket); if (asn == NULL) { close(clientsocket); syslog_bus(0, DBG_ERROR, "Session create failed!"); continue; } /* hand over client service to "thr_doClient()" from clientservice.c */ result = pthread_create(&ttid, NULL, thr_doClient, asn); if (result != 0) { syslog_bus(0, DBG_ERROR, "Create thread for network client " "failed: %s (errno = %d). Terminating...\n", strerror(result), result); close(clientsocket); destroy_anonymous_session(asn); continue; } } /*run the cleanup routine */ pthread_cleanup_pop(1); return NULL; } /* create network connection thread */ void create_netservice_thread() { int result; unsigned short int port; port = ((SERVER_DATA *) buses[0].driverdata)->TCPPORT; /*TODO: search for other solution than doubled type cast */ result = pthread_create(&netservice_tid, NULL, thr_handlePort, (void *) (unsigned long int) port); if (result != 0) { syslog_bus(0, DBG_ERROR, "Create netservice thread failed: %s " "(errno = %d). Terminating...\n", strerror(result), result); exit(EXIT_FAILURE); } syslog_bus(0, DBG_INFO, "Netservice thread for port %d created.", port); } /* cancel network connection thread */ void cancel_netservice_thread() { int result; void *thr_result; result = pthread_cancel(netservice_tid); if (result != 0) syslog_bus(0, DBG_ERROR, "Netservice thread cancel failed: %s (errno = %d).", strerror(result), result); /*wait for termination */ result = pthread_join(netservice_tid, &thr_result); if (result != 0) syslog_bus(0, DBG_ERROR, "Netservice thread join failed: %s (errno = %d).", strerror(result), result); syslog_bus(0, DBG_INFO, "Netservice thread terminated."); } srcpd-2.1.7/src/hsi-88.h0000644000175000017500000000274112101006231011523 00000000000000/*************************************************************************** hsi-88.h - description ------------------- begin : Mon Oct 29 2001 copyright : (C) 2001 by Dipl.-Ing. Frank Schmischke email : frank.schmischke@t-online.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _HSI_88_H #define _HSI_88_H #include /*xmlDocPtr, xmlNodePtr */ typedef struct _HSI_88_DATA { int number_fb[3]; int refresh; char v_text[50]; } HSI_88_DATA; int readConfig_HSI_88(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber); int init_bus_HSI_88(bus_t busnumber); int get_bus_config_HSI_88(bus_t busnummer, int *num_gl, int *num_ga, int *num_fb); void *thr_sendrec_HSI_88(void *); #endif srcpd-2.1.7/src/selectrix.c0000664000175000017500000011512714564574764012551 00000000000000/** * This software is published under the terms of the GNU General Public * License, Version 2.0 * Gerard van der Sel * * Version 2.1: 20071006: Re-release of SLX852 and error recovery * Version 2.0: 20070418: Release of SLX852 * Version 1.4: 20070315: Communication with the SLX852 * Version 1.3: 20070213: Communication with events * Version 1.2: 20060526: Text reformatting and error checking * Version 1.1: 20060505: Configuration of fb addresses from srcpd.conf * Version 1.0: 20050601: Release of Selectrix protocol * Version 0.4: 20050521: Feedback response * Version 0.3: 20050521: Controlling a switch/signal * Version 0.2: 20050514: Controlling a engine * Version 0.1: 20050508: Connection with CC-2000 and power on/off * Version 0.0: 20050501: Translated file from file M605X which compiles */ /** * This software does the translation for a selectrix central centre * An old Central centre is the default selection * In the XML-file the control centre can be changed to the new CC-2000 * A CC-2000 can program a engine * (Control centre of MUT and Uwe Magnus are CC-2000 compatible). */ #include #include #include #include #include "portio.h" #include "config-srcpd.h" #include "srcp-power.h" #include "srcp-info.h" #include "srcp-server.h" #include "srcp-error.h" #include "srcp-sm.h" #include "srcp-gl.h" #include "srcp-ga.h" #include "srcp-fb.h" #include "selectrix.h" #include "syslogmessage.h" #include "ttycygwin.h" int syncSXbus(bus_t busnumber); void commandreadSXbus(bus_t busnumber, int SXadres); int readSXbus(bus_t busnumber); void writeSXbus(bus_t busnumber, int SXadres, int SXdata); /* Macro definition */ #define __selectrix ((SELECTRIX_DATA *)buses[busnumber].driverdata) #define __selectrixt ((SELECTRIX_DATA *)buses[btd->bus].driverdata) #define __checkSXflag(flag) ((__selectrix->SXflags & (flag)) == (flag)) /******************************************************************* * readconfig_Selectrix: * Reads selectrix specific XML nodes and sets up bus specific data. * Called by register_bus(). ********************************************************************/ int readconfig_Selectrix(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber) { int i, offset; int portindex = 0; syslog_bus(busnumber, DBG_INFO, "Reading Selectrix specific data."); buses[busnumber].driverdata = malloc(sizeof(struct _SELECTRIX_DATA)); if (buses[busnumber].driverdata == NULL) { syslog_bus(busnumber, DBG_ERROR, "Memory allocation error in module '%s'.", node->name); return 0; } /* Selectrix specific data to the global data */ buses[busnumber].type = SERVER_SELECTRIX; buses[busnumber].device.file.baudrate = B9600; buses[busnumber].init_func = &init_bus_Selectrix; buses[busnumber].thr_func = &thr_commandSelectrix; buses[busnumber].thr_timer = &thr_feedbackSelectrix; buses[busnumber].sigio_reader = &sig_processSelectrix; buses[busnumber].init_gl_func = &init_gl_Selectrix; buses[busnumber].init_ga_func = &init_ga_Selectrix; buses[busnumber].init_fb_func = &init_fb_Selectrix; /* Initialise Selectrix part */ __selectrix->number_gl = 0; __selectrix->number_ga = 0; __selectrix->number_fb = 0; __selectrix->SXflags = 0; __selectrix->stateInterface = 0; __selectrix->currentFB = 1; __selectrix->max_address = 0x100; /* SXmax; */ /* Initialise the two array's */ for (i = 0; i < SXmax; i++) { __selectrix->bus_data[i] = 0; /* Set all outputs to 0 */ __selectrix->fb_adresses[i] = 255; /* Set invalid addresses */ } strcpy(buses[busnumber].description, "GA GL FB POWER LOCK DESCRIPTION"); xmlNodePtr child = node->children; xmlChar *txt = NULL; while (child != NULL) { if ((xmlStrncmp(child->name, BAD_CAST "text", 4) == 0) || (xmlStrncmp(child->name, BAD_CAST "comment", 7) == 0)) { /* just do nothing, it is only formatting text or a comment */ } else if (xmlStrcmp(child->name, BAD_CAST "number_fb") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __selectrix->number_fb = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "number_gl") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __selectrix->number_gl = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "number_ga") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __selectrix->number_ga = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "controller") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { if (xmlStrcmp(txt, BAD_CAST "CC2000") == 0) { __selectrix->SXflags |= CC2000_MODE; /* Last 8 addresses for the CC2000 */ /* __selectrix->max_address = SXcc2000; */ strcpy(buses[busnumber].description, "GA GL FB SM POWER LOCK DESCRIPTION"); } } } else if (xmlStrcmp(child->name, BAD_CAST "interface") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { if (xmlStrcmp(txt, BAD_CAST "RTHS_0") == 0) { /* Select Selectrix mode */ __selectrix->SXflags |= Rautenhaus_MODE; } else if (xmlStrcmp(txt, BAD_CAST "RTHS_1") == 0) { /* Select Selectrix mode and two buses */ __selectrix->SXflags |= Rautenhaus_MODE; __selectrix->SXflags |= Rautenhaus_DBL; } else if (xmlStrcmp(txt, BAD_CAST "RTHS_2") == 0) { /* Select Rautenhaus mode */ __selectrix->SXflags |= Rautenhaus_MODE; __selectrix->SXflags |= Rautenhaus_FDBCK; __selectrix->SXflags |= Rautenhaus_ADR; } else if (xmlStrcmp(txt, BAD_CAST "RTHS_3") == 0) { /* Select Rautenhaus mode and two buses */ __selectrix->SXflags |= Rautenhaus_MODE; __selectrix->SXflags |= Rautenhaus_DBL; __selectrix->SXflags |= Rautenhaus_FDBCK; __selectrix->SXflags |= Rautenhaus_ADR; } xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "ports") == 0) { portindex = 1; xmlNodePtr subchild = child->children; xmlChar *subtxt = NULL; while (subchild != NULL) { if (xmlStrncmp(subchild->name, BAD_CAST "text", 4) == 0) { /* just do nothing, it is only a comment */ } else if (xmlStrcmp(subchild->name, BAD_CAST "port") == 0) { /* Check if on the second SX-bus */ offset = 0; xmlChar *pOffset = xmlGetProp(subchild, BAD_CAST "sxbus"); if (pOffset != NULL) { if (atoi((char *) pOffset) == 1) { offset = 128; } } free(pOffset); /* Get address */ subtxt = xmlNodeListGetString(doc, subchild-> xmlChildrenNode, 1); if (subtxt != NULL) { /* Store address and number SXbus */ __selectrix->fb_adresses[portindex] = atoi((char *) subtxt) + offset; xmlFree(subtxt); if (__selectrix->number_fb > portindex) { portindex++; } } } else { syslog_bus(busnumber, DBG_WARN, "WARNING, unknown sub " "tag found: \"%s\"!\n", subchild->name); } subchild = subchild->next; } } else { syslog_bus(busnumber, DBG_WARN, "WARNING, unknown tag found: \"%s\"!\n", child->name); } child = child->next; } if ((__selectrix->number_gl + __selectrix->number_ga + __selectrix->number_fb) < __selectrix->max_address) { if (init_GL(busnumber, __selectrix->number_gl)) { __selectrix->number_gl = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array " "for locomotives"); } if (init_GA(busnumber, __selectrix->number_ga)) { __selectrix->number_ga = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array " "for accessories"); } if (init_FB(busnumber, __selectrix->number_fb * 8)) { __selectrix->number_fb = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array " "for feedback"); } } else { __selectrix->number_gl = 0; __selectrix->number_ga = 0; __selectrix->number_fb = 0; syslog_bus(busnumber, DBG_ERROR, "Too many devices on the SX-bus"); } syslog_bus(busnumber, DBG_WARN, "Found %d loco's.", __selectrix->number_gl); syslog_bus(busnumber, DBG_WARN, "Found %d switches.", __selectrix->number_ga); syslog_bus(busnumber, DBG_WARN, "Found %d feedback modules.", __selectrix->number_fb); if (portindex != 0) { for (i = 1; i <= portindex; i++) { syslog_bus(busnumber, DBG_WARN, "Found feedback port number %d with address %d.", i, __selectrix->fb_adresses[i]); } } return 1; } /**************************************************************************** * Manage a serial port for communication with a selectrix interface *****************************************************************************/ /* Opens a serial port */ /* On success the port handle is changed to a value <> -1 */ int init_bus_Selectrix(bus_t busnumber) { static char *protocols = "S"; buses[busnumber].protocols = protocols; syslog_bus(busnumber, DBG_INFO, "Selectrix init: debuglevel %d", buses[busnumber].debuglevel); if (buses[busnumber].debuglevel <= DBG_DEBUG) { open_port(busnumber); syslog_bus(busnumber, DBG_INFO, "Selectrix init done, fd=%d", buses[busnumber].device.file.fd); syslog_bus(busnumber, DBG_INFO, "Selectrix description: %s", buses[busnumber].description); syslog_bus(busnumber, DBG_INFO, "Selectrix flags: %04X (hex)", __selectrix->SXflags); } else { buses[busnumber].device.file.fd = -1; } return 0; } /******************************************************* * Device initialisation ********************************************************/ /* Engines */ /* INIT GL S 1 31 2 */ int init_gl_Selectrix(gl_data_t *gl) { if ((gl->protocol == 'S') || (gl->protocol == 's')) { return ((gl->n_fs == 31) && (gl->protocolversion == 1) && (gl->n_func == 2)) ? SRCP_OK : SRCP_WRONGVALUE; } return SRCP_UNSUPPORTEDDEVICEPROTOCOL; } /* Switches, signals, ... */ /* INIT GA S */ int init_ga_Selectrix(ga_data_t *ga) { if ((ga->protocol == 'S') || (ga->protocol == 's')) { return SRCP_OK; } return SRCP_UNSUPPORTEDDEVICEPROTOCOL; } /* Feedback modules */ /* INIT FB S */ int init_fb_Selectrix(bus_t busnumber, int adres, const char protocol, int index) { if ((protocol == 'S') || (protocol == 's')) { if ((__selectrix->max_address > adres) && (__selectrix->number_fb >= index)) { __selectrix->fb_adresses[index] = adres; return SRCP_OK; } else { return SRCP_WRONGVALUE; } } return SRCP_UNSUPPORTEDDEVICEPROTOCOL; } /******************************************************* * Rautenhaus setup ********************************************************/ /* Make configuration byte for Rautenhaus interface */ void confRautenhaus(bus_t busnumber) { int configuration; /* Check if a Rautenhaus devise is connected */ if (__checkSXflag(Rautenhaus_MODE)) { /* Start with bus 0 selection */ configuration = RautenhsB0; if (__checkSXflag(Rautenhaus_DBL + Rautenhaus_RTBS)) { /* Bus 1 selected so change to bus 1. */ configuration = RautenhsB1; } else { __selectrix->SXflags &= ~Rautenhaus_RTBS; } if (__checkSXflag(Rautenhaus_FDBCK)) { /* Rautenhaus mode */ configuration |= (cntrlON + fdbckON); if (__checkSXflag(CC2000_MODE)) { /* CC2000, don't check address 111 */ /* Don't check bus 0 */ configuration |= clkOFF0; if (__checkSXflag(Rautenhaus_DBL)) { /* Don't check bus 1 */ configuration |= clkOFF1; } } } else { /* Selectrix mode */ configuration |= (cntrlOFF + fdbckOFF); } /* Write configuration to the device */ write_port(busnumber, SXwrite + RautenhsCC); write_port(busnumber, configuration); syslog_bus(busnumber, DBG_INFO, "Selectrix on bus %ld, Rautenhaus " "configuration is: %02X (hex).", busnumber, configuration); } } /* Make bus selector for Rautenhaus interface */ void selRautenhaus(bus_t busnumber, int adres) { if (__checkSXflag(Rautenhaus_MODE + Rautenhaus_DBL)) { if (adres > 127) { /* Addresses 128 ... 255 => bus 1 */ /* Check if bus 1 selected */ if (!(__checkSXflag(Rautenhaus_RTBS))) { /* No, select bus 1 */ write_port(busnumber, SXwrite + RautenhsCC); write_port(busnumber, RautenhsB1); __selectrix->SXflags |= Rautenhaus_RTBS; syslog_bus(busnumber, DBG_WARN, "Selectrix on bus %ld, Rautenhaus " "bus 1 selected.", busnumber); } } else { /* Addresses 0 ... 127 => bus 0 */ /* Check if bus 0 selected */ if (__checkSXflag(Rautenhaus_RTBS)) { /* No, select bus 0 */ write_port(busnumber, SXwrite + RautenhsCC); write_port(busnumber, RautenhsB0); __selectrix->SXflags &= ~Rautenhaus_RTBS; syslog_bus(busnumber, DBG_WARN, "Selectrix on bus %ld, Rautenhaus " "bus 0 selected.", busnumber); } } } } /******************************************************* * Base communication with the interface (Selectrix) ********************************************************/ /* Read data from the SX-bus (8 bits) */ int readSXbus(bus_t busnumber) { unsigned int rr; if (buses[busnumber].device.file.fd != -1) { /* Wait until a character arrives */ rr = read_port(busnumber); syslog_bus(busnumber, DBG_DEBUG, "Selectrix on bus %ld, read byte %02X (hex).", busnumber, rr); if (rr < 0x100) { return rr; } } return 0xFF; /* Error or closed, return all blocked */ } void commandreadSXbus(bus_t busnumber, int SXadres) { if (buses[busnumber].device.file.fd != -1) { /* Select Rautenhaus bus */ selRautenhaus(busnumber, SXadres); SXadres &= 0x7F; /* write SX-address and the read command */ write_port(busnumber, SXread + SXadres); /* extra byte for power to receive data */ write_port(busnumber, SXempty); /* receive data */ } else { syslog_bus(busnumber, DBG_ERROR, "Selectrix on bus %ld, address %d not read.", busnumber, SXadres); } } /* Write data to the SX-bus (8bits) */ void writeSXbus(bus_t busnumber, int SXadres, int SXdata) { if (buses[busnumber].device.file.fd != -1) { /* Select Rautenhaus bus */ selRautenhaus(busnumber, SXadres); SXadres &= 0x7F; /* write SX-address and the write command */ write_port(busnumber, SXwrite + SXadres); /* write data to the SX-bus */ write_port(busnumber, SXdata); } else { syslog_bus(busnumber, DBG_ERROR, "Selectrix on bus %ld, byte %02X (hex) not to address %d.", busnumber, SXdata, SXadres); } } /******************************************************* * Decoder reading/programming (Selectrix) ********************************************************/ int chkCC2000Status(bus_t busnumber, int step, int statFlag) { int wait; /* Get status byte of the CC2000 */ commandreadSXbus(busnumber, SXstatus); __selectrix->stateInterface = step; wait = 10; while ((__selectrix->stateInterface < (step + 1)) || (wait == 0)) { if (usleep(500) == -1) { syslog_bus(busnumber, DBG_DEBUG, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } wait--; } /* Check flag in status byte */ return (((readSXbus(busnumber) & statFlag) == statFlag) ? -1 : 0); } /* Configure CC200 for reading/writing decoders */ int chkCC2000Ready(bus_t busnumber) { int readyCC2000; /* Check if ready */ if (chkCC2000Status(busnumber, 10, SXstready)) { /* Check if power off */ if (!chkCC2000Status(busnumber, 10, SXstpower)) { /* Now CC2000 ready */ readyCC2000 = 0; } else { syslog_bus(busnumber, DBG_DEBUG, "Selectrix on bus %ld, power stil on the track.", busnumber); readyCC2000 = 2; } } else { syslog_bus(busnumber, DBG_DEBUG, "Selectrix on bus %ld, interface not ready.", busnumber); readyCC2000 = 1; } return readyCC2000; } /* Read decoder data to the SX-bus */ int readSXDecoder(bus_t busnumber) { int SXdecoder; int waitCount; int result; /* Check if ready */ if (chkCC2000Ready(busnumber) == 0) { /* Start reading in Selectrix mode */ writeSXbus(busnumber, SXcommand, SXcmdstart + SXcmdprog + SXcmdmodus); result = sleep(250000); if (result != 0) { syslog_bus(busnumber, DBG_DEBUG, "sleep() interrupted, %d seconds left\n", result); } /* Stop reading */ writeSXbus(busnumber, SXcommand, SXcmdstart + SXcmdmodus); /* Get lowerbyte of decoder data */ commandreadSXbus(busnumber, SXprog1); __selectrix->stateInterface = 12; waitCount = 10; while ((__selectrix->stateInterface < (13)) || (waitCount == 0)) { if (usleep(500) == -1) { syslog_bus(busnumber, DBG_DEBUG, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } waitCount--; } if (waitCount > 0) { SXdecoder = readSXbus(busnumber); /* Get higherbyte of decoder data */ commandreadSXbus(busnumber, SXprog2); __selectrix->stateInterface = 12; waitCount = 10; while ((__selectrix->stateInterface < (13)) || (waitCount == 0)) { if (usleep(500) == -1) { syslog_bus(busnumber, DBG_DEBUG, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } waitCount--; } if (waitCount > 0) { SXdecoder = SXdecoder + 256 * readSXbus(busnumber); return SXdecoder; } } } return -1; /* Invalid decoder data */ } /* Write data on SX-bus to the decoder */ void writeSXDecoder(bus_t busnumber, int SXdecoder) { int timeout; /* Check if ready */ if (chkCC2000Ready(busnumber) == 0) { /* Write decoderdata to SX-bus (lower half) */ writeSXbus(busnumber, SXprog1, SXdecoder & 0xff); /* Write decoderdata to SX-bus (upper half) */ writeSXbus(busnumber, SXprog2, (SXdecoder / 256) & 0xff); /* Start Programming in Selectrix mode */ writeSXbus(busnumber, SXcommand, SXcmdstart + SXcmdprog + SXcmddcod + SXcmdmodus); /* Wait 3 seconds */ if (usleep(3000000) == -1) { syslog_bus(busnumber, DBG_DEBUG, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } timeout = 1000; while (timeout > 0) { if (chkCC2000Status(busnumber, 14, SXstready) == 0) { timeout = 0; } else { timeout--; if (usleep(500) == -1) { syslog_bus(busnumber, DBG_DEBUG, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } } } /* Stop programming */ writeSXbus(busnumber, SXcommand, SXcmdstart + SXcmdmodus); } } /******************************************************* * Command generation (Selectrix) ********************************************************/ /*thread cleanup routine for this bus*/ static void end_bus_thread(bus_thread_t * btd) { int result; syslog_bus(btd->bus, DBG_INFO, "Selectrix bus terminated."); if (buses[btd->bus].device.file.fd != -1) { close_port(btd->bus); } result = pthread_mutex_destroy(&buses[btd->bus].transmit_mutex); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_destroy() failed: %s (errno = %d).", strerror(result), result); } result = pthread_cond_destroy(&buses[btd->bus].transmit_cond); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_init() failed: %s (errno = %d).", strerror(result), result); } free(buses[btd->bus].driverdata); free(btd); } void *thr_commandSelectrix(void *v) { int addr, data, state; struct _SM smtmp; gl_data_t gltmp; ga_data_t gatmp; int last_cancel_state, last_cancel_type; bus_thread_t *btd = (bus_thread_t *) malloc(sizeof(bus_thread_t)); if (btd == NULL) pthread_exit((void *) 1); /* Exit thread */ btd->bus = (bus_t) v; btd->fd = -1; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_cancel_state); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_cancel_type); /* register cleanup routine */ pthread_cleanup_push((void *) end_bus_thread, (void *) btd); syslog_bus(btd->bus, DBG_INFO, "Selectrix bus command thread started."); buses[btd->bus].watchdog = 0; while (true) { state = 0; pthread_testcancel(); buses[btd->bus].watchdog = 1; /* Start/Stop */ if (buses[btd->bus].power_changed != 0) { state = 1; buses[btd->bus].watchdog = 2; char msg[1000]; if ((buses[btd->bus].power_state)) { /* Turn power on */ writeSXbus(btd->bus, SXcontrol, 0x80); confRautenhaus(btd->bus); } else { /* Turn power off */ writeSXbus(btd->bus, SXcontrol, 0x00); } infoPower(btd->bus, msg); enqueueInfoMessage(msg); syslog_bus(btd->bus, DBG_WARN, "Selectrix had a power change."); buses[btd->bus].power_changed = 0; } /* Programming */ /* Only programming if power is off */ if (buses[btd->bus].power_state == 0) { if (!queue_SM_isempty(btd->bus)) { state = 2; buses[btd->bus].watchdog = 3; dequeueNextSM(btd->bus, &smtmp); session_lock_wait(btd->bus); switch (smtmp.command) { case SET: /* Write data to decoder */ writeSXDecoder(btd->bus, smtmp.value); break; case GET: case VERIFY: /* Read data from decoder */ smtmp.value = readSXDecoder(btd->bus); break; } session_endwait(btd->bus, smtmp.value); } } /* Loco decoders */ if (!queue_GL_isempty(btd->bus)) { state = 3; buses[btd->bus].watchdog = 4; dequeueNextGL(btd->bus, &gltmp); /* Address of the engine */ addr = gltmp.id; /* Check if valid address */ if (__selectrixt->max_address > addr) { /* Check: terminating the engine */ if (gltmp.state == 2) { syslog_bus(btd->bus, DBG_WARN, "Selectrix engine " "with address %d is removed", addr); } else { /* Direction */ switch (gltmp.direction) { case 0: /* Backward */ data = 0x20; break; case 1: /* Forward */ data = 0x00; break; default: /* Emergency stop or ... */ /* Get last direction */ data = __selectrixt->bus_data[addr] & 0x20; gltmp.speed = 0; break; } /* Speed, Light, Function */ data = data + gltmp.speed + ((gltmp.funcs & 0x01) ? 0x40 : 0) + ((gltmp.funcs & 0x02) ? 0x80 : 0); writeSXbus(btd->bus, addr, data); __selectrixt->bus_data[addr] = data; cacheSetGL(btd->bus, addr, gltmp); syslog_bus(btd->bus, DBG_WARN, "Selectrix " "engine with address %d " "has data %02X (hex).", addr, data); } } else { syslog_bus(btd->bus, DBG_ERROR, "Selectrix invalid " "address %d with engine", addr); } } /* Drives solenoids and signals */ if (!queue_GA_isempty(btd->bus)) { state = 4; buses[btd->bus].watchdog = 5; dequeueNextGA(btd->bus, &gatmp); addr = gatmp.id; if (__selectrixt->max_address > addr) { data = __selectrixt->bus_data[addr]; /* Select the action to do */ if (gatmp.action == 0) { /* Set pin to "0" */ switch (gatmp.port) { case 1: data &= 0xfe; break; case 2: data &= 0xfd; break; case 3: data &= 0xfb; break; case 4: data &= 0xf7; break; case 5: data &= 0xef; break; case 6: data &= 0xdf; break; case 7: data &= 0xbf; break; case 8: data &= 0x7f; break; default: syslog_bus(btd->bus, DBG_WARN, "Selectrix invalid " "port number %d with " "switch/signal or ...", gatmp.port); break; } } else { /* Set pin to "1" */ switch (gatmp.port) { case 1: data |= 0x01; break; case 2: data |= 0x02; break; case 3: data |= 0x04; break; case 4: data |= 0x08; break; case 5: data |= 0x10; break; case 6: data |= 0x20; break; case 7: data |= 0x40; break; case 8: data |= 0x80; break; default: syslog_bus(btd->bus, DBG_WARN, "Selectrix invalid " "port number %d with " "switch/signal or ...", gatmp.port); break; } } writeSXbus(btd->bus, addr, data); __selectrixt->bus_data[addr] = data; syslog_bus(btd->bus, DBG_WARN, "Selectrix address %d " "has new data %02X (hex).", addr, data); } else { syslog_bus(btd->bus, DBG_ERROR, "Selectrix invalid " "address %d with switch/signal or ...", addr); } } /* Feed back contacts */ if ((__selectrixt->number_fb > 0) && (__selectrixt->stateInterface == 1)) { state = 5; buses[btd->bus].watchdog = 6; /* Fetch the module address */ addr = __selectrixt->fb_adresses[__selectrixt->currentFB]; /* Send command to read the SX-bus */ __selectrixt->stateInterface = 2; commandreadSXbus(btd->bus, addr); } if (state == 0) { /* Lock thread till new data to process arrives */ suspend_bus_thread(btd->bus); } } /*run the cleanup routine */ pthread_cleanup_pop(1); return NULL; } /******************************************************* * Timed command generation (Selectrix) ********************************************************/ void *thr_feedbackSelectrix(void *v) { int addr; int respondtime; bus_t busnumber = (bus_t) v; syslog_bus(busnumber, DBG_INFO, "Selectrix " "feedback thread started."); respondtime = 0; while (true) { /* Feed back contacts */ if ((__selectrix->number_fb > 0) && !(__checkSXflag(Rautenhaus_MODE + Rautenhaus_FDBCK))) { switch (__selectrix->stateInterface) { case 0: /* Fetch the module address */ addr = __selectrix->fb_adresses[__selectrix->currentFB]; if (__selectrix->max_address > addr) { /* Let thread process a feedback */ syslog_bus(busnumber, DBG_INFO, "Selectrix address %d selected.", addr); __selectrix->stateInterface = 1; resume_bus_thread(busnumber); } else { syslog_bus(busnumber, DBG_INFO, "Selectrix " "invalid address %d " "with feedback index %d.", addr, __selectrix->currentFB); __selectrix->stateInterface = 0; __selectrix->currentFB = 1; } respondtime = 0; break; case 1: case 2: respondtime++; if (respondtime > 50) { __selectrix->stateInterface = 0; __selectrix->currentFB = 1; respondtime = 0; } break; default: __selectrix->stateInterface = 0; __selectrix->currentFB = 1; respondtime = 0; break; } /* Process every feedback 4 times per second */ if (usleep(250000 / __selectrix->number_fb) == -1) { syslog_bus(busnumber, DBG_DEBUG, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } } else { if (usleep(1000000) == -1) { syslog_bus(busnumber, DBG_DEBUG, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } } } } /******************************************************* * Command processing (Selectrix) ********************************************************/ void sig_processSelectrix(bus_t busnumber) { int data, addr; int found; int dataUP, i; __selectrix->SXflags |= Connection; syslog_bus(busnumber, DBG_DEBUG, "Selectrix SIGIO processed."); /* Read the SX-bus */ data = readSXbus(busnumber); switch (__selectrix->stateInterface) { /* Reading Selectrix interface */ case 2: addr = __selectrix->fb_adresses[__selectrix->currentFB]; syslog_bus(busnumber, DBG_INFO, "Selectrix address %d " "has feedback data %02X (hex).", addr, data); __selectrix->bus_data[addr] = data; /* Rotate bits 7 ... 0 to 1 ... 8 */ dataUP = 0; for (i = 0; i < 8; i++) { dataUP = dataUP * 2; dataUP = dataUP + (data & 0x01); data = data / 2; } /* Set the daemon global data */ /* Use 1, 2, ... as address for feedback */ setFBmodul(busnumber, __selectrix->currentFB, dataUP); /* Use real address for feedback */ // setFBmodul(busnumber, addr, dataUP); /* Select the next module */ if (__selectrix->currentFB >= __selectrix->number_fb) { /* Reset to start */ __selectrix->currentFB = 1; } else { /* Next */ __selectrix->currentFB++; } __selectrix->stateInterface = 0; break; /* Reading and programming a decoder */ case 10: __selectrix->stateInterface = 11; break; case 12: __selectrix->stateInterface = 13; break; case 14: __selectrix->stateInterface = 15; break; /* Reading a Rautenhaus interface */ default: if (__checkSXflag(Rautenhaus_MODE + Rautenhaus_FDBCK)) { if (__checkSXflag(Rautenhaus_ADR)) { /* 1: SX-bus address */ found = true; __selectrix->currentFB = 1; while ((found == true) && !(__selectrix->currentFB > __selectrix->number_fb)) { if (data == __selectrix->fb_adresses[__selectrix-> currentFB]) { found = false; __selectrix->SXflags &= ~Rautenhaus_ADR; } else { __selectrix->currentFB++; } } } else { /* 0: SX-bus data */ addr = __selectrix->fb_adresses[__selectrix->currentFB]; syslog_bus(busnumber, DBG_INFO, "Selectrix address %d " "has feedback data %02X (hex).", addr, data); __selectrix->bus_data[addr] = data; /* Rotate bits 7 ... 0 to 1 ... 8 */ dataUP = 0; for (i = 0; i < 8; i++) { dataUP = dataUP * 2; dataUP = dataUP + (data & 0x01); data = data / 2; } /* Set the daemon global data */ /* Use 1, 2, ... as address for feedback */ setFBmodul(busnumber, __selectrix->currentFB, dataUP); /* Use real address for feedback */ /* setFBmodul(busnumber, addr, dataUP); */ __selectrix->SXflags |= Rautenhaus_ADR; } } else { syslog_bus(busnumber, DBG_INFO, "Selectrix discarded data %02X (hex).", data); __selectrix->stateInterface = 0; __selectrix->currentFB = 1; } break; } } srcpd-2.1.7/src/srcp-info.c0000664000175000017500000003602212673552173012430 00000000000000/*************************************************************************** srcp-info.c - description ------------------- begin : Mon May 20 2002 copyright : (C) 2002 by email : ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /* This code manages INFO SESSIONs. Every hardware driver, alias »bus process«, must call (directly or via set functions) the enqueueInfoMessage() function. This function is delegated to the session function session_enqueue_info_message() which writes the preformated string into the session specific message pipes. On the other end of each session pipe the information session process is waiting for new enqueued messages to write them to the socket file descriptor. The process is blocked by the select() function to only be bussy when real work has to be done. When a new INFO session starts, it will first send all available status data and then wait for newly arriving messages. */ #include #include #include #include #include "config-srcpd.h" #include "io.h" #include "srcp-gl.h" #include "srcp-ga.h" #include "srcp-fb.h" #include "srcp-sm.h" #include "srcp-power.h" #include "srcp-info.h" #include "srcp-error.h" #include "srcp-descr.h" #include "srcp-time.h" #include "srcp-session.h" #include "syslogmessage.h" #define max(a,b) ((a) > (b) ? (a) : (b)) /* Enqueue a pre-formatted message */ int enqueueInfoMessage(char *msg) { session_enqueue_info_message(0, msg); return SRCP_OK; } /* There is nothing to do here. */ void startup_INFO() { } /** * Handler for info mode client thread; * terminates on write failure or if cancelled externaly **/ int doInfoClient(session_node_t * sn) { int i, number, value, result, linelen, bufferlen; char reply[MAXSRCPLINELEN], description[MAXSRCPLINELEN]; char pipebuffer[2048]; char *buffer = &pipebuffer[0]; char *bufferend = &pipebuffer[sizeof(pipebuffer) - 1]; char *linestart; struct timeval cmp_time; bus_t bus; fd_set rset; int maxfdp1; ssize_t rwresult = 0; ssize_t swritten = 0; ssize_t total = 0; result = pipe(sn->pipefd); if (-1 == result) { syslog_session(sn->session, DBG_ERROR, "Pipe create failed: %s (errno = %d)\n", strerror(errno), errno); return (-1); } maxfdp1 = max(sn->socket, sn->pipefd[0]) + 1; FD_ZERO(&rset); syslog_session(sn->session, DBG_DEBUG, "New INFO client requested."); /* send start up-information to a new client */ for (bus = 0; bus <= num_buses; bus++) { pthread_testcancel(); syslog_session(sn->session, DBG_DEBUG, "Send all data for bus number %d to new client.", bus); /* first some global bus data */ /* send Descriptions for buses */ describeBus(bus, reply); if (writen(sn->socket, reply, strlen(reply)) == -1) { syslog_session(sn->session, DBG_ERROR, "Socket write failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } strcpy(description, reply); *reply = 0x00; if (strstr(description, "POWER")) { infoPower(bus, reply); if (writen(sn->socket, reply, strlen(reply)) == -1) { syslog_session(sn->session, DBG_ERROR, "Socket write failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } *reply = 0x00; } if (strstr(description, "TIME")) { describeTIME(reply); if (writen(sn->socket, reply, strlen(reply)) == -1) { syslog_session(sn->session, DBG_ERROR, "Socket write failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } *reply = 0x00; infoTIME(reply); if (writen(sn->socket, reply, strlen(reply)) == -1) { syslog_session(sn->session, DBG_ERROR, "Socket write failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } *reply = 0x00; } /* send all needed generic locomotives */ if (strstr(description, "GL")) { number = getMaxAddrGL(bus); for (i = 1; i <= number; i++) { if (isInitializedGL(bus, i)) { sessionid_t lockid; cacheDescribeGL(bus, i, reply); if (writen(sn->socket, reply, strlen(reply)) == -1) { syslog_session(sn->session, DBG_ERROR, "Socket write failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } *reply = 0x00; cacheInfoGL(bus, i, reply); if (writen(sn->socket, reply, strlen(reply)) == -1) { syslog_session(sn->session, DBG_ERROR, "Socket write failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } *reply = 0x00; cacheGetLockGL(bus, i, &lockid); if (lockid != 0) { describeLOCKGL(bus, i, reply); if (writen(sn->socket, reply, strlen(reply)) == -1) { syslog_session(sn->session, DBG_ERROR, "Socket write failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } *reply = 0x00; } } } } /* send all needed generic accessories */ if (strstr(description, "GA")) { number = get_number_ga(bus); for (i = 1; i <= number; i++) { if (isInitializedGA(bus, i)) { sessionid_t lockid; int rc, port; describeGA(bus, i, reply); if (writen(sn->socket, reply, strlen(reply)) == -1) { syslog_session(sn->session, DBG_ERROR, "Socket write failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } *reply = 0x00; for (port = 0; port <= 1; port++) { rc = infoGA(bus, i, port, reply); if (rc == SRCP_INFO) { if (writen(sn->socket, reply, strlen(reply)) == -1) { syslog_session(sn->session, DBG_ERROR, "Socket write failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } *reply = 0x00; } } getlockGA(bus, i, &lockid); if (lockid != 0) { describeLOCKGA(bus, i, reply); if (writen(sn->socket, reply, strlen(reply)) == -1) { syslog_session(sn->session, DBG_ERROR, "Socket write failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } *reply = 0x00; } } } } /* send all needed feedbacks */ if (strstr(description, "FB")) { number = get_number_fb(bus); for (i = 1; i <= number; i++) { int rc = getFB(bus, i, &cmp_time, &value); if (rc == SRCP_OK && value != 0) { infoFB(bus, i, reply, sizeof(reply)); if (writen(sn->socket, reply, strlen(reply)) == -1) { syslog_session(sn->session, DBG_ERROR, "Socket write failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } *reply = 0x00; } } } } syslog_session(sn->session, DBG_DEBUG, "All messages send to new INFO client.\n"); /* * There is a kind of race condition: Newly piped messages may * be ignored until we reach this point. But there is no message * loss because the following action will properly detect and send * them. */ /* * This while loop has two tasks: * 1) Wait for enqueued info messages to send them to the * connected client. * 2) Detect a client connection close in a timely manner. * * The select() function helps to detect activities on these two * diffent communication channels each having its own file * descriptor. */ while (true) { pthread_testcancel(); FD_SET(sn->pipefd[0], &rset); FD_SET(sn->socket, &rset); if ((result = select(maxfdp1, &rset, NULL, NULL, NULL)) == -1) { if (errno == EINTR) continue; else { syslog_session(sn->session, DBG_ERROR, "Select failed: %s (errno = %d)\n", strerror(errno), errno); return (-1); } } /* some socket activity was detected */ if (FD_ISSET(sn->socket, &rset)) { memset(reply, 0, sizeof(reply)); rwresult = read(sn->socket, &reply, sizeof(reply)); if (0 == rwresult) { syslog_session(sn->session, DBG_INFO, "Client terminated INFO session.\n"); return (-1); } if (-1 == rwresult) { syslog_session(sn->session, DBG_INFO, "Socket read failed: %s (errno = %d).\n", strerror(errno), errno); return (-1); } syslog_session(sn->session, DBG_INFO, "Unknown client message for INFO session: %s.\n", reply); } /* Message from enqueueing process arrived; dequeue piped info * messages and write them to socket. Watch out for truncated * messages if pipe or read buffer is completely full.*/ if (FD_ISSET(sn->pipefd[0], &rset)) { linelen = 0; do { /* start of read buffer has an offset if there is a * truncated message from last read */ buffer = &pipebuffer[0] + linelen; bufferlen = sizeof(pipebuffer) - linelen; linelen = 0; total = 0; swritten = 0; linestart = NULL; rwresult = read(sn->pipefd[0], buffer, bufferlen); /* pipe read error */ if (-1 == rwresult) { syslog_session(sn->session, DBG_ERROR, "Pipe read failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } /* EOF from other end of pipe */ if (0 == rwresult) { syslog_session(sn->session, DBG_ERROR, "Pipe closed unexpectedly.\n"); return -1; } /* check if buffer is full and last line was truncated; * if truncated line found, search start of line */ if (rwresult == bufferlen && *bufferend != '\0') { linestart = bufferend - 1; while (linestart >= &pipebuffer[0]) { if (*linestart == '\0') { linelen = bufferend - linestart; linestart++; break; } linestart--; } if (linestart == &pipebuffer[0]) { syslog_session(sn->session, DBG_ERROR, "Pipe read buffer overfilled."); return -1; } } /* normal operation; write several times to socket if pipe * containes more than one message string, which is * terminated by '\0' */ buffer = &pipebuffer[0]; do { swritten = writen(sn->socket, buffer, strlen(buffer)); total += swritten + 1; buffer += swritten + 1; /* if there is a truncated message, move it to start of * buffer to be used after next read*/ if (buffer == linestart) { memmove(&pipebuffer[0], linestart, linelen); break; } } while (total < rwresult && swritten > 0); /* socket write error */ if (-1 == swritten) { syslog_session(sn->session, DBG_ERROR, "Socket write failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } /* EOF, client terminated connection */ if (0 == swritten) { syslog_session(sn->session, DBG_WARN, "Socket write failed (connection terminated " "by client).\n"); return -1; } } while (linestart != NULL); } } return 0; } srcpd-2.1.7/src/dcc-address.h0000644000175000017500000000255711141012755012677 00000000000000/* Copyright (c) 2009 Guido Scholz This file is part of srcpd. srcpd is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. srcpd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with srcpd. If not, see . */ #ifndef DCC_ADDRESS_H #define DCC_ADDRESS_H /* Map lenz address to nmra/subaddress values and backward. * Valid ranges * lenz = 0..2044 * nmra = 0..511 * sub = 0..3 */ void lenz_to_nmra(unsigned int lenz, unsigned int* nmra, unsigned char* sub); void nmra_to_lenz(unsigned int nmra, unsigned char sub, unsigned int *lenz); /* Map nmra/port to lenz/port values and backward. * Valid ranges * lenz = 0..2044 * port = 0..1 * nmra_a = 0..511 * nmra_p = 0..7 */ void lenz2_to_nmra2(unsigned int lenz, unsigned char port, unsigned int* nmra_a, unsigned char* nmra_p); void nmra2_to_lenz2(unsigned int nmra_a, unsigned char nmra_p, unsigned int *lenz, unsigned char* port); #endif srcpd-2.1.7/src/srcp-fb.h0000644000175000017500000000222312673554172012064 00000000000000/* $Id: srcp-fb.h 1725 2016-03-20 17:06:01Z gscholz $ */ /* * Vorliegende Software unterliegt der General Public License, * Version 2, 1991. (c) Matthias Trute, 2000-2001. * */ #ifndef _SRCP_FB_H #define _SRCP_FB_H #include "config-srcpd.h" #include /* reserve 16 bit of space (short int) for 1 bit of information, two times */ typedef struct _FBSTATE { struct timeval timestamp; short int state; short int change; } fb_state_t; typedef struct _FB { int numberOfFb; fb_state_t *fbstate; } fb_t; typedef struct _RESET_FB { int port; struct timeval timestamp; } fb_reset_t; void startup_FB(); int init_FB(bus_t bus, int number); int get_number_fb(bus_t bus); int initFB(bus_t busnumber, int addr, const char protocol, int index); int getFB(bus_t bus, int port, struct timeval *time, int *value); int setFB( bus_t bus, int port, int value ); int updateFB(bus_t bus, int port, int value); int setFBmodul(bus_t bus, int mod, int values); int infoFB(bus_t bus, int port, char *msg, size_t length); int describeFB(bus_t bus, int addr, char *reply); void check_reset_fb(bus_t busnumber); void set_min_time(bus_t busnumber, int mt); #endif srcpd-2.1.7/src/Makefile.in0000664000175000017500000007073414615104457012435 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Makefile.am for srcpd # version: $Revision: 1702 $ # last update: $Date: 2014-07-01 21:15:13 +0200 (Di, 01. Jul 2014) $ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ sbin_PROGRAMS = srcpd$(EXEEXT) @USE_DDL_TRUE@am__append_1 = \ @USE_DDL_TRUE@ ddl.c ddl.h \ @USE_DDL_TRUE@ ddl_maerklin.c ddl_maerklin.h \ @USE_DDL_TRUE@ ddl_nmra.c ddl_nmra.h @USE_DDLS88_TRUE@am__append_2 = ddl-s88.c ddl-s88.h @USE_I2C_TRUE@am__append_3 = i2c-dev.c i2c-dev.h @USE_IB_TRUE@am__append_4 = ib.c ib.h @USE_HSI88_TRUE@am__append_5 = hsi-88.c hsi-88.h # tricky: li100-main includes li100.c twice for both USB and RS232 support @USE_LI100_TRUE@am__append_6 = li100.h \ @USE_LI100_TRUE@ li100-main.c @USE_LOCONET_TRUE@am__append_7 = loconet.c loconet.h @USE_LOOPBACK_TRUE@am__append_8 = loopback.c loopback.h @USE_M605X_TRUE@am__append_9 = m605x.c m605x.h @USE_SELECTRIX_TRUE@am__append_10 = selectrix.c selectrix.h @USE_ZIMO_TRUE@am__append_11 = zimo.c zimo.h @USE_DCCAR_TRUE@am__append_12 = dccar.c dccar.h subdir = src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am__srcpd_SOURCES_DIST = clientservice.c clientservice.h \ config-srcpd.c config-srcpd.h dcc-address.c dcc-address.h io.c \ io.h toolbox.c toolbox.h netservice.c netservice.h portio.c \ portio.h srcp-command.c srcp-command.h srcpd.c srcp-descr.c \ srcp-descr.h srcp-error.c srcp-error.h srcp-fb.c srcp-fb.h \ srcp-ga.c srcp-ga.h srcp-gl.c srcp-gl.h srcp-gm.c srcp-gm.h \ srcp-info.c srcp-info.h srcp-lock.c srcp-lock.h srcp-power.c \ srcp-power.h srcp-server.c srcp-server.h srcp-session.c \ srcp-session.h srcp-sm.c srcp-sm.h srcp-time.c srcp-time.h \ syslogmessage.c syslogmessage.h ttycygwin.c ttycygwin.h ddl.c \ ddl.h ddl_maerklin.c ddl_maerklin.h ddl_nmra.c ddl_nmra.h \ ddl-s88.c ddl-s88.h i2c-dev.c i2c-dev.h ib.c ib.h hsi-88.c \ hsi-88.h li100.h li100-main.c loconet.c loconet.h loopback.c \ loopback.h m605x.c m605x.h selectrix.c selectrix.h zimo.c \ zimo.h dccar.c dccar.h @USE_DDL_TRUE@am__objects_1 = ddl.$(OBJEXT) ddl_maerklin.$(OBJEXT) \ @USE_DDL_TRUE@ ddl_nmra.$(OBJEXT) @USE_DDLS88_TRUE@am__objects_2 = ddl-s88.$(OBJEXT) @USE_I2C_TRUE@am__objects_3 = i2c-dev.$(OBJEXT) @USE_IB_TRUE@am__objects_4 = ib.$(OBJEXT) @USE_HSI88_TRUE@am__objects_5 = hsi-88.$(OBJEXT) @USE_LI100_TRUE@am__objects_6 = li100-main.$(OBJEXT) @USE_LOCONET_TRUE@am__objects_7 = loconet.$(OBJEXT) @USE_LOOPBACK_TRUE@am__objects_8 = loopback.$(OBJEXT) @USE_M605X_TRUE@am__objects_9 = m605x.$(OBJEXT) @USE_SELECTRIX_TRUE@am__objects_10 = selectrix.$(OBJEXT) @USE_ZIMO_TRUE@am__objects_11 = zimo.$(OBJEXT) @USE_DCCAR_TRUE@am__objects_12 = dccar.$(OBJEXT) am_srcpd_OBJECTS = clientservice.$(OBJEXT) config-srcpd.$(OBJEXT) \ dcc-address.$(OBJEXT) io.$(OBJEXT) toolbox.$(OBJEXT) \ netservice.$(OBJEXT) portio.$(OBJEXT) srcp-command.$(OBJEXT) \ srcpd.$(OBJEXT) srcp-descr.$(OBJEXT) srcp-error.$(OBJEXT) \ srcp-fb.$(OBJEXT) srcp-ga.$(OBJEXT) srcp-gl.$(OBJEXT) \ srcp-gm.$(OBJEXT) srcp-info.$(OBJEXT) srcp-lock.$(OBJEXT) \ srcp-power.$(OBJEXT) srcp-server.$(OBJEXT) \ srcp-session.$(OBJEXT) srcp-sm.$(OBJEXT) srcp-time.$(OBJEXT) \ syslogmessage.$(OBJEXT) ttycygwin.$(OBJEXT) $(am__objects_1) \ $(am__objects_2) $(am__objects_3) $(am__objects_4) \ $(am__objects_5) $(am__objects_6) $(am__objects_7) \ $(am__objects_8) $(am__objects_9) $(am__objects_10) \ $(am__objects_11) $(am__objects_12) srcpd_OBJECTS = $(am_srcpd_OBJECTS) srcpd_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/clientservice.Po \ ./$(DEPDIR)/config-srcpd.Po ./$(DEPDIR)/dcc-address.Po \ ./$(DEPDIR)/dccar.Po ./$(DEPDIR)/ddl-s88.Po ./$(DEPDIR)/ddl.Po \ ./$(DEPDIR)/ddl_maerklin.Po ./$(DEPDIR)/ddl_nmra.Po \ ./$(DEPDIR)/hsi-88.Po ./$(DEPDIR)/i2c-dev.Po ./$(DEPDIR)/ib.Po \ ./$(DEPDIR)/io.Po ./$(DEPDIR)/li100-main.Po \ ./$(DEPDIR)/loconet.Po ./$(DEPDIR)/loopback.Po \ ./$(DEPDIR)/m605x.Po ./$(DEPDIR)/netservice.Po \ ./$(DEPDIR)/portio.Po ./$(DEPDIR)/selectrix.Po \ ./$(DEPDIR)/srcp-command.Po ./$(DEPDIR)/srcp-descr.Po \ ./$(DEPDIR)/srcp-error.Po ./$(DEPDIR)/srcp-fb.Po \ ./$(DEPDIR)/srcp-ga.Po ./$(DEPDIR)/srcp-gl.Po \ ./$(DEPDIR)/srcp-gm.Po ./$(DEPDIR)/srcp-info.Po \ ./$(DEPDIR)/srcp-lock.Po ./$(DEPDIR)/srcp-power.Po \ ./$(DEPDIR)/srcp-server.Po ./$(DEPDIR)/srcp-session.Po \ ./$(DEPDIR)/srcp-sm.Po ./$(DEPDIR)/srcp-time.Po \ ./$(DEPDIR)/srcpd.Po ./$(DEPDIR)/syslogmessage.Po \ ./$(DEPDIR)/toolbox.Po ./$(DEPDIR)/ttycygwin.Po \ ./$(DEPDIR)/zimo.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(srcpd_SOURCES) DIST_SOURCES = $(am__srcpd_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \ config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \ $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = -D_REENTRANT -DSYSCONFDIR=\"$(sysconfdir)\" @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ XML2_CONFIG = @XML2_CONFIG@ XML_CPPFLAGS = @XML_CPPFLAGS@ XML_LIBS = @XML_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ acx_pthread_config = @acx_pthread_config@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ srcpd_SOURCES = clientservice.c clientservice.h config-srcpd.c \ config-srcpd.h dcc-address.c dcc-address.h io.c io.h toolbox.c \ toolbox.h netservice.c netservice.h portio.c portio.h \ srcp-command.c srcp-command.h srcpd.c srcp-descr.c \ srcp-descr.h srcp-error.c srcp-error.h srcp-fb.c srcp-fb.h \ srcp-ga.c srcp-ga.h srcp-gl.c srcp-gl.h srcp-gm.c srcp-gm.h \ srcp-info.c srcp-info.h srcp-lock.c srcp-lock.h srcp-power.c \ srcp-power.h srcp-server.c srcp-server.h srcp-session.c \ srcp-session.h srcp-sm.c srcp-sm.h srcp-time.c srcp-time.h \ syslogmessage.c syslogmessage.h ttycygwin.c ttycygwin.h \ $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_4) $(am__append_5) $(am__append_6) \ $(am__append_7) $(am__append_8) $(am__append_9) \ $(am__append_10) $(am__append_11) $(am__append_12) EXTRA_DIST = li100.c all: config.h $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): config.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status src/config.h $(srcdir)/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) srcpd$(EXEEXT): $(srcpd_OBJECTS) $(srcpd_DEPENDENCIES) $(EXTRA_srcpd_DEPENDENCIES) @rm -f srcpd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(srcpd_OBJECTS) $(srcpd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clientservice.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config-srcpd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dcc-address.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dccar.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ddl-s88.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ddl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ddl_maerklin.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ddl_nmra.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hsi-88.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i2c-dev.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ib.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/li100-main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loconet.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loopback.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/m605x.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netservice.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/portio.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/selectrix.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-command.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-descr.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-error.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-fb.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-ga.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-gl.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-gm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-info.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-lock.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-power.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-server.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-session.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-sm.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcp-time.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srcpd.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/syslogmessage.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/toolbox.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttycygwin.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zimo.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) config.h installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/clientservice.Po -rm -f ./$(DEPDIR)/config-srcpd.Po -rm -f ./$(DEPDIR)/dcc-address.Po -rm -f ./$(DEPDIR)/dccar.Po -rm -f ./$(DEPDIR)/ddl-s88.Po -rm -f ./$(DEPDIR)/ddl.Po -rm -f ./$(DEPDIR)/ddl_maerklin.Po -rm -f ./$(DEPDIR)/ddl_nmra.Po -rm -f ./$(DEPDIR)/hsi-88.Po -rm -f ./$(DEPDIR)/i2c-dev.Po -rm -f ./$(DEPDIR)/ib.Po -rm -f ./$(DEPDIR)/io.Po -rm -f ./$(DEPDIR)/li100-main.Po -rm -f ./$(DEPDIR)/loconet.Po -rm -f ./$(DEPDIR)/loopback.Po -rm -f ./$(DEPDIR)/m605x.Po -rm -f ./$(DEPDIR)/netservice.Po -rm -f ./$(DEPDIR)/portio.Po -rm -f ./$(DEPDIR)/selectrix.Po -rm -f ./$(DEPDIR)/srcp-command.Po -rm -f ./$(DEPDIR)/srcp-descr.Po -rm -f ./$(DEPDIR)/srcp-error.Po -rm -f ./$(DEPDIR)/srcp-fb.Po -rm -f ./$(DEPDIR)/srcp-ga.Po -rm -f ./$(DEPDIR)/srcp-gl.Po -rm -f ./$(DEPDIR)/srcp-gm.Po -rm -f ./$(DEPDIR)/srcp-info.Po -rm -f ./$(DEPDIR)/srcp-lock.Po -rm -f ./$(DEPDIR)/srcp-power.Po -rm -f ./$(DEPDIR)/srcp-server.Po -rm -f ./$(DEPDIR)/srcp-session.Po -rm -f ./$(DEPDIR)/srcp-sm.Po -rm -f ./$(DEPDIR)/srcp-time.Po -rm -f ./$(DEPDIR)/srcpd.Po -rm -f ./$(DEPDIR)/syslogmessage.Po -rm -f ./$(DEPDIR)/toolbox.Po -rm -f ./$(DEPDIR)/ttycygwin.Po -rm -f ./$(DEPDIR)/zimo.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/clientservice.Po -rm -f ./$(DEPDIR)/config-srcpd.Po -rm -f ./$(DEPDIR)/dcc-address.Po -rm -f ./$(DEPDIR)/dccar.Po -rm -f ./$(DEPDIR)/ddl-s88.Po -rm -f ./$(DEPDIR)/ddl.Po -rm -f ./$(DEPDIR)/ddl_maerklin.Po -rm -f ./$(DEPDIR)/ddl_nmra.Po -rm -f ./$(DEPDIR)/hsi-88.Po -rm -f ./$(DEPDIR)/i2c-dev.Po -rm -f ./$(DEPDIR)/ib.Po -rm -f ./$(DEPDIR)/io.Po -rm -f ./$(DEPDIR)/li100-main.Po -rm -f ./$(DEPDIR)/loconet.Po -rm -f ./$(DEPDIR)/loopback.Po -rm -f ./$(DEPDIR)/m605x.Po -rm -f ./$(DEPDIR)/netservice.Po -rm -f ./$(DEPDIR)/portio.Po -rm -f ./$(DEPDIR)/selectrix.Po -rm -f ./$(DEPDIR)/srcp-command.Po -rm -f ./$(DEPDIR)/srcp-descr.Po -rm -f ./$(DEPDIR)/srcp-error.Po -rm -f ./$(DEPDIR)/srcp-fb.Po -rm -f ./$(DEPDIR)/srcp-ga.Po -rm -f ./$(DEPDIR)/srcp-gl.Po -rm -f ./$(DEPDIR)/srcp-gm.Po -rm -f ./$(DEPDIR)/srcp-info.Po -rm -f ./$(DEPDIR)/srcp-lock.Po -rm -f ./$(DEPDIR)/srcp-power.Po -rm -f ./$(DEPDIR)/srcp-server.Po -rm -f ./$(DEPDIR)/srcp-session.Po -rm -f ./$(DEPDIR)/srcp-sm.Po -rm -f ./$(DEPDIR)/srcp-time.Po -rm -f ./$(DEPDIR)/srcpd.Po -rm -f ./$(DEPDIR)/syslogmessage.Po -rm -f ./$(DEPDIR)/toolbox.Po -rm -f ./$(DEPDIR)/ttycygwin.Po -rm -f ./$(DEPDIR)/zimo.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-sbinPROGRAMS .MAKE: all install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-generic clean-sbinPROGRAMS cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-hdr \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-sbinPROGRAMS .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: srcpd-2.1.7/src/srcp-gl.c0000664000175000017500000003533214017530561012071 00000000000000/* $Id: srcp-gl.c 1765 2021-03-02 21:43:13Z gscholz $ */ #include #include #include #include "config-srcpd.h" #include "srcp-gl.h" #include "srcp-error.h" #include "srcp-info.h" #include "syslogmessage.h" #define QUEUELEN 50 /* complete GL device group data set */ static gl_t gl[MAX_BUSES]; /* command queues for each bus */ static gl_data_t queue[MAX_BUSES][QUEUELEN]; static pthread_mutex_t queue_mutex[MAX_BUSES]; /* write position for queue writers */ static int out[MAX_BUSES], in[MAX_BUSES]; /* forward declaration of internal functions */ static int queue_len(bus_t busnumber); static int queue_isfull(bus_t busnumber); /** * isValidGL: checks if a given address could be a valid GL. * returns true or false. false, if not all requirements are met. */ bool isValidGL(bus_t busnumber, int addr) { /* in bus 0 GL are not allowed */ /* only num_buses are configured */ /* number of GL is set */ /* address must be greater 0 */ /* but not more than the maximum address on that bus */ return (busnumber <= num_buses && gl[busnumber].glcount > 0 && addr > 0 && addr <= gl[busnumber].glcount); } /** * getMaxAddrGL: returns the maximum address for GL on the given bus * returns: =0: no GL on that bus, or busid not valid * >0: maximum address */ unsigned int getMaxAddrGL(bus_t busnumber) { if (busnumber <= num_buses) { return gl[busnumber].glcount; } return 0; } /* there are decoders for 14, 27, 28 and 128 speed steps */ static int calcspeed(int vs, int vmax, int n_fs) { int rs; if (vmax == 0) return vs; if (vs < 0) vs = 0; if (vs > vmax) vs = vmax; /* rs = (vs * n_fs) / vmax; */ /* for test: rs = ((vs * n_fs) / v_max) + 0.5 */ /* ==> rs = ((2 * vs * n_fs) + v_max) / (2 * v_max) */ rs = vs * n_fs; /* vs * n_fs */ rs <<= 1; /* 2 * vs * n_fs */ rs += vmax; /* (2 * vs * n_fs) + v_max */ rs /= vmax; /* ((2 * vs * n_fs) + v_max) / v_max */ rs >>= 1; /* ((2 * vs * n_fs) + v_max) / (2 * v_max) */ if ((rs == 0) && (vs != 0)) rs = 1; return rs; } /* checks whether a GL is already initialized or not * returns false even, if it is an invalid address! */ bool isInitializedGL(bus_t busnumber, int addr) { if (isValidGL(busnumber, addr)) { return (gl[busnumber].glstate[addr].state == glsActive); } return false; } /* Take new locomotive data and make some checks. * Lock is ignored! Lock is payed attention to in SRCP procedures, here not * necessary (emergency stop) */ int enqueueGL(bus_t busnumber, int addr, int dir, int speed, int maxspeed, int f) { if (!isValidGL(busnumber, addr)) return SRCP_WRONGVALUE; int result; struct timeval now; if (!isInitializedGL(busnumber, addr)) { cacheInitGL(busnumber, addr, 'P', 1, 14, 1); syslog_bus(busnumber, DBG_WARN, "GL default init for %d-%d", busnumber, addr); } if (queue_isfull(busnumber)) { syslog_bus(busnumber, DBG_WARN, "GL command queue full"); return SRCP_TEMPORARILYPROHIBITED; } result = pthread_mutex_lock(&queue_mutex[busnumber]); if (result != 0) { syslog_bus(busnumber, DBG_ERROR, "pthread_mutex_lock() failed: %s (errno = %d).", strerror(result), result); } /* copy all known (INIT) values to queue */ queue[busnumber][in[busnumber]] = gl[busnumber].glstate[addr]; /* update remaining new variables */ queue[busnumber][in[busnumber]].speed = calcspeed(speed, maxspeed, gl[busnumber].glstate[addr].n_fs); queue[busnumber][in[busnumber]].direction = dir; queue[busnumber][in[busnumber]].funcs = f; gettimeofday(&now, NULL); queue[busnumber][in[busnumber]].tv = now; queue[busnumber][in[busnumber]].id = addr; in[busnumber]++; if (in[busnumber] == QUEUELEN) in[busnumber] = 0; result = pthread_mutex_unlock(&queue_mutex[busnumber]); if (result != 0) { syslog_bus(busnumber, DBG_ERROR, "pthread_mutex_unlock() failed: %s (errno = %d).", strerror(result), result); } /* Restart thread to send GL command */ resume_bus_thread(busnumber); return SRCP_OK; } int queue_GL_isempty(bus_t busnumber) { return (in[busnumber] == out[busnumber]); } static int queue_len(bus_t busnumber) { if (in[busnumber] >= out[busnumber]) return in[busnumber] - out[busnumber]; else return QUEUELEN + in[busnumber] - out[busnumber]; } /* maybe, 1 element in the queue cannot be used.. */ static int queue_isfull(bus_t busnumber) { return queue_len(busnumber) >= QUEUELEN - 1; } /** result is next item or -1, updates fifo pointer! */ int dequeueNextGL(bus_t busnumber, gl_data_t *gld) { if (in[busnumber] == out[busnumber]) return -1; *gld = queue[busnumber][out[busnumber]]; out[busnumber]++; if (out[busnumber] == QUEUELEN) out[busnumber] = 0; return out[busnumber]; } int cacheGetGL(bus_t busnumber, int addr, gl_data_t *gld) { if (!isInitializedGL(busnumber, addr)) return SRCP_NODATA; *gld = gl[busnumber].glstate[addr]; return SRCP_OK; } /** * cacheSetGL is called from the hardware drivers to keep the * the data and the info mode informed. It is called from * within the SRCP SET Command code. * It respects the TERM function. */ int cacheSetGL(bus_t busnumber, int addr, gl_data_t l) { if (!isValidGL(busnumber, addr)) return SRCP_WRONGVALUE; char msg[1000]; gl[busnumber].glstate[addr] = l; gettimeofday(&gl[busnumber].glstate[addr].tv, NULL); if (gl[busnumber].glstate[addr].state == glsTerm) { snprintf(msg, sizeof(msg), "%lu.%.3lu 102 INFO %ld GL %d\n", gl[busnumber].glstate[addr].tv.tv_sec, gl[busnumber].glstate[addr].tv.tv_usec / 1000, busnumber, addr); bzero(&gl[busnumber].glstate[addr], sizeof(gl_data_t)); } else { cacheInfoGL(busnumber, addr, msg); } enqueueInfoMessage(msg); return SRCP_OK; } int cacheInitGL(bus_t busnumber, int addr, const char protocol, int protoversion, int n_fs, int n_func) { if (!isValidGL(busnumber, addr)) return SRCP_WRONGVALUE; char msg[1000]; gl_data_t tgl; memset(&tgl, 0, sizeof(tgl)); int rc = bus_supports_protocol(busnumber, protocol); if (rc != SRCP_OK) { return rc; } gettimeofday(&tgl.inittime, NULL); tgl.tv = tgl.inittime; tgl.n_fs = n_fs; tgl.n_func = n_func; tgl.protocolversion = protoversion; tgl.protocol = protocol; tgl.id = addr; if (buses[busnumber].init_gl_func) rc = (*buses[busnumber].init_gl_func) (&tgl); if (rc == SRCP_OK) { gl[busnumber].glstate[addr] = tgl; gl[busnumber].glstate[addr].state = glsActive; cacheDescribeGL(busnumber, addr, msg); enqueueInfoMessage(msg); } return rc; } int cacheTermGL(bus_t busnumber, int addr) { if (!isInitializedGL(busnumber, addr)) return SRCP_NODATA; gl_data_t *gld = &gl[busnumber].glstate[addr]; /*we are terminating now*/ gld->state = glsTerm; /* first brake if current speed != 0 */ if (gld->speed != 0) { gld->speed = 0; gld->direction = 2; enqueueGL(busnumber, addr, gld->direction, gld->speed, gld->n_fs, gld->funcs); } /* second terminate GL */ char msg[256]; gettimeofday(&gld->tv, NULL); snprintf(msg, sizeof(msg), "%lu.%.3lu 102 INFO %ld GL %d\n", gld->tv.tv_sec, gld->tv.tv_usec / 1000, busnumber, addr); enqueueInfoMessage(msg); /* third clear GL data */ memset(gld, 0, sizeof(gl_data_t)); return SRCP_OK; } /* * RESET a GL to its defaults */ int resetGL(bus_t busnumber, int addr) { if (!isInitializedGL(busnumber, addr)) return SRCP_NODATA; enqueueGL(busnumber, addr, 0, 0, 1, 0); return SRCP_OK; } void cacheCleanGL(bus_t bus) { for (unsigned int i = 1; i <= gl[bus].glcount; i++) { bzero(&gl[bus].glstate[i], sizeof(gl_data_t)); } } int cacheDescribeGL(bus_t busnumber, int addr, char *msg) { if (!isInitializedGL(busnumber, addr)) { strcpy(msg, ""); return SRCP_NODATA; } gl_data_t* gld = &gl[busnumber].glstate[addr]; sprintf(msg, "%lu.%.3lu 101 INFO %ld GL %d %c %d %d %d\n", gld->inittime.tv_sec, gld->inittime.tv_usec / 1000, busnumber, addr, gld->protocol, gld->protocolversion, gld->n_fs, gld->n_func); return SRCP_INFO; } int cacheInfoGL(bus_t busnumber, int addr, char *msg) { if (!isInitializedGL(busnumber, addr)) return SRCP_NODATA; char line[MAXSRCPLINELEN]; gl_data_t* gld = &gl[busnumber].glstate[addr]; sprintf(msg, "%lu.%.3lu 100 INFO %ld GL %d %d %d %d %d", gld->tv.tv_sec, gld->tv.tv_usec / 1000, busnumber, addr, gld->direction, gld->speed, gld->n_fs, (gld->funcs & 0x01) ? 1 : 0); for (int i = 1; i < gld->n_func; i++) { snprintf(line, sizeof(line), "%s %d", msg, ((gld->funcs >> i) & 0x01) ? 1 : 0); strcpy(msg, line); } snprintf(line, sizeof(line), "%s\n", msg); strcpy(msg, line); return SRCP_INFO; } /* has to use a semaphore, must be atomized! */ int cacheLockGL(bus_t busnumber, int addr, long int duration, sessionid_t sessionid) { if (!isInitializedGL(busnumber, addr)) return SRCP_WRONGVALUE; char msg[256]; gl_data_t *gld = &gl[busnumber].glstate[addr]; if (gld->locked_by == sessionid || gld->locked_by == 0) { gld->locked_by = sessionid; gld->lockduration = duration; gettimeofday(&gld->locktime, NULL); describeLOCKGL(busnumber, addr, msg); enqueueInfoMessage(msg); return SRCP_OK; } return SRCP_DEVICELOCKED; } int cacheGetLockGL(bus_t busnumber, int addr, sessionid_t * session_id) { if (!isInitializedGL(busnumber, addr)) return SRCP_WRONGVALUE; *session_id = gl[busnumber].glstate[addr].locked_by; return SRCP_OK; } int describeLOCKGL(bus_t busnumber, int addr, char *reply) { if (!isInitializedGL(busnumber, addr)) return SRCP_WRONGVALUE; gl_data_t *gld = &gl[busnumber].glstate[addr]; sprintf(reply, "%lu.%.3lu 100 INFO %ld LOCK GL %d %ld %ld\n", gld->locktime.tv_sec, gld->locktime.tv_usec / 1000, busnumber, addr, gld->lockduration, gld->locked_by); return SRCP_OK; } int cacheUnlockGL(bus_t busnumber, int addr, sessionid_t sessionid) { if (!isInitializedGL(busnumber, addr)) return SRCP_WRONGVALUE; gl_data_t *gld = &gl[busnumber].glstate[addr]; if (gld->locked_by == 0 || gld->locked_by == sessionid) { char msg[256]; gld->locked_by = 0; gettimeofday(&gld->locktime, NULL); sprintf(msg, "%lu.%.3lu 102 INFO %ld LOCK GL %d\n", gld->locktime.tv_sec, gld->locktime.tv_usec / 1000, busnumber, addr); enqueueInfoMessage(msg); return SRCP_OK; } return SRCP_DEVICELOCKED; } /** * called when a session is terminating */ void unlock_gl_bysessionid(sessionid_t sessionid) { syslog_session(sessionid, DBG_DEBUG, "Unlocking GLs by session-id"); for (bus_t i = 0; i <= num_buses; i++) { int number = getMaxAddrGL(i); for (int j = 1; j <= number; j++) { if (gl[i].glstate[j].locked_by == sessionid) { cacheUnlockGL(i, j, sessionid); } } } } /** * called once per second to unlock */ void unlock_gl_bytime(void) { for (bus_t i = 0; i <= num_buses; i++) { int number = getMaxAddrGL(i); for (int j = 1; j <= number; j++) { if (gl[i].glstate[j].lockduration > 0 && gl[i].glstate[j].lockduration-- == 1) { cacheUnlockGL(i, j, gl[i].glstate[j].locked_by); } } } } /** * First initialisation after program start up */ void startup_GL() { for (bus_t i = 0; i < MAX_BUSES; i++) { in[i] = 0; out[i] = 0; gl[i].glcount = 0; gl[i].glstate = NULL; int result = pthread_mutex_init(&queue_mutex[i], NULL); if (result != 0) { syslog_bus(0, DBG_ERROR, "pthread_mutex_init() failed: %s (errno = %d).", strerror(result), result); } } } /*destroy all occupied mutexes*/ void shutdown_GL() { for (bus_t i = 0; i < MAX_BUSES; i++) { free(gl[i].glstate); int result = pthread_mutex_destroy(&queue_mutex[i]); if (result != 0) { syslog_bus(0, DBG_ERROR, "pthread_mutex_destroy() failed: %s (errno = %d).", strerror(result), result); } } } /** * allocate memory for all single GL devices used by this bus, * called by configuration routines * return values: * 1: bus > maxbuses, memory accoration error * 0: success */ int init_GL(bus_t busnumber, unsigned int count) { syslog_bus(busnumber, DBG_INFO, "init GL: %d", count); if (busnumber >= MAX_BUSES) return 1; if (count > 0) { gl[busnumber].glstate = malloc((count + 1) * sizeof(gl_data_t)); if (gl[busnumber].glstate == NULL) return 1; gl[busnumber].glcount = count; for (unsigned int i = 0; i <= count; i++) { bzero(&gl[busnumber].glstate[i], sizeof(gl_data_t)); } } return 0; } void debugGL(bus_t busnumber, int start, int end) { gl_data_t *gld; syslog_bus(busnumber, DBG_WARN, "debug GLSTATE from %d to %d", start, end); for (int i = start; i <= end; i++) { gld = &gl[busnumber].glstate[i]; syslog_bus(busnumber, DBG_WARN, "GLSTATE for %d/%d", busnumber, i); syslog_bus(busnumber, DBG_WARN, "state %d", gld->state); syslog_bus(busnumber, DBG_WARN, "protocol %c", gld->protocol); syslog_bus(busnumber, DBG_WARN, "protocolversion %d", gld->protocolversion); syslog_bus(busnumber, DBG_WARN, "n_func %d", gld->n_func); syslog_bus(busnumber, DBG_WARN, "n_fs %d", gld->n_fs); syslog_bus(busnumber, DBG_WARN, "id %d", gld->id); syslog_bus(busnumber, DBG_WARN, "speed %d", gld->speed); syslog_bus(busnumber, DBG_WARN, "direction %d", gld->direction); syslog_bus(busnumber, DBG_WARN, "funcs %d", gld->funcs); syslog_bus(busnumber, DBG_WARN, "lockduration %ld", gld->lockduration); syslog_bus(busnumber, DBG_WARN, "locked_by %ld", gld->locked_by); } } srcpd-2.1.7/src/ddl_nmra.c0000644000175000017500000017044112300743360012275 00000000000000/* +----------------------------------------------------------------------+ */ /* | DDL - Digital Direct for Linux | */ /* +----------------------------------------------------------------------+ */ /* | Copyright (c) 2002 - 2003 Vogt IT | */ /* +----------------------------------------------------------------------+ */ /* | This source file is subject of the GNU general public license 2, | */ /* | that is bundled with this package in the file COPYING, and is | */ /* | available at through the world-wide-web at | */ /* | http://www.gnu.org/licenses/gpl.txt | */ /* | If you did not receive a copy of the PHP license and are unable to | */ /* | obtain it through the world-wide-web, please send a note to | */ /* | gpl-license@vogt-it.com so we can mail you a copy immediately. | */ /* +----------------------------------------------------------------------+ */ /* | Authors: Torsten Vogt vogt@vogt-it.com | */ /* | For more read ChangeLog file | */ /* +----------------------------------------------------------------------+ */ /***************************************************************/ /* erddcd - Electric Railroad Direct Digital Command Daemon */ /* generates without any other hardware digital commands */ /* to control electric model railroads */ /* */ /* file: nmra.c */ /* job : implements routines to compute data for the */ /* NMRA-DCC protocol and send this data to */ /* the serial device. */ /* */ /* Torsten Vogt, may 1999 */ /* */ /* last changes: Torsten Vogt, September 2000 */ /* Torsten Vogt, January 2001 */ /* Torsten Vogt, April 2001 */ /* For more read ChangeLog file */ /***************************************************************/ /********************************************************************** data format: look at the srcp specification protocol formats: N: NMRA multi function decoder with 7/14-bit address, 14/28/128 speed steps (implemented) NA: accessory digital decoders (implemented) service mode instruction packets for direct mode (verify cv, write cv, cv bit manipulation) (implemented) service mode instruction packets for PoM mode (verify cv, write cv, cv bit manipulation) (only write implemented) service mode instruction packets for address-only mode (verify address contents, write address contents) (implemented) service mode instruction packets for physical register addressing (verify register contents, write register contents) (implemented) service mode instruction packets paged cv addressing (verify/write register/cv contents) (implemented) general notes: configuration of the serial port: start bit: 1 stop bit : 1 data bits: 8 baud rate: 19200 ==> one serial bit takes 52.08 usec. ==> NMRA-1-Bit: 01 (52 usec low and 52 usec high) NMRA-0-Bit: 0011 (at least 100 usec low and high) serial stream (only start/stop bits): 0_______10_______10_______10_______10_______10_______10___ ... problem: how to place the NMRA-0- and NMRA-1-Bits in the serial stream examples: 0 0xF0 _____----- 00 0xC6 __--___--- 01 0x78 ____----_- 10 0xE1 _-____---- 001 0x66 __--__--_- 010 0x96 __--_-__-- 011 0x5C ___---_-_- 100 0x99 _-__--__-- 101 0x71 _-___---_- 110 0xC5 _-_-___--- 0111 0x56 __--_-_-_- 1011 0x59 _-__--_-_- 1101 0x65 _-_-__--_- 1110 0x95 _-_-_-__-- 11111 0x55 _-_-_-_-_- ^ ^ start- stop- bit bit known bugs (of version 1 of the NMRA dcc translation routine): (i hope version 2 don't have these bugs ;-) ) following packets are not translatable: N1 031 1 06 0 0 0 0 0 N1 047 0 07 0 0 0 0 0 N2 031 0 091 0 0 0 0 0 N2 031 1 085 0 0 0 0 0 N2 031 1 095 0 0 0 0 0 N2 047 0 107 0 0 0 0 0 N2 047 1 103 0 0 0 0 0 N2 047 1 111 0 0 0 0 0 N2 048 1 112 0 0 0 0 0 N2 051 1 115 0 0 0 0 0 N2 053 1 117 0 0 0 0 0 N2 056 0 124 0 0 0 0 0 N2 057 1 113 0 0 0 0 0 N2 058 1 114 0 0 0 0 0 N2 059 1 115 0 0 0 0 0 N2 060 1 116 0 0 0 0 0 N2 061 1 117 0 0 0 0 0 N2 062 1 118 0 0 0 0 0 I think, that these are not really problems. The only consequence is e.g. that some addresses has 127 speed steps instead of 128. That's life, don't worry. New: completely new algorithm to generate the NMRA packet stream (i call it 'version 3' of the translate routines) The idea in this approach to generate NMRA patterns is, to split the starting and ending bit in each pattern and share it with the next pattern. Therefore the patterns, which could be generated, are coded with h, H, l and L, lowercase describing the half bits. The longest possible pattern contains two half h bits and four H bits. For the access into the coding table, the index of course doesn't differentiate between half and full bits, because the first one is always half and the last one determined by this table. This table shows, which bit pattern will be replaced by which pattern on the serial line. There is only one pattern left, which could not be directly translated. This pattern starts with an h, so we have to look at the patterns, which end with an h, if we want to avoid this pattern. All of the patterns, we access in the first try, contain an l or an L, which could be enlarged, to get rid of at least on bit in this pattern and don't have our problem in the next pattern. With the only exception of hHHHHh, but this pattern simply moves our problem into one byte before or up to the beginning of the sequence. And there, we could always add a bit. So we are sure, to be able, to translate any given sequence of bits. Because only the case of hHHHHh really requires 6 bits, the translation table could be left at 32 entries. The other case, which has the same first five bits is our problem, so we have to handle it separately anyway. Of course the resulting sequence is not dc free. But if this is required, one could replace the bytes in the TranslateData by an index in another table which holds for each data containing at least an L or two l replacements with different dc components. This way one could get a dc free signal or at will a signal with a given dc part. #define ll 0xf0 _____----- #define lLl 0xcc ___--__--- 000000 000001 000010 000011 000100 000101 000110 000111 #define lHl 0xe8 ____-_---- #define lHLl 0x9a __-_--__-- 010000 010001 010010 010011 #define lLHl 0xa6 __--__-_-- 001000 001001 001010 001011 #define lHHl 0xd4 ___-_-_--- 011000 011001 011010 011011 #define lHHHl 0xaa __-_-_-_-- #define lh 0x00 _________- #define lLh 0x1c ___---___- #define lHh 0x40 _______-_- #define lLHh 0x4c ___--__-_- 001100 001101 001110 001111 #define lHLh 0x34 ___-_--__- 010100 010101 010110 010111 #define lHHh 0x50 _____-_-_- 011100 011101 #define lHHHh 0x54 ___-_-_-_- 011110 011111 #define hLh 0x0f _----____- #define hHLh 0x1d _-_---___- 110100 110101 #define hLHh 0x47 _---___-_- 101100 101101 #define hHHLh 0x35 _-_-_--__- 111010 111011 #define hHLHh 0x4d _-_--__-_- 110110 110111 #define hLHHh 0x53 _--__-_-_- 101110 101111 #define hHHHHh 0x55 _-_-_-_-_- 111111 #define hl 0xff _--------- #define hLl 0xc7 _---___--- 100000 100001 100010 100011 100100 100101 100110 100111 #define hHl 0xfd _-_------- #define hHLl 0xcd _-_--__--- 110000 110001 110010 110011 #define hLHl 0xD3 _--__-_--- 101000 101001 101010 101011 #define hHHl 0xF5 _-_-_----- 111000 111001 #define hHHHl 0xd5 _-_-_-_--- 111100 111101 not directly translatable 111110 ****************************************************************/ #define ll 0xf0 #define lLl 0xcc #define lHl 0xe8 #define lHLl 0x9a #define lLHl 0xa6 #define lHHl 0xd4 #define lHHHl 0xaa #define lh 0x00 #define lLh 0x1c #define lHh 0x40 #define lLHh 0x4c #define lHLh 0x34 #define lHHh 0x50 #define lHHHh 0x54 #define hLh 0x0f #define hHLh 0x1d #define hLHh 0x47 #define hHHLh 0x35 #define hHLHh 0x4d #define hLHHh 0x53 #define hHHHHh 0x55 #define hl 0xff #define hLl 0xc7 #define hHl 0xfd #define hHLl 0xcd #define hLHl 0xD3 #define hHHl 0xF5 #define hHHHl 0xd5 #include #include "ddl.h" #include "ddl_nmra.h" #include "syslogmessage.h" typedef struct { char *pattern; int patternlength; int value; } tTranslateData; typedef struct { int value; int patternlength; } tTranslateData_v3; static const tTranslateData TranslateData[] = { {"0", 1, 0xF0}, {"00", 2, 0xC6}, {"01", 2, 0x78}, {"10", 2, 0xE1}, {"001", 3, 0x66}, {"010", 3, 0x96}, {"011", 3, 0x5C}, {"100", 3, 0x99}, {"101", 3, 0x71}, {"110", 3, 0xC5}, {"0111", 4, 0x56}, {"1011", 4, 0x59}, {"1101", 4, 0x65}, {"1110", 4, 0x95}, {"11111", 5, 0x55} }; /* number of translatable patterns */ static int DataCnt = sizeof(TranslateData) / sizeof(TranslateData[0]); static const tTranslateData_v3 TranslateData_v3[32][2] = { {{lLl, 2}, {ll, 1}}, {{lLl, 2}, {ll, 1}}, {{lLl, 2}, {ll, 1}}, {{lLl, 2}, {ll, 1}}, {{lLHl, 3}, {lLh, 2}}, {{lLHl, 3}, {lLh, 2}}, {{lLHh, 3}, {lLh, 2}}, {{lLHh, 3}, {lLh, 2}}, {{lHLl, 3}, {lHl, 2}}, {{lHLl, 3}, {lHl, 2}}, {{lHLh, 3}, {lHl, 2}}, {{lHLh, 3}, {lHl, 2}}, {{lHHl, 3}, {lHh, 2}}, {{lHHl, 3}, {lHh, 2}}, {{lHHh, 3}, {lHh, 2}}, {{lHHHh, 4}, {lHHh, 3}}, {{hLl, 2}, {hl, 1}}, {{hLl, 2}, {hl, 1}}, {{hLl, 2}, {hl, 1}}, {{hLl, 2}, {hl, 1}}, {{hLHl, 3}, {hLh, 2}}, {{hLHl, 3}, {hLh, 2}}, {{hLHh, 3}, {hLh, 2}}, {{hLHHh, 4}, {hLHh, 3}}, {{hHLl, 3}, {hHl, 2}}, {{hHLl, 3}, {hHl, 2}}, {{hHLh, 3}, {hHl, 2}}, {{hHLHh, 4}, {hHLh, 3}}, {{hHHl, 3}, {hHHl, 3}}, {{hHHLh, 4}, {hHHl, 3}}, {{hHHHl, 4}, {hHHHl, 4}}, {{hHHHHh, 5}, {hHHHHh, 5}} }; static char *preamble = "111111111111111"; static const int NMRA_STACKSIZE = 200; /* 230 is needed for all functions F0-F28 */ static const unsigned int BUFFERSIZE = 1000; /* internal offset of the long addresses */ static const unsigned int ADDR14BIT_OFFSET = 128; /* the result is only an index, no warranty */ static int translateabel(char *bs) { int i; size_t size; char *pbs; size = strlen(bs); for (i = (DataCnt - 1); i >= 0; i--) { pbs = bs + (size - TranslateData[i].patternlength); if (strcmp(pbs, TranslateData[i].pattern) == 0) return 1; } return 0; } static int read_next_six_bits(char *Bitstream) { int i, bits = 0; for (i = 0; i < 6; i++) bits = (bits << 1) | (*Bitstream++ == '0' ? 0 : 1); return bits; } static int translateBitstream2Packetstream_v1(char *Bitstream, char *Packetstream, int force_translation) { char Buffer[BUFFERSIZE]; char *pBs = Buffer; int i; /* decision of each recursion level */ int j = 0; /* index of Packetstream, level of recursion */ int found; /* flag */ int stack[NMRA_STACKSIZE]; /* stack for the i's */ int pstack = 0; /* stack pointer */ int correction = 0; size_t bufsize = 0; int highest_level = 0; /* highest recursion level reached during algo. */ const int max_level_delta = 7; /* additional recursion base, speeds up */ pBs = strncpy(Buffer, Bitstream, BUFFERSIZE - 1); memset(Packetstream, 0, PKTSIZE); i = DataCnt - 1; if (!translateabel(Buffer)) { /* The last bit of the bitstream is always '1'. */ pBs[strlen(pBs) - 1] = 0; correction = 1; } bufsize = strlen(Buffer); while (*pBs) { found = 0; while (i >= 0) { if (strncmp(pBs, TranslateData[i].pattern, TranslateData[i].patternlength) == 0) { found = 1; break; } i--; } if (!found) { /* now backtracking */ pstack--; /* back to last level */ if (pstack >= 0) { /* last level avail.? */ i = stack[pstack]; pBs -= TranslateData[i].patternlength; /* corrections */ j--; if (((highest_level - j) >= max_level_delta) && (!force_translation)) j = 0; i--; /* next try */ } } else { Packetstream[j] = (unsigned char) TranslateData[i].value; j++; if (j > highest_level) highest_level = j; pBs += TranslateData[i].patternlength; stack[pstack] = i; pstack++; i = DataCnt - 1; } if (j >= PKTSIZE - 1 || bufsize == BUFFERSIZE) { syslog(LOG_INFO, "cannot translate bitstream '%s' to NMRA packet", Bitstream); return 0; } if (j <= 0 || pstack < 0 || pstack > NMRA_STACKSIZE - 1) { /* it's nasty, but a try: */ /* leading 1's don't make problems */ strcat(Buffer, "1"); bufsize++; pBs = Buffer; j = 0; pstack = 0; i = DataCnt - 1; correction = 0; /* correction also done */ memset(Packetstream, 0, PKTSIZE); } } if (correction) { Packetstream[j] = (unsigned char) 0x99; /* Now the handling of the */ j++; /* final '1'. See above. */ } return j + 1; /* return number of bytes in packetstream */ } static int translateBitstream2Packetstream_v2(char *Bitstream, char *Packetstream) { int i = DataCnt - 1; /* decision of each recursion level */ int j = 0; /* index of Packetstream, level of recursion */ int found; /* flag */ int stack[PKTSIZE]; /* stack for the i's */ memset(Packetstream, 0, PKTSIZE); while (*Bitstream) { /* Check if the end of the buffer contains only 1s */ if (strlen(Bitstream) <= 5) { if (strncmp(Bitstream, "11111", strlen(Bitstream)) == 0) { /* This is the end */ Packetstream[j++] = (unsigned char) 0x55; return j + 1; } } found = 0; while (i >= 0) { if (strncmp (Bitstream, TranslateData[i].pattern, TranslateData[i].patternlength) == 0) { found = 1; break; } i--; } if (!found) { /* now backtracking */ if (j > 0) { /* last level avail.? */ j--; /* go back */ i = stack[j]; Bitstream -= TranslateData[i].patternlength; /* corrections */ i--; } else { syslog(LOG_INFO, "cannot translate bitstream '%s' to NMRA packet", Bitstream); return 0; } } else { Packetstream[j] = (unsigned char) TranslateData[i].value; Bitstream += TranslateData[i].patternlength; stack[j] = i; j++; i = DataCnt - 1; } /* Check buffer size */ if (j >= PKTSIZE) { syslog(LOG_INFO, "Oops buffer too small - bitstream '%s'", Bitstream); return 0; } } return j + 1; /* return number of bytes in packetstream */ } static int translateBitstream2Packetstream_v3(char *Bitstream, char *Packetstream) { /* This routine assumes, that any Bitstream starts with a 1 Bit. */ /* This could be changed, if necessary */ /* keep room for additional pre and postamble */ char Buffer[BUFFERSIZE + 20]; /* here the real sequence starts */ char *read_ptr = Buffer + 1; /* one more 1 in the beginning for successful restart */ char *restart_read = Buffer; /* this necessary, only to verify our assumptions */ char *last_restart = Buffer - 1; char *buf_end; int restart_packet = 0; int generate_packet = 0; int second_try = false; int act_six; read_ptr = strcpy(Buffer, "11"); /* one bit, to start with a half-bit, so we have to put in the left half */ /* one bit, to be able, to back up one bit, if we run into a 111110 pattern */ strncat(Buffer, Bitstream, BUFFERSIZE - 1); /* for simply testing, whether our job is done */ buf_end = Buffer + strlen(Buffer); strcat(Buffer, "111111"); /* at most six trailing bits are possibly necessary */ memset(Packetstream, 0, PKTSIZE); while (generate_packet < PKTSIZE && read_ptr < buf_end) { act_six = read_next_six_bits(read_ptr); if (act_six == 0x3e /* 111110 */ ) { /*did we reach an untranslatable value */ /* try again from last position, where a shorter translation */ /* could be chosen */ second_try = true; generate_packet = restart_packet; if (restart_read == last_restart) syslog(LOG_INFO, "Sorry, restart algorithm doesn't " "work as expected for NMRA-Packet %s", Bitstream); last_restart = restart_read; read_ptr = restart_read; act_six = read_next_six_bits(read_ptr); } Packetstream[generate_packet] = TranslateData_v3[act_six >> 1][second_try ? 1 : 0].value; if (act_six < 0x3e /* 111110 */ ) { /* is translation fixed up to here ? */ restart_packet = generate_packet; restart_read = read_ptr; } read_ptr += TranslateData_v3[act_six >> 1][second_try ? 1 : 0]. patternlength; generate_packet++; second_try = false; } return generate_packet; /* return number of bytes in packetstream */ } int translateBitstream2Packetstream(bus_t busnumber, char *Bitstream, char *Packetstream, int force_translation) { DDL_DATA *DDL = ((DDL_DATA *) buses[busnumber].driverdata); int NMRADCC_TR_V = DDL->NMRADCC_TR_V; switch (NMRADCC_TR_V) { case 1: return translateBitstream2Packetstream_v1(Bitstream, Packetstream, force_translation); case 2: return translateBitstream2Packetstream_v2(Bitstream, Packetstream); case 3: return translateBitstream2Packetstream_v3(Bitstream, Packetstream); default: return 0; } } /*** Some useful functions to calculate NMRA-DCC bytes (char arrays) ***/ /** Transform the lower 8 bit of the input into a "bitstream" byte @par Input: int value @par Output: char* byte */ static void calc_single_byte(char *byte, int value) { int i; int bit = 0x1; strncpy(byte, "00000000", 8); byte[8] = 0; for (i = 7; i >= 0; i--) { if (value & bit) byte[i] = '1'; bit <<= 1; } } /* calculating address bytes: 11AAAAAA AAAAAAAA */ static void calc_14bit_address_byte(char *byte1, char *byte2, int address) { calc_single_byte(byte2, address); calc_single_byte(byte1, 0xc0 | (address >> 8)); } /* calculating speed byte2: 01DUSSSS */ static void calc_baseline_speed_byte(char *byte, int direction, int speed, int func) { calc_single_byte(byte, 0x40 | (direction << 5) | speed); if (func & 1) byte[3] = '1'; } /* calculating speed byte: 01DSSSSS */ static void calc_28spst_speed_byte(char *byte, int direction, int speed) { /* last significant speed bit is at pos 3 */ if (speed > 1) { speed += 2; calc_single_byte(byte, 0x40 | (direction << 5) | (speed >> 1)); if (speed & 1) { byte[3] = '1'; } } else { calc_single_byte(byte, 0x40 | (direction << 5) | speed); } } /* calculating function byte: 100DDDDD */ static void calc_function_group_one_byte(char *byte, int func) { /* mask out lower 5 function bits */ func &= 0x1f; calc_single_byte(byte, 0x80 | (func >> 1)); /* F0 or FL is out of order */ if (func & 1) byte[3] = '1'; } /* calculating function byte: 101SDDDD */ static void calc_function_group_two_byte(char *byte, int func, int lower) { if (lower) { /* shift func bits to lower 4 bits and mask them */ func = (func >> 5) & 0xf; /* set command for F5 to F8 */ func |= 0xb0; } else { func = (func >> 9) & 0xf; func |= 0xa0; } calc_single_byte(byte, func); } static void calc_128spst_adv_op_bytes(char *byte1, char *byte2, int direction, int speed) { strcpy(byte1, "00111111"); calc_single_byte(byte2, speed); if (direction == 1) byte2[0] = '1'; } static void xor_two_bytes(char *byte, char *byte1, char *byte2) { int i; for (i = 0; i < 8; i++) { if (byte1[i] == byte2[i]) byte[i] = '0'; else byte[i] = '1'; } byte[8] = 0; } /*** functions to generate NMRA-DCC data packets ***/ int comp_nmra_accessory(bus_t busnumber, int nr, int output, int activate, int offset) { /* command: NA example: NA 0012 0 1 */ char byte1[9]; char byte2[9]; char byte3[9]; char bitstream[BUFFERSIZE]; char packetstream[PKTSIZE]; char *p_packetstream; int address = 0; /* of the decoder */ int pairnr = 0; /* decoders have pair of outputs */ int j; syslog_bus(busnumber, DBG_DEBUG, "command for NMRA protocol for accessory decoders " "(NA) received"); /* no special error handling, it's job of the clients */ if (nr < 1 || nr > 2044 || output < 0 || output > 1 || activate < 0 || activate > 1) return 1; /* packet is not available */ p_packetstream = packetstream; /* calculate the real address of the decoder and the pair number * of the switch */ /* valid decoder addresses: 0..511 */ address = ((nr - 1) / 4) + offset; pairnr = (nr - 1) % 4; /* address byte: 10AAAAAA (lower 6 bits) */ calc_single_byte(byte1, 0x80 | (address & 0x3f)); /* address and data 1AAACDDO upper 3 address bits are inverted */ /* C = activate, DD = pairnr */ calc_single_byte(byte2, 0x80 | ((~address) & 0x1c0) >> 2 | activate << 3 | pairnr << 1 | output); xor_two_bytes(byte3, byte2, byte1); /* putting all together in a 'bitstream' (char array) */ memset(bitstream, 0, BUFFERSIZE); strcat(bitstream, preamble); strcat(bitstream, "0"); strcat(bitstream, byte1); strcat(bitstream, "0"); strcat(bitstream, byte2); strcat(bitstream, "0"); strcat(bitstream, byte3); strcat(bitstream, "1"); j = translateBitstream2Packetstream(busnumber, bitstream, packetstream, true); if (j > 0) { queue_add(busnumber, address, p_packetstream, QNBACCPKT, j); #if 0 /* GA Packet Cache */ updateNMRAGaPacketPool(nr, output, activate, p_packetstream, j); #endif return 0; } return 1; } /** Calculate up to 4 command sequences depending on the number of possible functions (taken from INIT GL ...) for up to 28 Functions due to the long bitstream in case of 28 functions the bitstream is split into to parts. @par Input: char *addrerrbyte Error detection code for address bytes(s) char *addrstream "bitstream" for preamble and the address byte(s) int func function bits int nfuncs number of functions @par Output: char* bitstream the resulting "bitstream" @par Output: char* bitstream2 the second "bitstream" */ static void calc_function_stream(char *bitstream, char *bitstream2, char *addrerrbyte, char *addrstream, int func, int nfuncs) { char funcbyte[9]; char errdbyte[9]; /* between two commands to the same address there has to be a gap of at least 5ms. 5ms are 10 packet bytes. one packet byte can take 5 logical "1" (0x55) ==> 50 logical "1" are needed between 2 packets. The preamble holds 15 "1"s, so only 35 additional are needed */ char wait[40] = "11111111111111111111111111111111111"; calc_function_group_one_byte(funcbyte, func); xor_two_bytes(errdbyte, addrerrbyte, funcbyte); /* putting all together in a 'bitstream' (char array) (functions) */ memset(bitstream2, 0, BUFFERSIZE); strcat(bitstream2, addrstream); strcat(bitstream2, funcbyte); strcat(bitstream2, "0"); strcat(bitstream2, errdbyte); strcat(bitstream2, "1"); if (nfuncs > 5) { calc_function_group_two_byte(funcbyte, func, true); xor_two_bytes(errdbyte, addrerrbyte, funcbyte); strcat(bitstream, wait); strcat(bitstream, addrstream); strcat(bitstream, funcbyte); strcat(bitstream, "0"); strcat(bitstream, errdbyte); strcat(bitstream, "1"); if (nfuncs > 8) { calc_function_group_two_byte(funcbyte, func, false); xor_two_bytes(errdbyte, addrerrbyte, funcbyte); strcat(bitstream2, wait); strcat(bitstream2, addrstream); strcat(bitstream2, funcbyte); strcat(bitstream2, "0"); strcat(bitstream2, errdbyte); strcat(bitstream2, "1"); if (nfuncs > 12) { char funcbyte2[9]; strncpy(funcbyte2, "11011110", 8); funcbyte2[8] = 0; calc_single_byte(funcbyte, func >> 13); xor_two_bytes(errdbyte, addrerrbyte, funcbyte2); xor_two_bytes(errdbyte, errdbyte, funcbyte); strcat(bitstream, wait); strcat(bitstream, addrstream); strcat(bitstream, funcbyte2); strcat(bitstream, "0"); strcat(bitstream, funcbyte); strcat(bitstream, "0"); strcat(bitstream, errdbyte); strcat(bitstream, "1"); if (nfuncs > 20) { funcbyte2[7] = '1'; xor_two_bytes(errdbyte, addrerrbyte, funcbyte2); calc_single_byte(funcbyte, func >> 21); xor_two_bytes(errdbyte, errdbyte, funcbyte); strcat(bitstream2, wait); strcat(bitstream2, addrstream); strcat(bitstream2, funcbyte2); strcat(bitstream2, "0"); strcat(bitstream2, funcbyte); strcat(bitstream2, "0"); strcat(bitstream2, errdbyte); strcat(bitstream2, "1"); } } } } } /** Calculate the "bitstream" for the cv programming sequence @par Input: char *addrerrbyte error detection byte of the address byte(s) int cv int value int verify int pom if true generate PoM command @par Output: char* progstream the resulting "bitstream" for the program sequence */ static void calc_byte_program_stream(char *progstream, char *addrerrbyte, int cv, int value, int verify, int pom) { char byte2[9]; char byte3[9]; char byte4[9]; char byte5[9]; memset(progstream, 0, BUFFERSIZE); /* calculating byte3: AAAAAAAA (rest of CV#) */ calc_single_byte(byte3, cv); if (pom) { /* calculating byte2: 1110C1AA (instruction byte1) */ calc_single_byte(byte2, 0xec | (cv >> 8)); } else { /* calculating byte2: 011110AA (instruction byte1) */ calc_single_byte(byte2, 0x7c | (cv >> 8)); } if (verify) { byte2[4] = '0'; } /* calculating byte4: DDDDDDDD (data) */ calc_single_byte(byte4, value); /* calculating byte5: EEEEEEEE (error detection byte) */ xor_two_bytes(byte5, addrerrbyte, byte2); xor_two_bytes(byte5, byte5, byte3); xor_two_bytes(byte5, byte5, byte4); strcat(progstream, byte2); strcat(progstream, "0"); strcat(progstream, byte3); strcat(progstream, "0"); strcat(progstream, byte4); strcat(progstream, "0"); strcat(progstream, byte5); strcat(progstream, "1"); } /** Calculate the "bitstream" for the cvbit programming sequence @par Input: char *addrerrbyte error detection byte of the address byte(s) int cv int value int verify int pom if true generrate PoM command @par Output: char* progstream the resulting "bitstream" for the program sequence */ static void calc_bit_program_stream(char *progstream, char *addrerrbyte, int cv, int bit, int value, int verify, int pom) { char byte2[9]; char byte3[9]; char byte4[9]; char byte5[9]; memset(progstream, 0, BUFFERSIZE); /* calculating byte3: AAAAAAAA (rest of CV#) */ calc_single_byte(byte3, cv); if (pom) { /* calculating byte2: 111010AA (instruction byte1) */ calc_single_byte(byte2, 0xe8 | (cv >> 8)); } else { /* calculating byte2: 011110AA (instruction byte1) */ calc_single_byte(byte2, 0x78 | (cv >> 8)); } /* calculating byte4: 111CDBBB (data) */ calc_single_byte(byte4, 0xf0 | (value << 3) | bit); if (verify) { byte4[3] = '0'; } /* calculating byte5: EEEEEEEE (error detection byte) */ xor_two_bytes(byte5, addrerrbyte, byte2); xor_two_bytes(byte5, byte5, byte3); xor_two_bytes(byte5, byte5, byte4); /* putting all together in a 'bitstream' (char array) */ strcat(progstream, byte2); strcat(progstream, "0"); strcat(progstream, byte3); strcat(progstream, "0"); strcat(progstream, byte4); strcat(progstream, "0"); strcat(progstream, byte5); strcat(progstream, "1"); } /** Calculate the "bitstream" for 7 and 14 bit addresses @par Input: int address int mode 1 = 7 bit, 2 = 14 bit @par Output: char* addrstream the resulting "bitstream" for address byte(s) char* addrerrbyte the "bitstream" for error detection byte */ static void calc_address_stream(char *addrstream, char *addrerrbyte, int address, int mode) { char addrbyte[9]; char addrbyte2[9]; // if (mode == 1 || mode == 2 || mode == 5) { // Torsten Vogt 2012-01-15 if (mode == 1) { // Torsten Vogt 2012-11-10 /* calc 7 bit address - leading bit is zero */ calc_single_byte(addrbyte, address & 0x7f); /* no second byte => error detection byte = addressbyte */ memcpy(addrerrbyte, addrbyte, 9); } else { calc_14bit_address_byte(addrbyte, addrbyte2, address); xor_two_bytes(addrerrbyte, addrbyte, addrbyte2); } /* putting all together in a 'bitstream' (char array) (speed & direction) */ memset(addrstream, 0, BUFFERSIZE); strcat(addrstream, preamble); strcat(addrstream, "0"); strcat(addrstream, addrbyte); strcat(addrstream, "0"); if (mode == 2) { // Torsten Vogt 2012-11-10 strcat(addrstream, addrbyte2); strcat(addrstream, "0"); } } /** Generate the packet for NMRA (multi)-function-decoder with 7-bit or 14-bit address and 14/28 or 128 speed steps and up to 28 functions @par Input: bus_t busnumber int address GL address int direction int speed int func function bits int nspeed number of speeds for this decoder int nfuncs number of functions int mode 1 == short address, 2 == long (2byte) address @return 0 == OK, 1 == Error */ int comp_nmra_multi_func(bus_t busnumber, int address, int direction, int speed, int func, int nspeed, int nfuncs, int mode) { char spdrbyte[9]; char spdrbyte2[9]; char errdbyte[9]; char addrerrbyte[9]; char addrstream[BUFFERSIZE]; char bitstream[BUFFERSIZE]; char bitstream2[BUFFERSIZE]; char packetstream[PKTSIZE]; char packetstream2_buf[PKTSIZE]; char *packetstream2 = packetstream2_buf; int adr = 0; int j, jj; syslog_bus(busnumber, DBG_DEBUG, "command for NMRA protocol (N%d) received \naddr:%d " "dir:%d speed:%d nspeeds:%d nfunc:%d", mode, address, direction, speed, nspeed, nfuncs); adr = address; // adr is an additional identifier, only used to store // the pakets in the internal queue!!!!! // Torsten Vogt, 2012-11-10 if (mode == 2) { adr += ADDR14BIT_OFFSET; } /* no special error handling, it's job of the clients */ // Torsten Vogt, 2012-11-10 if (address < 1 || address > 10239 || direction < 0 || direction > 1 || speed < 0 || speed > (nspeed + 1) || (address > 127 && mode == 1)) return 1; if (speed > 127) { speed = 127; } calc_address_stream(addrstream, addrerrbyte, address, mode); if (speed < 2 || nspeed < 15) { /* commands for stop and emergency stop are identical for 14 and 28 speed steps. All decoders supporting 128 speed steps also have to support 14/28 speed step commands ==> results in shorter refresh cycle if there are many 128 speed steps decoders with speed=0, and a slightly faster emergency stop for these decoders. */ calc_baseline_speed_byte(spdrbyte, direction, speed, func); } else { if (nspeed > 29) { calc_128spst_adv_op_bytes(spdrbyte, spdrbyte2, direction, speed); } else { calc_28spst_speed_byte(spdrbyte, direction, speed); } } xor_two_bytes(errdbyte, addrerrbyte, spdrbyte); memset(bitstream, 0, BUFFERSIZE); strcat(bitstream, addrstream); strcat(bitstream, spdrbyte); strcat(bitstream, "0"); if (nspeed > 29 && speed > 1) { strcat(bitstream, spdrbyte2); strcat(bitstream, "0"); xor_two_bytes(errdbyte, errdbyte, spdrbyte2); } strcat(bitstream, errdbyte); strcat(bitstream, "1"); if (nfuncs && (nspeed > 14)) { calc_function_stream(bitstream, bitstream2, addrerrbyte, addrstream, func, nfuncs); j = translateBitstream2Packetstream(busnumber, bitstream, packetstream, false); jj = translateBitstream2Packetstream(busnumber, bitstream2, packetstream2, false); } else { j = translateBitstream2Packetstream(busnumber, bitstream, packetstream, false); packetstream2 = packetstream; jj = j; } if (j > 0 && jj > 0) { update_NMRAPacketPool(busnumber, adr, packetstream, j, packetstream2, jj); queue_add(busnumber, adr, packetstream, QNBLOCOPKT, j); if (nfuncs && (nspeed > 14)) { queue_add(busnumber, adr, packetstream2, QNBLOCOPKT, jj); } return 0; } return 1; } /** Write a configuration variable (cv) on the Main (operations mode programming). This is very similar to the service mode programming with the extension, that the decoder address is used. I.e. only the cv of the selected decoder is updated not all decoders. @par Input: bus_t busnumber int address int cv int value int mode 1 == short address, 2 == long (2byte) address @return ack */ int protocol_nmra_sm_write_cvbyte_pom(bus_t busnumber, int address, int cv, int value, int mode) { char addrerrbyte[9]; char addrstream[BUFFERSIZE]; char progstream[BUFFERSIZE]; char bitstream[BUFFERSIZE]; char packetstream[PKTSIZE]; int j; int adr = 0; syslog_bus(busnumber, DBG_DEBUG, "command for PoM %d received \naddr:%d CV:%d value:%d", mode, address, cv, value); cv -= 1; if (address < 1 || address > 10239 || cv < 0 || cv > 1023 || value < 0 || value > 255 || (address > 127 && mode == 1)) return 1; adr = address; // adr is an additional identifier, only used to store // the pakets in the internal queue!!!!! // Torsten Vogt, 2012-11-10 if (mode == 2) { // if (mode > 2 && mode < 5) { adr += ADDR14BIT_OFFSET; } calc_address_stream(addrstream, addrerrbyte, address, mode); calc_byte_program_stream(progstream, addrerrbyte, cv, value, false, true); memset(bitstream, 0, BUFFERSIZE); strcat(bitstream, addrstream); strcat(bitstream, progstream); j = translateBitstream2Packetstream(busnumber, bitstream, packetstream, false); if (j > 0) { queue_add(busnumber, adr, packetstream, QNBLOCOPKT, j); return 0; } return 1; } /** Write a single bit of a configuration variable (cv) on the Main. This is very similar to the service mode programming with the extension, that the decoder address is used. I.e. only the cv of the selected decoder is updated not all decoders. @par Input: bus_t busnumber int address int cv int value int mode 1 == short address, 2 == long (2byte) address @return ack */ int protocol_nmra_sm_write_cvbit_pom(bus_t busnumber, int address, int cv, int bit, int value, int mode) { char addrerrbyte[9]; char addrstream[BUFFERSIZE]; char progstream[BUFFERSIZE]; char bitstream[BUFFERSIZE]; char packetstream[PKTSIZE]; int j; int adr = 0; syslog_bus(busnumber, DBG_DEBUG, "command for PoM %d received \naddr:%d CV:%d value:%d", mode, address, cv, value); cv -= 1; /* do not allow to change the address on the main ==> cv 1 is disabled */ if (address < 1 || address > 10239 || cv < 1 || cv > 1023 || bit < 0 || bit > 7 || value < 0 || value > 1 || (address > 127 && mode == 1)) return 1; adr = address; // adr is an additional identifier, only used to store // the pakets in the internal queue!!!!! // Torsten Vogt, 2012-11-10 if (mode == 2) { // if (mode > 2 && mode < 5) { adr += ADDR14BIT_OFFSET; } calc_address_stream(addrstream, addrerrbyte, address, mode); calc_bit_program_stream(progstream, addrerrbyte, cv, bit, value, false, true); memset(bitstream, 0, BUFFERSIZE); strcat(bitstream, addrstream); strcat(bitstream, progstream); j = translateBitstream2Packetstream(busnumber, bitstream, packetstream, false); if (j > 0) { queue_add(busnumber, adr, packetstream, QNBLOCOPKT, j); return 0; } return 1; } /** * The following function(s) supports the implementation of NMRA- * programmers. It is recommended to use a programming track to * program your locos. In every case it is useful to stop the * refresh-cycle on the track when using one of the following * service mode functions. **/ static int sm_initialized = false; static char resetstream[PKTSIZE]; static int rs_size = 0; static char idlestream[PKTSIZE]; static int is_size = 0; static char pagepresetstream[PKTSIZE]; static int ps_size = 0; static char *longpreamble = "111111111111111111111111111111"; static char reset_packet[] = "1111111111111111111111111111110000000000000000000000000001"; static char page_preset_packet[] = "1111111111111111111111111111110011111010000000010011111001"; static char idle_packet[] = "1111111111111111111111111111110111111110000000000111111111"; static void sm_init(bus_t busnumber) { memset(resetstream, 0, PKTSIZE); rs_size = translateBitstream2Packetstream(busnumber, reset_packet, resetstream, false); memset(idlestream, 0, PKTSIZE); is_size = translateBitstream2Packetstream(busnumber, idle_packet, idlestream, false); memset(pagepresetstream, 0, PKTSIZE); ps_size = translateBitstream2Packetstream(busnumber, page_preset_packet, pagepresetstream, true); sm_initialized = true; } /** Check the serial line for an acknowledgment (ack) @par Input: bus_t busnumber @return ack */ static int scanACK(bus_t busnumber) { int result, arg; result = ioctl(buses[busnumber].device.file.fd, TIOCMGET, &arg); if (result == -1) { syslog_bus(busnumber, DBG_ERROR, "ioctl() failed: %s (errno = %d)\n", strerror(errno), errno); } if ((result >= 0) && (!(arg & TIOCM_RI))) return 1; return 0; } /** Wait for the UART to write the packetstream check in the meantime if an ack is set @par Input: bus_t busnumber @return ack */ static int waitUARTempty_scanACK(bus_t busnumber) { int value = 0; int result = 0; int ack = 0; clock_t start = clock(); do { /* wait until UART is empty */ if (scanACK(busnumber)) ack = 1; /* scan ACK */ /* prevent endless loop in case somone turned the power on */ if (buses[busnumber].power_state == 1) { clock_t now = clock(); float diff = (now - start); diff /= CLOCKS_PER_SEC; if (ack) { value = 1; waitUARTempty(busnumber); } /* wait 300ms */ if (diff > 0.3) { waitUARTempty(busnumber); value = 1; } } else { #if linux result = ioctl(buses[busnumber].device.file.fd, TIOCSERGETLSR, &value); #else result = ioctl(buses[busnumber].device.file.fd, TCSADRAIN, &value); #endif } if (result == -1) { syslog_bus(busnumber, DBG_ERROR, "ioctl() failed: %s (errno = %d)\n", strerror(errno), errno); } } while (!value); /* if power is on do not turn it off */ if (!buses[busnumber].power_state) tcflow(buses[busnumber].device.file.fd, TCOOFF); return ack; } /** Check if a given ack is valid an ack is invalid if the line is permanently active @par Input: bus_t busnumber int ack @return ack if valid, 0 otherwise */ static int handleACK(bus_t busnumber, int ack) { if (usleep(5000) == -1) { syslog_bus(busnumber, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } /* ack not supported */ if ((ack == 1) && (scanACK(busnumber) == 1)) { return 0; } /* ack supported ==> send to client */ else return ack; } /** Generate command stream to access a physical register @par Input: bus_t bus int reg int value int verify @par Output:char *packetstream @return length of packetstream */ static int calc_reg_stream(bus_t bus, int reg, int value, int verify, char *packetstream) { char byte1[9]; char byte2[9]; char byte3[9]; char bitstream[BUFFERSIZE]; int j; /* calculating byte1: 0111CRRR (instruction and number of register) */ calc_single_byte(byte1, 0x78 | reg); if (verify) { byte1[4] = '0'; } /* calculating byte2: DDDDDDDD (data) */ calc_single_byte(byte2, value); /* calculating byte3 (error detection byte) */ xor_two_bytes(byte3, byte1, byte2); /* putting all together in a 'bitstream' (char array) */ memset(bitstream, 0, BUFFERSIZE); strcat(bitstream, longpreamble); strcat(bitstream, "0"); strcat(bitstream, byte1); strcat(bitstream, "0"); strcat(bitstream, byte2); strcat(bitstream, "0"); strcat(bitstream, byte3); strcat(bitstream, "1"); memset(packetstream, 0, PKTSIZE); j = translateBitstream2Packetstream(bus, bitstream, packetstream, true); return j; } /** Write or verify a byte of a physical register special case: a write to register 1 is the address only command 0111C000 0AAAAAAA @par Input: bus_t bus int reg int value int verify @return 1 if successful, 0 otherwise */ static int protocol_nmra_sm_phregister(bus_t bus, int reg, int value, int verify) { /* physical register addressing */ char packetstream[PKTSIZE]; char SendStream[4096]; int j, l, y, ack; syslog_bus(bus, DBG_DEBUG, "command for NMRA service mode instruction (SMPRA) received" " REG %d, Value %d", reg, value); /* no special error handling, it's job of the clients */ if (reg < 1 || reg > 8 || value < 0 || value > 255) return -1; if (!sm_initialized) sm_init(bus); reg -= 1; j = calc_reg_stream(bus, reg, value, verify, packetstream); memset(SendStream, 0, 4096); if (!verify) { /* power-on cycle, at least 20 valid packets */ for (l = 0; l < 50; l++) strcat(SendStream, idlestream); /* 3 or more reset packets */ for (l = 0; l < 6; l++) strcat(SendStream, resetstream); /* 5 or more page preset packets */ for (l = 0; l < 10; l++) strcat(SendStream, pagepresetstream); /* 6 or more reset packets */ for (l = 0; l < 12; l++) strcat(SendStream, resetstream); /* 3 or more reset packets */ for (l = 0; l < 12; l++) strcat(SendStream, resetstream); /* 5 or more write packets */ for (l = 0; l < 20; l++) strcat(SendStream, packetstream); /* 6 or more reset or identical write packets */ for (l = 0; l < 24; l++) strcat(SendStream, packetstream); /* 3 or more reset packets */ for (l = 0; l < 24; l++) strcat(SendStream, resetstream); y = 50 * is_size + 54 * rs_size + 44 * j + 10 * ps_size; } else { /* power-on cycle, at least 20 valid packets */ for (l = 0; l < 30; l++) strcat(SendStream, idlestream); /* 3 or more reset packets */ for (l = 0; l < 5; l++) strcat(SendStream, resetstream); /* 7 or more verify packets */ for (l = 0; l < 20; l++) strcat(SendStream, packetstream); y = 30 * is_size + 5 * rs_size + 20 * j + 0; } setSerialMode(bus, SDM_NMRA); tcflow(buses[bus].device.file.fd, TCOON); l = write(buses[bus].device.file.fd, SendStream, y); if (l == -1) { syslog_bus(bus, DBG_ERROR, "write() failed: %s (errno = %d)\n", strerror(errno), errno); } ack = waitUARTempty_scanACK(bus); setSerialMode(bus, SDM_DEFAULT); return handleACK(bus, ack); } /** Write or verify a byte of a physical register using paged mode addressing @par Input: bus_t bus int page int reg int value int verify @return 1 if successful, 0 otherwise */ static int protocol_nmra_sm_page(bus_t bus, int page, int reg, int value, int verify) { /* physical register addressing */ char packetstream[PKTSIZE]; char packetstream_page[PKTSIZE]; char SendStream[4096]; int j, k, l, y, ack; syslog_bus(bus, DBG_DEBUG, "command for NMRA service mode instruction (SMPRA) received" " PAGE %d, REG %d, Value %d", page, reg, value); /* no special error handling, it's job of the clients */ if (reg < 0 || reg > 3 || page < 0 || page > 255 || value < 0 || value > 255) return -1; if (!sm_initialized) sm_init(bus); j = calc_reg_stream(bus, reg, value, verify, packetstream); /* set page to register 6 (number 5) */ k = calc_reg_stream(bus, 5, page, false, packetstream_page); memset(SendStream, 0, 4096); /* power-on cycle, at least 20 valid packets */ for (l = 0; l < 50; l++) strcat(SendStream, idlestream); /* 3 or more reset packets */ for (l = 0; l < 6; l++) strcat(SendStream, resetstream); /* 5 or more writes to the page register */ for (l = 0; l < 10; l++) strcat(SendStream, packetstream_page); /* 6 or more reset packets */ for (l = 0; l < 12; l++) strcat(SendStream, resetstream); /* 3 or more reset packets */ for (l = 0; l < 12; l++) strcat(SendStream, resetstream); /* 5 or more write packets */ for (l = 0; l < 15; l++) strcat(SendStream, packetstream); /* 6 or more reset or identical write packets */ for (l = 0; l < 15; l++) strcat(SendStream, packetstream); /* 3 or more reset packets */ for (l = 0; l < 24; l++) strcat(SendStream, resetstream); y = 50 * is_size + 54 * rs_size + 30 * j + 10 * k; setSerialMode(bus, SDM_NMRA); tcflow(buses[bus].device.file.fd, TCOON); l = write(buses[bus].device.file.fd, SendStream, y); if (l == -1) { syslog_bus(bus, DBG_ERROR, "write() failed: %s (errno = %d)\n", strerror(errno), errno); } ack = waitUARTempty_scanACK(bus); setSerialMode(bus, SDM_DEFAULT); return handleACK(bus, ack); } /** Write a byte to a physical register @par Input: bus_t bus int reg int value @return 1 if successful, 0 otherwise */ int protocol_nmra_sm_write_phregister(bus_t bus, int reg, int value) { return protocol_nmra_sm_phregister(bus, reg, value, false); } /** Check the contens of a physical register @par Input: bus_t bus int reg int value @return 1 if the contens of the register equals reg, 0 otherwise */ int protocol_nmra_sm_verify_phregister(bus_t bus, int reg, int value) { return protocol_nmra_sm_phregister(bus, reg, value, true); } /** Get the contens of a physical register @par Input: bus_t bus int reg @return the value of the register */ int protocol_nmra_sm_get_phregister(bus_t bus, int reg) { int rc; int i; for (i = 0; i < 256; i++) { rc = protocol_nmra_sm_phregister(bus, reg, i, true); if (rc) break; } return i; } /** Verify/write a byte of a configuration variable (cv) @par Input: bus_t busnumber int cv int value int verify @return 1 if successful, 0 otherwise */ static int protocol_nmra_sm_direct_cvbyte(bus_t busnumber, int cv, int value, int verify) { ssize_t result; /* direct cv access */ char bitstream[BUFFERSIZE]; char progstream[BUFFERSIZE]; char packetstream[PKTSIZE]; char SendStream[2048]; char progerrbyte[9]; int j, l, ack = 0; cv -= 1; syslog_bus(busnumber, DBG_DEBUG, "command for NMRA service mode instruction (SMDWY) received"); /* no special error handling, it's job of the clients */ if (cv < 0 || cv > 1024 || value < 0 || value > 255) return -1; /* address only mode */ if (!cv && (value < 128)) { return protocol_nmra_sm_phregister(busnumber, 1, value, verify); } if (!sm_initialized) sm_init(busnumber); /* putting all together in a 'bitstream' (char array) */ strncpy(progerrbyte, "00000000", 8); progerrbyte[8] = 0; calc_byte_program_stream(progstream, progerrbyte, cv, value, verify, false); memset(bitstream, 0, BUFFERSIZE); strcat(bitstream, longpreamble); strcat(bitstream, "0"); strcat(bitstream, progstream); j = translateBitstream2Packetstream(busnumber, bitstream, packetstream, false); memset(SendStream, 0, 2048); if (!verify) { for (l = 0; l < 30; l++) strcat(SendStream, idlestream); for (l = 0; l < 15; l++) strcat(SendStream, resetstream); for (l = 0; l < 20; l++) strcat(SendStream, packetstream); l = 30 * is_size + 15 * rs_size + 20 * j; } else { for (l = 0; l < 30; l++) strcat(SendStream, idlestream); for (l = 0; l < 5; l++) strcat(SendStream, resetstream); for (l = 0; l < 20; l++) strcat(SendStream, packetstream); l = 30 * is_size + 5 * rs_size + 20 * j; } setSerialMode(busnumber, SDM_NMRA); tcflow(buses[busnumber].device.file.fd, TCOON); result = write(buses[busnumber].device.file.fd, SendStream, l); if (result == -1) { syslog_bus(busnumber, DBG_ERROR, "write() failed: %s (errno = %d)\n", strerror(errno), errno); } ack = waitUARTempty_scanACK(busnumber); setSerialMode(busnumber, SDM_DEFAULT); return handleACK(busnumber, ack); } /** Write a byte to a configuration variable (cv) @par Input: bus_t bus int cv int value @return 1 if successful, 0 otherwise */ int protocol_nmra_sm_write_cvbyte(bus_t bus, int cv, int value) { return protocol_nmra_sm_direct_cvbyte(bus, cv, value, false); } /** Verify the content of a configuration variable (cv) @par Input: bus_t bus int cv int value @return 1 if the value matches, 0 otherwise */ int protocol_nmra_sm_verify_cvbyte(bus_t bus, int cv, int value) { return protocol_nmra_sm_direct_cvbyte(bus, cv, value, true); } /** Verify/write a single bit of a configuration variable (cv) @par Input: bus_t bus int cv int bit int value int verify @return 1 if successful, 0 otherwise */ static int protocol_nmra_sm_direct_cvbit(bus_t bus, int cv, int bit, int value, int verify) { ssize_t result; /* direct cv access */ char progerrbyte[9]; char bitstream[BUFFERSIZE]; char progstream[BUFFERSIZE]; char packetstream[PKTSIZE]; char SendStream[2048]; int j, l, ack; cv -= 1; syslog_bus(bus, DBG_DEBUG, "command for NMRA service mode instruction (SMDWB) received"); /* no special error handling, it's job of the clients */ if (cv < 0 || cv > 1023 || bit < 0 || bit > 7 || value < 0 || value > 1) return -1; if (!sm_initialized) sm_init(bus); strncpy(progerrbyte, "00000000", 8); progerrbyte[8] = 0; calc_bit_program_stream(progstream, progerrbyte, cv, bit, value, verify, false); /* putting all together in a 'bitstream' (char array) */ memset(bitstream, 0, BUFFERSIZE); strcat(bitstream, longpreamble); strcat(bitstream, "0"); strcat(bitstream, progstream); j = translateBitstream2Packetstream(bus, bitstream, packetstream, false); memset(SendStream, 0, 2048); for (l = 0; l < 30; l++) strcat(SendStream, idlestream); for (l = 0; l < 15; l++) strcat(SendStream, resetstream); for (l = 0; l < 20; l++) strcat(SendStream, packetstream); l = 30 * is_size + 15 * rs_size + 20 * j; setSerialMode(bus, SDM_NMRA); tcflow(buses[bus].device.file.fd, TCOON); result = write(buses[bus].device.file.fd, SendStream, l); if (result == -1) { syslog_bus(bus, DBG_ERROR, "write() failed: %s (errno = %d)\n", strerror(errno), errno); } ack = waitUARTempty_scanACK(bus); setSerialMode(bus, SDM_DEFAULT); return handleACK(bus, ack); } /** Write a single bit of a configuration variable (cv) @par Input: bus_t bus int cv int bit int value @return 1 if successful, 0 otherwise */ int protocol_nmra_sm_write_cvbit(bus_t bus, int cv, int bit, int value) { return protocol_nmra_sm_direct_cvbit(bus, cv, bit, value, false); } /** Verify a single bit of a configuration variable (cv) @par Input: bus_t bus int cv int bit int value @return 1 if the value matches, 0 otherwise */ int protocol_nmra_sm_verify_cvbit(bus_t bus, int cv, int bit, int value) { return protocol_nmra_sm_direct_cvbit(bus, cv, bit, value, true); } /** Get cvbyte by verifying all bits -> constant runtime @par Input: bus_t bus int cv @return the value of the configuration variable (cv) */ int protocol_nmra_sm_get_cvbyte(bus_t busnumber, int cv) { int bit; int rc = 0; for (bit = 7; bit >= 0; bit--) { rc <<= 1; /* shift bits */ rc += protocol_nmra_sm_direct_cvbit(busnumber, cv, bit, 1, true); } return rc; } /** Calclulate the page number for a given cv @par Input: int cv @return the page number */ static int calc_page(int cv) { int page = (cv - 1) / 4 + 1; return page; } /** Write a configuration variable (cv) using paged mode addressing @par Input: bus_t bus int cv int value @return 1 if successful, 0 otherwise */ int protocol_nmra_sm_write_page(bus_t busnumber, int cv, int value) { int page = calc_page(cv); return protocol_nmra_sm_page(busnumber, page, (cv - 1) & 3, value, false); } /** Verify the contens of a cv using paged mode addressing @par Input: bus_t bus int cv int value @return 1 if the value matches, 0 otherwise */ int protocol_nmra_sm_verify_page(bus_t busnumber, int cv, int value) { int page = calc_page(cv); return protocol_nmra_sm_page(busnumber, page, (cv - 1) & 3, value, true); } /** Get the contens of a cv using paged mode addressing @par Input: bus_t bus int cv @return the value of the configuration variable (cv) */ int protocol_nmra_sm_get_page(bus_t busnumber, int cv) { int page = calc_page(cv); int rc; int i; for (i = 0; i < 256; i++) { rc = protocol_nmra_sm_page(busnumber, page, (cv - 1) & 3, i, true); if (rc) break; } return i; } srcpd-2.1.7/src/dccar.c0000664000175000017500000002541514564575017011613 00000000000000/* $Id: dccar.c 2012-02-19 15:00 achim_marikar $ */ /* * Copyright 2012-2013 Achim Marikar * Copyright 2003-2007 Matthias Trute * Copyright 2004 Frank Schmischke * Copyright 2005 Johann Vieselthaler * Copyright 2009 Joerg Rottland * Copyright 2005-2009 Guido Scholz * * This file is part of srcpd. * * srcpd is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * srcpd is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with srcpd. If not, see . */ /* * dccar: dc-car pc-sender hardware */ #include #include #include #include #include "config-srcpd.h" #include "dccar.h" #include "toolbox.h" #include "srcp-sm.h" #include "srcp-power.h" #include "srcp-server.h" #include "srcp-info.h" #include "srcp-error.h" #include "syslogmessage.h" #define __dccar ((DCCAR_DATA*)buses[busnumber].driverdata) static int fd = 0; int readconfig_DCCAR(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber) { buses[busnumber].driverdata = malloc(sizeof(struct _DCCAR_DATA)); if (buses[busnumber].driverdata == NULL) { syslog_bus(busnumber, DBG_ERROR, "Memory allocation error in module '%s'.", node->name); return 0; } buses[busnumber].type = SERVER_DCCAR; buses[busnumber].init_func = &init_bus_DCCAR; buses[busnumber].thr_func = &thr_sendrec_DCCAR; buses[busnumber].init_gl_func = &init_gl_DCCAR; strcpy(buses[busnumber].description, "GL POWER LOCK DESCRIPTION"); __dccar->mode = DCCAR; __dccar->pause_between_cmd = 10; xmlNodePtr child = node->children; xmlChar *txt = NULL; while (child != NULL) { if ((xmlStrncmp(child->name, BAD_CAST "text", 4) == 0) || (xmlStrncmp(child->name, BAD_CAST "comment", 7) == 0)) { /* just do nothing, it is only formatting text or a comment */ } else if (xmlStrcmp(child->name, BAD_CAST "number_gl") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __dccar->number_gl = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "pause_between_commands") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __dccar->pause_between_cmd = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "mode") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { if (xmlStrcmp(txt, BAD_CAST "dccar") == 0) __dccar->mode = DCCAR; else if (xmlStrcmp(txt, BAD_CAST "infracar") == 0) __dccar->mode = INFRACAR; xmlFree(txt); } } else syslog_bus(busnumber, DBG_WARN, "WARNING, unknown tag found: \"%s\"!\n", child->name);; child = child->next; } if (__dccar->mode == DCCAR && __dccar->number_gl > 1023) __dccar->number_gl = 1023; else if (__dccar->mode == INFRACAR && __dccar->number_gl > 4096) __dccar->number_gl = 4096; if (init_GL(busnumber, __dccar->number_gl)) { __dccar->number_gl = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array for locomotives"); } return (1); } int init_linedccar(bus_t busnumber, char *name) { struct termios interface; syslog_bus(busnumber, DBG_INFO, "Try opening serial line %s \n", name); fd = open(name, O_RDWR); if (fd == -1) { syslog_bus(busnumber, DBG_ERROR, "Open serial line failed: %s (errno = %d).\n", strerror(errno), errno); } else { tcgetattr(fd, &interface); if (__dccar->mode == DCCAR) { /* dc-car: 9600 bps, 8 bit, odd parity, 2 stopbits */ interface.c_cflag = PARENB | PARODD | CSTOPB | CSIZE | CS8 | CLOCAL; cfsetispeed(&interface, B9600); cfsetospeed(&interface, B9600); } else { /* infracar: 2400 bps, 8 Bit, no parity, 1 stopbits */ interface.c_cflag = CSIZE | CS8 | CLOCAL; cfsetispeed(&interface, B2400); cfsetospeed(&interface, B2400); } interface.c_cc[VMIN] = 0; interface.c_cc[VTIME] = 1; tcsetattr(fd, TCSANOW, &interface); } return fd; } /* Initialisiere den Bus, signalisiere Fehler */ /* Einmal aufgerufen mit busnummer als einzigem Parameter */ /* return code wird ignoriert (vorerst) */ int init_bus_DCCAR(bus_t busnumber) { static char *protocols = "MN"; buses[busnumber].protocols = protocols; syslog_bus(busnumber, DBG_INFO, "DC-Car init: debug %d, device %s", buses[busnumber].debuglevel, buses[busnumber].device.file.path); buses[busnumber].device.file.fd = init_linedccar(busnumber, buses[busnumber].device.file.path); syslog_bus(busnumber, DBG_INFO, "DC-Car init done"); return 0; } /** * cacheInitGL: modifies the gl data used to initialize the device **/ int init_gl_DCCAR(gl_data_t * gl) { /* TODO instead of setting mode (dccar or infracar) in config file, the mode could be individual specified by protocol of car to enable mixed mode.*/ switch (gl->protocol) { case 'L': case 'S': case 'P': case 'M': case 'N': default: return (gl->n_fs == 28) ? SRCP_OK : SRCP_WRONGVALUE; break; } return SRCP_UNSUPPORTEDDEVICEPROTOCOL; } static void handle_power_command(bus_t busnumber) { buses[busnumber].power_changed = 0; char msg[110]; infoPower(busnumber, msg); enqueueInfoMessage(msg); buses[busnumber].watchdog++; if ( buses[busnumber].power_state == 0 && __dccar->mode == DCCAR ) { unsigned char command[] = {240,240,0}; write_command(command, sizeof(command), fd, busnumber); } } void set_address_bytes(unsigned char command[3], int id) { command[0] = (unsigned char) ( id % 64 ); /* byte 1, address low */ command[1] = (unsigned char) ( id / 64 ) + 64; /* byte 2, address high, add 64 for speed and functions F1-F6, 96 for functions F0, F7-F11 and 112 for functions F12 and greater */ } void write_command(unsigned char *command, int length, int fd, bus_t busnumber) { if (!write(fd,command,length)) syslog_bus(busnumber, DBG_ERROR, "could not send data to device"); /* the cars need a short delay between two commands */ usleep(__dccar->pause_between_cmd * 1000); } static void handle_gl_command(bus_t busnumber) { gl_data_t gltmp, glakt; int addr; /* byte 1: address low, byte 2: address high, byte 3: speed/functions (see http://www.dc-car.de/DC-Car_PC_Sender.htm & http://www.modellautobahnen.de/newsletter/download/wdp_dc-car_steuerung2.pdf for details) */ unsigned char command[3]; dequeueNextGL(busnumber, &gltmp); addr = gltmp.id; cacheGetGL(busnumber, addr, &glakt); if (gltmp.direction == 2) { gltmp.speed = 0; gltmp.direction = !glakt.direction; } /* send speed message to car */ if (gltmp.speed != glakt.speed) { set_address_bytes(command,gltmp.id); if (gltmp.speed < 8) command[2] = gltmp.speed + 200; else if (gltmp.speed < 16) command[2] = gltmp.speed + 208; else if (gltmp.speed < 24) command[2] = gltmp.speed + 216; else if (gltmp.speed <= 28) command[2] = gltmp.speed + 224; else command[2] = 200; write_command(command, sizeof(command), fd, busnumber); } /* send function message to car */ if (gltmp.funcs != glakt.funcs) { unsigned char byte; /* separate functions to different messages with offset for byte 2 0x40 (default), 0x60 (+32) or 0x70 (+64, currently not implemented) */ if( (gltmp.funcs&126) != (glakt.funcs&126) ) { set_address_bytes(command,gltmp.id); byte = 128; if(gltmp.funcs & 2) byte = byte + 1; if(gltmp.funcs & 4) byte = byte + 2; if(gltmp.funcs & 8) byte = byte + 4; if(gltmp.funcs & 16) byte = byte + 8; if(gltmp.funcs & 32) byte = byte + 16; if(gltmp.funcs & 64) byte = byte + 32; command[2]=byte; write_command(command, sizeof(command),fd, busnumber); } if( ((gltmp.funcs&3969) != (glakt.funcs&3969)) && (__dccar->mode == DCCAR) ) { set_address_bytes(command,gltmp.id); command[1]=command[1] + 32; byte = 128; if(gltmp.funcs & 1) byte = byte + 1; if(gltmp.funcs & 128) byte = byte + 2; if(gltmp.funcs & 256) byte = byte + 4; if(gltmp.funcs & 512) byte = byte + 8; if(gltmp.funcs & 1024) byte = byte + 16; if(gltmp.funcs & 2048) byte = byte + 32; command[2]=byte; write_command(command, sizeof(command), fd, busnumber); } } cacheSetGL(busnumber, addr, gltmp); buses[busnumber].watchdog++; } /*thread cleanup routine for this bus*/ static void end_bus_thread(bus_thread_t * btd) { int result; syslog_bus(btd->bus, DBG_INFO, "DC-Car bus terminated."); result = pthread_mutex_destroy(&buses[btd->bus].transmit_mutex); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_destroy() failed: %s (errno = %d).", strerror(result), result); } result = pthread_cond_destroy(&buses[btd->bus].transmit_cond); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_init() failed: %s (errno = %d).", strerror(result), result); } free(buses[btd->bus].driverdata); free(btd); } /*main thread routine for this bus*/ void *thr_sendrec_DCCAR(void *v) { int last_cancel_state, last_cancel_type; bus_thread_t *btd = (bus_thread_t *) malloc(sizeof(bus_thread_t)); if (btd == NULL) pthread_exit((void *) 1); btd->bus = (bus_t) v; btd->fd = -1; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_cancel_state); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_cancel_type); /*register cleanup routine */ pthread_cleanup_push((void *) end_bus_thread, (void *) btd); syslog_bus(btd->bus, DBG_INFO, "DC-Car bus started (device = %s).", buses[btd->bus].device.file.path); /*enter endless loop to process work tasks */ while (true) { buses[btd->bus].watchdog = 1; /*POWER action arrived */ if (buses[btd->bus].power_changed == 1) handle_power_command(btd->bus); /* loop shortcut to prevent processing of GA, GL (and FB) * without power on; arriving commands will flood the command * queue */ if (buses[btd->bus].power_state == 0) { /* wait 1 ms */ if (usleep(1000) == -1) { syslog_bus(btd->bus, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } continue; } /*GL action arrived */ if (!queue_GL_isempty(btd->bus)) handle_gl_command(btd->bus); /*FB action arrived */ /* currently nothing to do here */ buses[btd->bus].watchdog++; /* busy wait and continue loop */ /* wait 1 ms */ if (usleep(1000) == -1) { syslog_bus(btd->bus, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } } /*run the cleanup routine */ pthread_cleanup_pop(1); return NULL; } srcpd-2.1.7/src/io.c0000664000175000017500000001637612270020620011125 00000000000000/*************************************************************************** io.c - description ------------------- begin : Wed Jul 4 2001 copyright : (C) 2001 by Dipl.-Ing. Frank Schmischke email : frank.schmischke@t-online.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /* changes: 25.11.2007 Frank Schmischke in isvalidchar() change 'char' to 'unsigned char' to avoid compiler warning */ #include #include #include #include #ifdef __CYGWIN__ #include /*for FIONREAD */ #endif #ifdef __sun__ #include #endif #include "config-srcpd.h" #include "io.h" #include "syslogmessage.h" #include "ttycygwin.h" int readByte(bus_t bus, bool wait, unsigned char *the_byte) { ssize_t i; int status; i=0; /* make sure every bit of the integer gets initialized, prevents some ioctl's from beeing misinterpreted */ /* with debug level beyond DBG_DEBUG, we will not really work on hardware */ if (buses[bus].debuglevel > DBG_DEBUG) { i = 1; *the_byte = 0; } else { status = ioctl(buses[bus].device.file.fd, FIONREAD, &i); if (status == -1) { syslog_bus(bus, DBG_ERROR, "readbyte(): ioctl() failed: %s (errno = %d)\n", strerror(errno), errno); return -1; } syslog_bus(bus, DBG_DEBUG, "readbyte(): (fd = %d), there are %d bytes to read.", buses[bus].device.file.fd, i); /* read only, if there is really an input or if "wait" is true * to do a blocking read */ if ((i > 0) || wait) { i = read(buses[bus].device.file.fd, the_byte, 1); if (i == -1) { syslog_bus(bus, DBG_ERROR, "readbyte(): read() failed: %s (errno = %d)\n", strerror(errno), errno); } if (i > 0) syslog_bus(bus, DBG_DEBUG, "readbyte(): byte read: 0x%02x", *the_byte); } } return (i > 0 ? 0 : -1); } void writeByte(bus_t bus, const unsigned char b, unsigned long msecs) { ssize_t i = 0; char byte = b; if (buses[bus].debuglevel <= DBG_DEBUG) { i = write(buses[bus].device.file.fd, &byte, 1); syslog_bus(bus, DBG_DEBUG, "(FD: %d) %i byte sent: 0x%02x (%d)\n", buses[bus].device.file.fd, i, b, b); if (i < 0) { syslog_bus(bus, DBG_ERROR, "(FD: %d) write failed: %s " "(errno = %d)\n", buses[bus].device.file.fd, strerror(errno), errno); } tcdrain(buses[bus].device.file.fd); } else { syslog_bus(bus, DBG_DEBUG, "(FD: %d) %i byte sent: 0x%02x (%d)\n", buses[bus].device.file.fd, i, b, b); } if (usleep(msecs * 1000) == -1) { syslog_bus(bus, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } } void writeString(bus_t bus, const char *s, unsigned long msecs) { size_t l = strlen(s); size_t i; for (i = 0; i < l; i++) { writeByte(bus, s[i], msecs); } } void save_comport(bus_t bus) { int fd; fd = open(buses[bus].device.file.path, O_RDWR); if (fd == -1) { syslog_bus(bus, DBG_ERROR, "Open serial line failed: %s (errno = %d).\n", strerror(errno), errno); } else { tcgetattr(fd, &buses[bus].device.file.devicesettings); close(fd); } } void restore_comport(bus_t bus) { int fd; syslog_bus(bus, DBG_INFO, "Restoring attributes for serial line %s", buses[bus].device.file.path); fd = open(buses[bus].device.file.path, O_RDWR); if (fd == -1) { syslog_bus(bus, DBG_ERROR, "Open serial line failed: %s (errno = %d).\n", strerror(errno), errno); } else { syslog_bus(bus, DBG_INFO, "Restoring old values..."); tcsetattr(fd, TCSANOW, &buses[bus].device.file.devicesettings); close(fd); syslog_bus(bus, DBG_INFO, "Old values successfully restored"); } } void close_comport(bus_t bus) { struct termios interface; syslog_bus(bus, DBG_INFO, "Closing serial line"); tcgetattr(buses[bus].device.file.fd, &interface); cfsetispeed(&interface, B0); cfsetospeed(&interface, B0); tcsetattr(buses[bus].device.file.fd, TCSANOW, &interface); close(buses[bus].device.file.fd); } /* Zeilenweises Lesen vom Socket */ /* nicht eben trivial! */ static int isvalidchar(unsigned char c) { return ((c >= 0x20 && c <= 127) || c == 0x09 || c == '\n'); } /* * Read a text line from socket descriptor including newline character * (like fgets()). * return values * -1: error * 0: end of file (EOF), client terminated connection * >0: number of read characters * */ ssize_t socket_readline(int Socket, char *line, int len) { char c; int i = 0; ssize_t bytes_read; again: bytes_read = read(Socket, &c, 1); if (bytes_read == -1) { /* handle interrupt */ if (errno == EINTR) goto again; /* normal read error */ else return -1; } /*EOF detected, client closed connection */ else if (bytes_read == 0) { return 0; } /*normal operation */ else { if (isvalidchar(c)) line[i++] = c; /* die Reihenfolge beachten! */ /*TODO: handle (errno == EINTR), message part will get lost */ while (read(Socket, &c, 1) > 0) { if (isvalidchar(c) && (i < len - 1)) line[i++] = c; /* stop at newline character */ if (c == '\n') break; } } line[i++] = 0x00; return (i - 1); } /* Write "n" bytes to a descriptor. Stevens, UNP; * srcp messages must end with '\n' to use this function directly * return values: * -1: write error * >=0: number of written characters */ ssize_t writen(int fd, const void *vptr, size_t n) { size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ((nwritten = write(fd, ptr, nleft)) <= 0) { /* if EINTR call write() again */ if (nwritten < 0 && errno == EINTR) nwritten = 0; /* a real error */ else return (-1); } nleft -= nwritten; ptr += nwritten; } return n; } srcpd-2.1.7/src/srcp-sm.h0000664000175000017500000000425613663753750012131 00000000000000/*************************************************************************** srcp-sm.h - description ------------------- begin : Mon Aug 12 2002 copyright : (C) 2002 by Dipl.-Ing. Frank Schmischke email : frank.schmischke@t-online.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _SRCP_SM_H #define _SRCP_SM_H #include #include "config-srcpd.h" extern enum COMMAND { SET = 0, GET, VERIFY, INIT, TERM } sm_command_t; extern enum TYPE { REGISTER = 0, PAGE, CV, CV_BIT } sm_type_t; extern enum TYPEADDR { NMRA = 0 } sm_typeaddr_t; /* Loco decoder */ typedef struct _SM { char protocol[6]; /* currently only NMRA is supported */ /* (for IB, but not completely, work in progress) */ int type; int command; int protocolversion; int addr; int typeaddr; int bit; /* bit to set/get for CVBIT */ int value; struct timeval tv; /* time of change */ } sm_t; int enqueueSM(bus_t busnumber, int command, int type, int addr, int typeaddr, int bit, int value); int queue_SM_isempty(bus_t busnumber); int dequeueNextSM(bus_t, sm_t *); int getSM(bus_t busnumber, int addr, sm_t *); int setSM(bus_t busnumber, int type, int addr, int typeaddr, int bit, int value, int return_value); int infoSM(bus_t busnumber, int command, int type, int addr, int typeaddr, int bit, int value, char *info); #endif srcpd-2.1.7/src/srcp-ga.h0000644000175000017500000000436312673554172012073 00000000000000/* $Id: srcp-ga.h 1725 2016-03-20 17:06:01Z gscholz $ */ #ifndef _SRCP_GA_H #define _SRCP_GA_H #include #include #include "config-srcpd.h" #include "srcp-session.h" #define MAXGAPORT 2 enum ga_state_t {gasNone = 0, gasActive, gasTerm}; /* GA device data set (single accessory decoder) */ typedef struct { enum ga_state_t state; /* 0==none, 1==active, 2==terminating */ char protocol; /* Protocol Id */ int id; /* Identification */ int port; /* Port number */ int action; /* 0, 1, 2, 3... */ long activetime; /* Aktivierungszeit in msec bis das automatische AUS kommen soll */ struct timeval inittime; struct timeval tv[MAXGAPORT]; /* time of last activation, each port gets its own time value */ struct timeval t; /* switch off time */ struct timeval locktime; sessionid_t locked_by; /* who has the LOCK? */ long int lockduration; } ga_data_t; /* GA device group data set */ typedef struct { int numberOfGa; ga_data_t* gastate; } ga_t; void startup_GA(); void shutdown_GA(); int init_GA(bus_t busnumber, int number); int get_number_ga(bus_t busnumber); int enqueueGA(bus_t busnumber, int addr, int port, int action, long int activetime); int dequeueNextGA(bus_t busnumber, ga_data_t *); int queue_GA_isempty(bus_t busnumber); int getGA(bus_t busnumber, int addr, ga_data_t *a); int setGA(bus_t busnumber, int addr, ga_data_t a); int initGA(bus_t busnumber, int addr, const char protocol); int termGA(bus_t busnumber, int addr); int describeGA(bus_t busnumber, int addr, char *msg); int infoGA(bus_t busnumber, int addr, int port, char *msg); int cmpGA(ga_data_t a, ga_data_t b); bool isInitializedGA(bus_t busnumber, int addr); void clean_GA(bus_t bus); int lockGA(bus_t busnumber, int addr, long int duration, sessionid_t sessionid); int getlockGA(bus_t busnumber, int addr, sessionid_t * sessionid); int unlockGA(bus_t busnumber, int addr, sessionid_t sessionid); void unlock_ga_bysessionid(sessionid_t); void unlock_ga_bytime(void); int describeLOCKGA(bus_t bus, int addr, char *reply); #endif srcpd-2.1.7/src/selectrix.h0000644000175000017500000000731612673514370012536 00000000000000/** * This software is published under the terms of the GNU General Public * License, Version 2.0 * Gerard van der Sel * */ #ifndef _Selectrix_H #define _Selectrix_H #include /*xmlDocPtr, xmlNodePtr*/ /* Read and Write command for the interface (Send with the address) */ #define SXread 0x00 /* Read command on the Selectrixbus */ #define SXwrite 0x80 /* Write command on the Selectrixbus */ #define SXempty 0x5a /* Fill character for reception */ /* Maximum number off addresses on the SX-bus */ #define SXmax 112 /* Number of addresses on the SX-bus */ #define SXcc2000 104 /* Number of addresses on the SX-bus with a CC-2000 */ /* Addresses on the SX_bus */ #define SXcontrol 127 /* Power on/off address (all SX controllers) */ /* Control addresses for a CC2000 */ #define SXstatus 109 /* Status address */ #define SXcommand 106 /* Command address */ #define SXprog2 105 /* Program parameter 2 */ #define SXprog1 104 /* Program parameter 1 */ /* Status bits */ #define SXstpower 0x80 /* Power on track */ #define SXstready 0x40 /* CC2000 ready */ #define SXstprogram 0x20 /* Programming ready */ #define SXstshort 0x10 /* Track shorted */ #define SXstmode 0x0f /* Function mode (internal) */ /* Commandbits */ #define SXcmdstart 0x80 /* Start command */ #define SXcmdprog 0x40 /* Start programming */ /* bit 5 - 4 must be 0x00 */ #define SXcmddcod 0x08 /* 0= read 1= write */ #define SXcmdmodus 0x01 /* Bit 2 - 1 001 = Selectrix */ /* Control addresses for a SLX852 */ #define RautenhsCC 126 /* Rautenhaus control address */ #define RautenhsB0 0x00 /* Select bus 0 */ #define RautenhsB1 0x02 /* Select bus 1 */ /* Rautenhaus control bits (for address 126) */ #define cntrlON 128 /* Start Rautenhaus protocol */ #define cntrlOFF 64 /* Stop Rautenhaus protocol */ #define fdbckON 32 /* Changes on then SX bus are reported automatically */ #define fdbckOFF 16 /* Stop reporting changes on the SX bus */ #define clkOFF0 8 /* Don't check address 111 (clock) on bus 1 */ #define clkOFF1 4 /* Don't check address 111 (clock) on bus 0 */ /* Constants for SXflags */ /* Central is a special */ #define CC2000_MODE 0x0001 /* CC2000 commanding the SX-bus */ #define Rautenhaus_MODE 0x0002 /* Rautenhaus commanding the SX-bus */ #define Rautenhaus_FDBCK 0x0010 /* Automatic feedback report */ #define Rautenhaus_DBL 0x0020 /* Two busses are controlled */ #define Rautenhaus_ADR 0x0040 /* Last byte was an address */ #define Rautenhaus_RTBS 0x0080 /* Last selected bus */ #define Connection 0x0100 /* Got a replay from the interface */ /* Array with the size of two SX-busses */ /* typedef int SX_BUS[SXmax]; */ typedef int SX_BUS[256]; /* Space for addresses/data on the SX-bus */ /* Structure of a Selectrix bus */ typedef struct _SELECTRIX_DATA { int number_fb; int number_ga; int number_gl; int SXflags; int stateInterface; /* Reply state of the interface */ int currentFB; /* holds current number of the feedback */ int max_address; SX_BUS fb_adresses; SX_BUS bus_data; } SELECTRIX_DATA; /* Initialisation of the structure */ int readconfig_Selectrix(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber); /* Methods for Selectrix */ int init_lineSelectrix(bus_t bus); int init_bus_Selectrix(bus_t bus); int init_gl_Selectrix(gl_data_t *gl); int init_ga_Selectrix(ga_data_t *ga); int init_fb_Selectrix(bus_t busnumber, int addr, const char protocol, int index); void *thr_commandSelectrix(void *); void *thr_feedbackSelectrix(void *); void sig_processSelectrix(bus_t busnumber); #endif srcpd-2.1.7/src/srcp-session.c0000644000175000017500000004456512704701516013161 00000000000000/************************************************************************** srcp-session.c ------------------- begin : Don Apr 25 2002 copyright : (C) 2002 by email : **************************************************************************/ /************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * **************************************************************************/ #include #include #include #include #include #include "srcp-session.h" #include "srcp-ga.h" #include "srcp-gl.h" #include "srcp-error.h" #include "srcp-info.h" #include "syslogmessage.h" /* * A linked list stores the data of all connected sessions. This code was * mainly impressed by: * http://en.wikipedia.org/wiki/Linked_list#Language_support */ /*session counter, session list root and mutex to lock access*/ static sessionid_t lastsession = 0; static unsigned int runningsessions = 0; static session_node_t *session_list = NULL; static pthread_mutex_t session_list_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t session_list_cond = PTHREAD_COND_INITIALIZER; static pthread_mutex_t cb_mutex[MAX_BUSES]; static pthread_cond_t cb_cond[MAX_BUSES]; static int cb_data[MAX_BUSES]; /*add new session data node to list with a valid socket*/ static session_node_t *list_add(session_node_t ** p, int s) { session_node_t *n; n = (session_node_t *) malloc(sizeof(session_node_t)); if (NULL == n) return NULL; n->next = *p; *p = n; n->session = 0; n->socket = s; n->thread = 0; n->mode = smUndefined; n->pipefd[0] = -1; n->pipefd[1] = -1; return n; } /*remove session data node from list, returns "true" for success*/ static bool list_remove(session_node_t ** p) { bool returnvalue = false; if (*p != NULL) { session_node_t *n = *p; *p = (*p)->next; free(n); returnvalue = true; } return returnvalue; } /* search sessionid in list, return pointer to node pointer */ static session_node_t **list_search_session(session_node_t ** n, sessionid_t sid) { while (*n != NULL) { if ((*n)->session == sid) { return n; } n = &(*n)->next; } return NULL; } /* search sessionid in list, return pointer to node */ static session_node_t *list_search_session_node(session_node_t ** n, sessionid_t sid) { while (*n != NULL) { if ((*n)->session == sid) { return *n; } n = &(*n)->next; } return NULL; } /* search thread id by sessionid, return thread id */ static pthread_t list_search_thread_by_sessionid(session_node_t ** n, sessionid_t sid) { while (*n != NULL) { if ((*n)->session == sid) { return (*n)->thread; } n = &(*n)->next; } return 0; } /* search valid info sessionid, return "true" if found */ static bool list_has_info_sessionid(session_node_t ** n, sessionid_t sid) { bool returnvalue = false; while (*n != NULL) { if ((*n)->session == sid && (*n)->mode == smInfo) { returnvalue = true; break; } n = &(*n)->next; } return returnvalue; } /** * First initialisation after program start up */ void startup_SESSION() { for (int i = 0; i < MAX_BUSES; i++) { int result = pthread_mutex_init(&cb_mutex[i], NULL); if (result != 0) { syslog_bus(0, DBG_ERROR, "pthread_mutex_init() failed: %s (errno = %d).", strerror(result), result); } result = pthread_cond_init(&cb_cond[i], NULL); if (result != 0) { syslog_bus(0, DBG_ERROR, "pthread_cond_init() failed: %s (errno = %d).", strerror(result), result); } } } /*destroy all occupied mutexes and condition variables*/ void shutdown_SESSION() { for (int i = 0; i < MAX_BUSES; i++) { int result = pthread_mutex_destroy(&cb_mutex[i]); if (result != 0) { syslog_bus(0, DBG_ERROR, "pthread_mutex_destroy() failed: %s (errno = %d).", strerror(result), result); } result = pthread_cond_destroy(&cb_cond[i]); if (result != 0) { syslog_bus(0, DBG_ERROR, "pthread_cond_destroy() failed: %s (errno = %d).", strerror(result), result); } } } /*create a node with an anonymous session*/ session_node_t *create_anonymous_session(int s) { int result; session_node_t *node = NULL; result = pthread_mutex_lock(&session_list_mutex); if (result != 0) { syslog_session(s, DBG_ERROR, "pthread_mutex_lock() failed: %s (errno = %d).", strerror(result), result); } node = list_add(&session_list, s); if (NULL != node) runningsessions++; else syslog_session(s, DBG_ERROR, "Could not add session node."); result = pthread_mutex_unlock(&session_list_mutex); if (result != 0) { syslog_session(s, DBG_ERROR, "pthread_mutex_unlock() failed: %s (errno = %d).", strerror(result), result); } return node; } /*destroy a node with an anonymous session*/ void destroy_anonymous_session(session_node_t * n) { int result; sessionid_t sid; if (n == NULL) return; sid = n->session; result = pthread_mutex_lock(&session_list_mutex); if (result != 0) { syslog_session(sid, DBG_ERROR, "pthread_mutex_lock() failed: %s (errno = %d).", strerror(result), result); } if (list_remove(&n)) runningsessions--; else syslog_session(sid, DBG_ERROR, "Could not remove session node."); result = pthread_cond_signal(&session_list_cond); if (result != 0) { syslog_session(n->session, DBG_ERROR, "pthread_cond_signal() failed: %s (errno = %d).", strerror(result), result); } result = pthread_mutex_unlock(&session_list_mutex); if (result != 0) { syslog_session(n->session, DBG_ERROR, "pthread_mutex_unlock() failed: %s (errno = %d).", strerror(result), result); } } /*destroy a fully functionalized session*/ void destroy_session(sessionid_t sid) { int result; result = pthread_mutex_lock(&session_list_mutex); if (result != 0) { syslog_session(sid, DBG_ERROR, "pthread_mutex_lock() failed: %s (errno = %d).", strerror(result), result); } if (list_remove(list_search_session(&session_list, sid))) runningsessions--; else syslog_session(sid, DBG_ERROR, "Could not remove session node."); result = pthread_cond_signal(&session_list_cond); if (result != 0) { syslog_session(sid, DBG_ERROR, "pthread_cond_signal() failed: %s (errno = %d).", strerror(result), result); } result = pthread_mutex_unlock(&session_list_mutex); if (result != 0) { syslog_session(sid, DBG_ERROR, "pthread_mutex_unlock() failed: %s (errno = %d).", strerror(result), result); } } /*register a new session id*/ void register_session(session_node_t * n) { int result; if (NULL == n) return; result = pthread_mutex_lock(&session_list_mutex); if (result != 0) { syslog_session(lastsession + 1, DBG_ERROR, "pthread_mutex_lock() failed: %s (errno = %d).", strerror(result), result); } lastsession++; /* check possible overflow, restart numbering * FIXME: new session ids now may still be used*/ if (0 == lastsession) { lastsession++; syslog_session(lastsession, DBG_ERROR, "Session id overflow," " restarting at 1"); } n->session = lastsession; /*set default mode if mode was not set explicitly */ if (n->mode == smUndefined) n->mode = smCommand; result = pthread_mutex_unlock(&session_list_mutex); if (result != 0) { syslog_session(n->session, DBG_ERROR, "pthread_mutex_unlock() failed: %s (errno = %d).", strerror(result), result); } } /* search for valid session id */ bool is_valid_info_session(sessionid_t session) { int result; bool isvalid; result = pthread_mutex_lock(&session_list_mutex); if (result != 0) { syslog_session(session, DBG_ERROR, "pthread_mutex_lock() failed: %s (errno = %d).", strerror(result), result); } isvalid = list_has_info_sessionid(&session_list, session); result = pthread_mutex_unlock(&session_list_mutex); if (result != 0) { syslog_session(session, DBG_ERROR, "pthread_mutex_unlock() failed: %s (errno = %d).", strerror(result), result); } return isvalid; } /* * Enqueue a new info message to the appropriate session pipe. * * There is no write locking because writing to pipes is atomic as * far as MAXSRCPLEN < PIPE_BUF and pipe write access is blocking (see * "man 3 write" for more details). */ void session_enqueue_info_message(sessionid_t sid, char *msg) { session_node_t *n; int result; ssize_t nwritten; /*return immediately, if no session is running */ if (NULL == session_list) return; /*enqueue message for all info sessions */ if (sid == 0) { n = session_list; result = pthread_mutex_lock(&session_list_mutex); if (result != 0) { syslog_session(sid, DBG_ERROR, "pthread_mutex_lock() failed: %s (errno = %d).", strerror(result), result); } while (n != NULL) { if (n->mode == smInfo && n->pipefd[1] != -1) { nwritten = write(n->pipefd[1], msg, strlen(msg) + 1); if (nwritten == -1) { syslog_session(n->session, DBG_ERROR, "Write to pipe failed: %s (errno = %d).", strerror(errno), errno); } } n = n->next; } result = pthread_mutex_unlock(&session_list_mutex); if (result != 0) { syslog_session(sid, DBG_ERROR, "pthread_mutex_unlock() failed: %s (errno = %d).", strerror(result), result); } } /*enqueue message for a single info session */ else { result = pthread_mutex_lock(&session_list_mutex); if (result != 0) { syslog_session(sid, DBG_ERROR, "pthread_mutex_lock() failed: %s (errno = %d).", strerror(result), result); } n = list_search_session_node(&session_list, sid); if (n != NULL && n->mode == smInfo && n->pipefd[1] != -1) { nwritten = write(n->pipefd[1], msg, strlen(msg) + 1); if (nwritten == -1) { syslog_session(n->session, DBG_ERROR, "Write to pipe failed: %s (errno = %d).", strerror(errno), errno); } } result = pthread_mutex_unlock(&session_list_mutex); if (result != 0) { syslog_session(sid, DBG_ERROR, "pthread_mutex_unlock() failed: %s (errno = %d).", strerror(result), result); } } } /* terminate a session by cancellation of client thread */ void session_terminate(sessionid_t session) { int result; pthread_t pc; result = pthread_mutex_lock(&session_list_mutex); if (result != 0) { syslog_session(session, DBG_ERROR, "pthread_mutex_lock() failed: %s (errno = %d).", strerror(result), result); } pc = list_search_thread_by_sessionid(&session_list, session); result = pthread_mutex_unlock(&session_list_mutex); if (result != 0) { syslog_session(session, DBG_ERROR, "pthread_mutex_unlock() failed: %s (errno = %d).", strerror(result), result); } if (0 != pc) { result = pthread_cancel(pc); if (result != 0) { syslog_session(session, DBG_ERROR, "pthread_cancel() failed: %s (errno = %d).", strerror(result), result); } } else syslog_session(session, DBG_ERROR, "Found unvalid thread id to cancel."); } /* terminate all active sessions */ void terminate_all_sessions() { int result; if (session_list == NULL) return; session_node_t *node = session_list; /*first cancel all session threads ... */ result = pthread_mutex_lock(&session_list_mutex); if (result != 0) { syslog_bus(0, DBG_ERROR, "pthread_mutex_lock() failed: %s (errno = %d).", strerror(result), result); } while (node != NULL) { result = pthread_cancel(node->thread); if (result != 0) { syslog_bus(0, DBG_ERROR, "pthread_cancel() failed: %s (errno = %d).", strerror(result), result); } node = node->next; } /*... then wait for complete termination */ while (runningsessions != 0) { result = pthread_cond_wait(&session_list_cond, &session_list_mutex); if (result != 0) { syslog_bus(0, DBG_ERROR, "pthread_cond_wait() failed: %s (errno = %d).", strerror(result), result); } } result = pthread_mutex_unlock(&session_list_mutex); if (result != 0) { syslog_bus(0, DBG_ERROR, "pthread_mutex_unlock() failed: %s (errno = %d).", strerror(result), result); } syslog_bus(0, DBG_INFO, "Session thread termination completed."); } /*this function is used by clientservice starting the session*/ int start_session(session_node_t * sn) { char msg[1000]; struct timeval akt_time; gettimeofday(&akt_time, NULL); snprintf(msg, sizeof(msg), "%lu.%.3lu 101 INFO 0 SESSION %lu %s\n", akt_time.tv_sec, akt_time.tv_usec / 1000, sn->session, (sn->mode == 1 ? "COMMAND" : "INFO")); enqueueInfoMessage(msg); syslog_session(sn->session, DBG_INFO, "Session started (mode = %d).", sn->mode); return SRCP_OK; } /** * this funtion is called by clientservice when the client thread * terminates */ int stop_session(sessionid_t sid) { char msg[1000]; struct timeval akt_time; gettimeofday(&akt_time, NULL); /* clean all locks */ unlock_ga_bysessionid(sid); unlock_gl_bysessionid(sid); snprintf(msg, sizeof(msg), "%lu.%.3lu 102 INFO 0 SESSION %lu\n", akt_time.tv_sec, akt_time.tv_usec / 1000, sid); enqueueInfoMessage(msg); return SRCP_OK; } int describeSESSION(bus_t bus, sessionid_t sessionid, char *reply) { return SRCP_UNSUPPORTEDOPERATION; } /** * called by srcp command session finishing a session; * return negative value of SRCP_OK to ack the request. */ int termSESSION(bus_t bus, sessionid_t sessionid, sessionid_t termsessionid, char *reply) { if (sessionid == termsessionid) { session_terminate(termsessionid); return -SRCP_OK; } return SRCP_FORBIDDEN; } int session_lock_wait(bus_t bus) { int result; syslog_bus(bus, DBG_DEBUG, "SESSION process wait1 for bus."); result = pthread_mutex_lock(&cb_mutex[bus]); if (result != 0) { syslog_bus(bus, DBG_ERROR, "pthread_mutex_lock() failed: %s (errno = %d).", strerror(result), result); } syslog_bus(bus, DBG_DEBUG, "SESSION process wait2 for bus."); return result; } int session_unlock_wait(bus_t bus) { int result; syslog_bus(bus, DBG_DEBUG, "SESSION cleanup wait for bus."); result = pthread_mutex_unlock(&cb_mutex[bus]); if (result != 0) { syslog_bus(bus, DBG_ERROR, "pthread_mutex_unlock() failed: %s (errno = %d).", strerror(result), result); } return result; } int session_condt_wait(bus_t bus, unsigned int timeout, int *value) { int result; struct timespec stimeout; struct timeval now; gettimeofday(&now, NULL); stimeout.tv_sec = now.tv_sec + timeout; stimeout.tv_nsec = now.tv_usec * 1000; syslog_bus(bus, DBG_DEBUG, "SESSION start wait1"); result = pthread_cond_timedwait(&cb_cond[bus], &cb_mutex[bus], &stimeout); if (result != 0) { syslog_bus(bus, DBG_ERROR, "pthread_cond_timedwait() failed: %s (errno = %d).", strerror(result), result); } *value = cb_data[bus]; syslog_bus(bus, DBG_DEBUG, "SESSION start wait2"); return result; } int session_endwait(bus_t bus, int returnvalue) { int result; syslog_bus(bus, DBG_DEBUG, "SESSION end wait1 for bus."); cb_data[bus] = returnvalue; result = pthread_cond_broadcast(&cb_cond[bus]); if (result != 0) { syslog_bus(bus, DBG_ERROR, "pthread_cond_broadcast() failed: %s (errno = %d).", strerror(result), result); } result = pthread_mutex_unlock(&cb_mutex[bus]); if (result != 0) { syslog_bus(bus, DBG_ERROR, "pthread_mutex_unlock() failed: %s (errno = %d).", strerror(result), result); } syslog_bus(bus, DBG_DEBUG, "SESSION end wait2 for bus."); return returnvalue; } srcpd-2.1.7/src/syslogmessage.c0000644000175000017500000000422512267537210013405 00000000000000/* * syslogmessage.c */ /************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * **************************************************************************/ #include #include #include #include #include "syslogmessage.h" /* * DBG: write some syslog information is current debug level of the bus is greater then the the debug level of the message. e.g. if a debug message is deb_info and the bus is configured to inform only about deb_error, no message will be generated. * @param busnumber integer, busnumber * @param dbglevel one of the constants DBG_FATAL, DBG_ERROR, DBG_WARN, DBG_INFO, DBG_DEBUG * @param fmt const char *: standard c format string * @param ... remaining parameters according to format string */ void syslog_bus(bus_t busnumber, int dbglevel, const char *fmt, ...) { if (dbglevel <= buses[busnumber].debuglevel) { va_list parm; va_start(parm, fmt); char *msg; msg = (char *) malloc(sizeof(char) * (strlen(fmt) + 18)); if (msg == NULL) return; sprintf(msg, "[bus %ld] %s", busnumber, fmt); vsyslog(LOG_INFO, msg, parm); free(msg); va_end(parm); } } void syslog_session(sessionid_t session, int dbglevel, const char *fmt, ...) { if (dbglevel <= buses[0].debuglevel) { va_list parm; va_start(parm, fmt); char *msg; msg = (char *) malloc(sizeof(char) * (strlen(fmt) + 22)); if (msg == NULL) return; sprintf(msg, "[session %ld] %s", session, fmt); vsyslog(LOG_INFO, msg, parm); free(msg); va_end(parm); } } srcpd-2.1.7/src/srcp-error.h0000644000175000017500000000260510737374113012624 00000000000000/* $Id: srcp-error.h 1073 2008-01-04 09:11:38Z gscholz $ */ /* * Vorliegende Software unterliegt der General Public License, * Version 2, 1991. (c) Matthias Trute, 2000-2001. * */ #ifndef _SRCP_ERROR_H #define _SRCP_ERROR_H #include /* Handshake */ #define SRCP_OK_GO 200 #define SRCP_OK_PROTOCOL 201 #define SRCP_OK_CONNMODE 202 /* HandShake */ #define SRCP_HS_WRONGPROTOCOL 400 #define SRCP_HS_WRONGCONNMODE 401 #define SRCP_HS_NODATA 402 /* COMMAND MODE */ #define SRCP_INFO 100 #define SRCP_OK 200 #define SRCP_UNKNOWNCOMMAND 410 #define SRCP_UNKNOWNVALUE 411 #define SRCP_WRONGVALUE 412 #define SRCP_TEMPORARILYPROHIBITED 413 #define SRCP_DEVICELOCKED 414 #define SRCP_FORBIDDEN 415 #define SRCP_NODATA 416 #define SRCP_TIMEOUT 417 #define SRCP_LISTTOOLONG 418 #define SRCP_LISTTOOSHORT 419 #define SRCP_UNSUPPORTEDDEVICEPROTOCOL 420 #define SRCP_UNSUPPORTEDDEVICE 421 #define SRCP_UNSUPPORTEDDEVICEGROUP 422 #define SRCP_UNSUPPORTEDOPERATION 423 #define SRCP_DEVICEREINITIALIZED 424 #define SRCP_OUTOFRESOURCES 500 int srcp_fmt_msg(int errorcode, char *msg, struct timeval); #endif srcpd-2.1.7/src/toolbox.c0000644000175000017500000000114011307245765012204 00000000000000/* * Various functions used by or useful for more than 1 module. * */ #include "toolbox.h" /** * cmdTime: * compare two time stamps. * Input: 2 time stamps in the struct timeval (from sys/time.h) * Output: 1 if timestamp 1 is newer than 2 * 0 if same or older */ int cmpTime(struct timeval *t1, struct timeval *t2) { int result; result = 0; if (t2->tv_sec > t1->tv_sec) { result = 1; } else { if (t2->tv_sec == t1->tv_sec) { if (t2->tv_usec > t1->tv_usec) { result = 1; } } } return result; } srcpd-2.1.7/src/li100.c0000664000175000017500000021703412673514455011362 00000000000000/*************************************************************************** li100.c - description ------------------- begin : Tue Jan 22 11:35:13 CEST 2002 copyright : (C) 2002-2007 by Dipl.-Ing. Frank Schmischke email : frank.schmischke@t-online.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifdef LI100_USB static int readAnswer_LI100_USB(bus_t busnumber); static void send_command_ga_LI100_USB(bus_t busnumber); static void send_command_gl_LI100_USB(bus_t busnumber); static void send_command_sm_LI100_USB(bus_t busnumber); static void check_status_LI100_USB(bus_t busnumber); static int send_command_LI100_USB(bus_t busnumber, const unsigned char *); static void get_status_sm_LI100_USB(bus_t busnumber); static void check_extern_engines_USB(bus_t busnumber); static void end_bus_usb_thread(bus_thread_t * btd); #else static int readAnswer_LI100_SERIAL(bus_t busnumber); static void send_command_ga_LI100_SERIAL(bus_t busnumber); static void send_command_gl_LI100_SERIAL(bus_t busnumber); static void send_command_sm_LI100_SERIAL(bus_t busnumber); static void check_status_LI100_SERIAL(bus_t busnumber); static int send_command_LI100_SERIAL(bus_t busnumber, const unsigned char *); static void get_status_sm_LI100_SERIAL(bus_t busnumber); static void check_extern_engines_SERIAL(bus_t busnumber); static void end_bus_rs232_thread(bus_thread_t * btd); #endif #ifdef LI100_USB int readConfig_LI100_USB(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber) #else int readConfig_LI100_SERIAL(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber) #endif { #ifdef LI100_USB syslog_bus(busnumber, DBG_INFO, "reading configuration for LI100 (usb) at bus #%ld", busnumber); #else syslog_bus(busnumber, DBG_INFO, "reading configuration for LI100 (serial) at bus #%ld", busnumber); #endif buses[busnumber].driverdata = malloc(sizeof(struct _LI100_DATA)); if (buses[busnumber].driverdata == NULL) { syslog_bus(busnumber, DBG_ERROR, "Memory allocation error in module '%s'.", node->name); return 0; } #ifdef LI100_USB buses[busnumber].type = SERVER_LI100_USB; buses[busnumber].init_func = &init_bus_LI100_USB; buses[busnumber].thr_func = &thr_sendrec_LI100_USB; buses[busnumber].device.file.baudrate = B57600; #else buses[busnumber].type = SERVER_LI100_SERIAL; buses[busnumber].init_func = &init_bus_LI100_SERIAL; buses[busnumber].thr_func = &thr_sendrec_LI100_SERIAL; buses[busnumber].device.file.baudrate = B9600; #endif buses[busnumber].init_gl_func = &init_gl_LI100; buses[busnumber].init_ga_func = &init_ga_LI100; buses[busnumber].flags |= FB_4_PORTS; buses[busnumber].flags |= FB_ORDER_0; strcpy(buses[busnumber].description, "GA GL FB SM POWER LOCK DESCRIPTION"); #ifdef LI100_USB __li100->number_fb = 512; __li100->number_ga = 1024; __li100->number_gl = 9999; #else __li100->number_fb = 256; __li100->number_ga = 256; __li100->number_gl = 99; #endif xmlNodePtr child = node->children; xmlChar *txt = NULL; while (child != NULL) { if ((xmlStrncmp(child->name, BAD_CAST "text", 4) == 0) || (xmlStrncmp(child->name, BAD_CAST "comment", 7) == 0)) { /* just do nothing, it is only formatting text or a comment */ } else if (xmlStrcmp(child->name, BAD_CAST "number_fb") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __li100->number_fb = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "number_gl") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __li100->number_gl = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "number_ga") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __li100->number_ga = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "fb_delay_time_0") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { set_min_time(busnumber, atoi((char *) txt)); xmlFree(txt); } } else syslog_bus(busnumber, DBG_WARN, "WARNING, unknown tag found: \"%s\"!\n", child->name); child = child->next; } return (1); } #ifdef LI100_USB int initLine_LI100_USB(bus_t busnumber) #else int initLine_LI100_SERIAL(bus_t busnumber) #endif { int status, status2; int result; int fd; unsigned char byte2send[20]; struct termios interface; char *name = buses[busnumber].device.file.path; syslog_bus(busnumber, DBG_INFO, "Beginning to detect LI100 on serial " "line: %s\n", name); status = -4; switch (buses[busnumber].device.file.baudrate) { case B9600: strcpy((char *) byte2send, "9600"); break; case B19200: strcpy((char *) byte2send, "19200"); break; case B38400: strcpy((char *) byte2send, "38400"); break; case B57600: strcpy((char *) byte2send, "57600"); break; case B115200: strcpy((char *) byte2send, "57600"); break; default: strcpy((char *) byte2send, "9600"); break; } syslog_bus(busnumber, DBG_INFO, "Try to open serial line %s for %s baud\n", name, byte2send); fd = open(name, O_RDWR); if (fd == -1) { syslog_bus(busnumber, DBG_ERROR, "Open serial device '%s' failed: %s " "(errno = %d).\n", name, strerror(errno), errno); return status; } buses[busnumber].device.file.fd = fd; tcgetattr(fd, &interface); interface.c_oflag = ONOCR; #ifdef LI100_USB interface.c_cflag = CS8 | CLOCAL | CREAD | HUPCL; #else interface.c_cflag = CS8 | CRTSCTS | CLOCAL | CREAD | HUPCL; #endif interface.c_iflag = IGNBRK; interface.c_lflag = IEXTEN; cfsetispeed(&interface, buses[busnumber].device.file.baudrate); cfsetospeed(&interface, buses[busnumber].device.file.baudrate); interface.c_cc[VMIN] = 0; interface.c_cc[VTIME] = 1; tcsetattr(fd, TCSANOW, &interface); result = sleep(1); if (result != 0) { syslog_bus(busnumber, DBG_ERROR, "sleep() interrupted, %d seconds left\n", result); } status++; /* get version of LI100 */ byte2send[0] = 0xF0; #ifdef LI100_USB status2 = send_command_LI100_USB(busnumber, byte2send); #else status2 = send_command_LI100_SERIAL(busnumber, byte2send); #endif if (status2 == 0) status++; else return status; /* get version of central unit */ byte2send[0] = 0x21; byte2send[1] = 0x21; #ifdef LI100_USB status2 = send_command_LI100_USB(busnumber, byte2send); #else status2 = send_command_LI100_SERIAL(busnumber, byte2send); #endif if (status2 == 0) status++; else return status; /* get status of central unit */ byte2send[0] = 0x21; byte2send[1] = 0x24; #ifdef LI100_USB status2 = send_command_LI100_USB(busnumber, byte2send); #else status2 = send_command_LI100_SERIAL(busnumber, byte2send); #endif if (status2 == 0) status++; return status; } #ifdef LI100_USB int init_bus_LI100_USB(bus_t busnumber) #else int init_bus_LI100_SERIAL(bus_t busnumber) #endif { int status; int i; unsigned char byte2send[20]; static char *protocols = "N"; buses[busnumber].protocols = protocols; if (init_GA(busnumber, __li100->number_ga)) { __li100->number_ga = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array for accessories"); } if (init_GL(busnumber, __li100->number_gl)) { __li100->number_gl = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array for locomotives"); } syslog_bus(busnumber, DBG_WARN, "debug array for locomotives"); if (init_FB(busnumber, __li100->number_fb * 8)) { __li100->number_fb = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array for feedback"); } status = 0; syslog_bus(busnumber, DBG_DEBUG, "Lenz interface with debug level %d\n", buses[busnumber].debuglevel); #ifdef LI100_USB if (buses[busnumber].type != SERVER_LI100_USB) #else if (buses[busnumber].type != SERVER_LI100_SERIAL) #endif { status = -2; } else { if (buses[busnumber].device.file.fd > 0) status = -3; /* bus is already in use */ } if (status == 0) { __li100->working_LI100 = 0; } if (buses[busnumber].debuglevel < 7) { if (status == 0) #ifdef LI100_USB status = initLine_LI100_USB(busnumber); #else status = initLine_LI100_SERIAL(busnumber); #endif } else buses[busnumber].device.file.fd = 9999; if (status == 0) { __li100->working_LI100 = 1; syslog_bus(busnumber, DBG_INFO, "Version Lenz interface: %d.%d\n", __li100->version_interface / 256, __li100->version_interface % 256); syslog_bus(busnumber, DBG_INFO, "Code Lenz interface: %d%d\n", __li100->code_interface / 16, __li100->code_interface % 16); syslog_bus(busnumber, DBG_INFO, "Version Lenz central unit: %d.%d\n", __li100->version_zentrale / 256, __li100->version_zentrale % 256); /* printf("Code LENZ-Central unit: %d",__li100->code_zentrale); */ __li100->get_addr = 0; /* if version of central unit is greater than 3.0, cleanup stack */ if (__li100->version_zentrale >= 0x0300) { for (;;) { byte2send[0] = 0xe3; byte2send[1] = 0x05; byte2send[2] = 0; byte2send[3] = 0; #ifdef LI100_USB send_command_LI100_USB(busnumber, byte2send); #else send_command_LI100_SERIAL(busnumber, byte2send); #endif if (__li100->get_addr == 0) break; syslog_bus(busnumber, DBG_INFO, "Remove engine with address %d from stack\n", __li100->get_addr & 0x3fff); byte2send[0] = 0xe3; byte2send[1] = 0x44; byte2send[2] = (unsigned char) (__li100->get_addr >> 8); byte2send[3] = (unsigned char) (__li100->get_addr & 0x00FF); #ifdef LI100_USB send_command_LI100_USB(busnumber, byte2send); #else send_command_LI100_SERIAL(busnumber, byte2send); #endif } } /* read all feedbacks for first time */ for (i = 0; i < __li100->number_fb; i++) { /* read bit 0..3 */ byte2send[0] = 0x42; byte2send[1] = i; byte2send[2] = 0x80; #ifdef LI100_USB send_command_LI100_USB(busnumber, byte2send); #else send_command_LI100_SERIAL(busnumber, byte2send); #endif /* read bit 4..7 */ byte2send[0] = 0x42; byte2send[1] = i; byte2send[2] = 0x81; #ifdef LI100_USB send_command_LI100_USB(busnumber, byte2send); #else send_command_LI100_SERIAL(busnumber, byte2send); #endif } } #ifdef LI100_USB syslog_bus(busnumber, DBG_DEBUG, "INIT_BUS_LI100 (usb) finished with code: %d\n", status); #else syslog_bus(busnumber, DBG_DEBUG, "INIT_BUS_LI100 (serial) finished with code: %d\n", status); #endif __li100->last_type = -1; __li100->last_value = -1; __li100->pgm_mode = 0; __li100->emergency_on_LI100 = 0; __li100->extern_engine_ctr = 0; for (i = 0; i < 100; i++) __li100->extern_engine[i] = -1; return status; } /*thread cleanup routine for this bus*/ #ifdef LI100_USB static void end_bus_usb_thread(bus_thread_t * btd) #else static void end_bus_rs232_thread(bus_thread_t * btd) #endif { int result; #ifdef LI100_USB syslog_bus(btd->bus, DBG_INFO, "LI100 bus (usb) terminated."); #else syslog_bus(btd->bus, DBG_INFO, "LI100 bus (serial) terminated."); #endif __li100t->working_LI100 = 0; close_comport(btd->bus); result = pthread_mutex_destroy(&buses[btd->bus].transmit_mutex); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_destroy() failed: %s (errno = %d).", strerror(result), result); } result = pthread_cond_destroy(&buses[btd->bus].transmit_cond); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_init() failed: %s (errno = %d).", strerror(result), result); } free(buses[btd->bus].driverdata); free(btd); } #ifdef LI100_USB void *thr_sendrec_LI100_USB(void *v) #else void *thr_sendrec_LI100_SERIAL(void *v) #endif { unsigned char byte2send[20]; int status; int zaehler1; int last_cancel_state, last_cancel_type; bus_thread_t *btd = (bus_thread_t *) malloc(sizeof(bus_thread_t)); if (btd == NULL) pthread_exit((void *) 1); btd->bus = (bus_t) v; btd->fd = -1; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_cancel_state); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_cancel_type); #ifdef LI100_USB /*register cleanup routine */ pthread_cleanup_push((void *) end_bus_usb_thread, (void *) btd); syslog_bus(btd->bus, DBG_INFO, "LI100 bus (usb) started."); #else /*register cleanup routine */ pthread_cleanup_push((void *) end_bus_rs232_thread, (void *) btd); syslog_bus(btd->bus, DBG_INFO, "LI100 bus (serial) started."); #endif /* initialize tga-structure */ for (zaehler1 = 0; zaehler1 < 50; zaehler1++) __li100t->tga[zaehler1].id = 0; while (1) { pthread_testcancel(); /* syslog(LOG_INFO, "thr_sendrec_LI100 Start in loop"); */ /* Start/Stop */ /* fprintf(stderr, "START/STOP... "); */ if (buses[btd->bus].power_changed == 1) { byte2send[0] = 0x21; byte2send[1] = buses[btd->bus].power_state ? 0x81 : 0x80; #ifdef LI100_USB status = send_command_LI100_USB(btd->bus, byte2send); #else status = send_command_LI100_SERIAL(btd->bus, byte2send); #endif if (status == 0) /* all was OK ? */ buses[btd->bus].power_changed = 0; } #ifdef LI100_USB send_command_gl_LI100_USB(btd->bus); send_command_ga_LI100_USB(btd->bus); check_status_LI100_USB(btd->bus); check_extern_engines_USB(btd->bus); send_command_sm_LI100_USB(btd->bus); #else send_command_gl_LI100_SERIAL(btd->bus); send_command_ga_LI100_SERIAL(btd->bus); check_status_LI100_SERIAL(btd->bus); check_extern_engines_SERIAL(btd->bus); send_command_sm_LI100_SERIAL(btd->bus); #endif check_reset_fb(btd->bus); buses[btd->bus].watchdog = 1; if (usleep(50000) == -1) { syslog_bus(btd->bus, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } } /* End WHILE(1) */ /*run the cleanup routine */ pthread_cleanup_pop(1); return NULL; } #ifdef LI100_USB static void send_command_ga_LI100_USB(bus_t busnumber) #else static void send_command_ga_LI100_SERIAL(bus_t busnumber) #endif { int i, i1; unsigned int temp; unsigned char byte2send[20]; unsigned char status; struct timeval akt_time, cmp_time; gettimeofday(&akt_time, NULL); /* first eventually Decoder switch off */ for (i = 0; i < 50; i++) { if (__li100->tga[i].id > 0) { syslog_bus(busnumber, DBG_DEBUG, "time %i,%i", (int) akt_time.tv_sec, (int) akt_time.tv_usec); syslog_bus(busnumber, DBG_DEBUG, "time %i,%i", (int) akt_time.tv_sec, (int) akt_time.tv_usec); cmp_time = __li100->tga[i].t; /* switch off time reached? */ if (cmpTime(&cmp_time, &akt_time)) { ga_data_t delayedga = __li100->tga[i]; /*align SRCP address (1..2048) to li100 address (0..2047) */ temp = delayedga.id - 1; byte2send[0] = 0x52; byte2send[1] = temp >> 2; byte2send[2] = 0x80; temp &= 0x03; temp <<= 1; byte2send[2] |= temp; if (delayedga.port > 0) { byte2send[2] |= 0x01; } #ifdef LI100_USB send_command_LI100_USB(busnumber, byte2send); #else send_command_LI100_SERIAL(busnumber, byte2send); #endif delayedga.action = 0; setGA(busnumber, delayedga.id, delayedga); __li100->tga[i].id = 0; } } } /* Decoder switch on */ if (!queue_GA_isempty(busnumber)) { ga_data_t gatmp; dequeueNextGA(busnumber, &gatmp); /*align SRCP address (1..2048) to li100 address (0..2047) */ temp = gatmp.id - 1; byte2send[0] = 0x52; byte2send[1] = temp >> 2; byte2send[2] = 0x80; temp &= 0x03; temp <<= 1; byte2send[2] |= temp; if (gatmp.action > 0) { byte2send[2] |= 0x08; } if (gatmp.port > 0) { byte2send[2] |= 0x01; } #ifdef LI100_USB send_command_LI100_USB(busnumber, byte2send); #else send_command_LI100_SERIAL(busnumber, byte2send); #endif status = 1; /*add GA to empty place of delayed switch back queue */ if ((gatmp.action > 0) && (gatmp.activetime > 0)) { for (i1 = 0; i1 < 50; i1++) { if (__li100->tga[i1].id == 0) { gatmp.t = akt_time; gatmp.t.tv_sec += gatmp.activetime / 1000; gatmp.t.tv_usec += (gatmp.activetime % 1000) * 1000; if (gatmp.t.tv_usec > 1000000) { gatmp.t.tv_sec++; gatmp.t.tv_usec -= 1000000; } __li100->tga[i1] = gatmp; status = 0; syslog_bus(busnumber, DBG_DEBUG, "GA %i for switch off at %i,%i on %i", __li100->tga[i1].id, (int) __li100->tga[i1].t.tv_sec, (int) __li100->tga[i1].t.tv_usec, i1); break; } } } if (status) { setGA(busnumber, gatmp.id, gatmp); } } } #ifdef LI100_USB static void send_command_gl_LI100_USB(bus_t busnumber) #else static void send_command_gl_LI100_SERIAL(bus_t busnumber) #endif { int temp; int addr; unsigned char byte2send[20]; int status = -1; gl_data_t gltmp, glakt; /* Locomotive decoder */ /* fprintf(stderr, "LOK's... "); */ /* nur senden, wenn wirklich etwas vorliegt */ if (!queue_GL_isempty(busnumber)) { dequeueNextGL(busnumber, &gltmp); addr = gltmp.id; cacheGetGL(busnumber, addr, &glakt); /* speed, direction or function changed? */ if ((gltmp.direction != glakt.direction) || (gltmp.speed != glakt.speed) || (gltmp.funcs != glakt.funcs)) { /* command for engine should be send */ /* emergency stop for one locomotive */ if (gltmp.direction == 2) { if (__li100->version_zentrale >= 0x0300) { byte2send[0] = 0x92; byte2send[1] = addr >> 8; if (addr > 99) byte2send[1] |= 0xc0; byte2send[2] = addr & 0xff; } else { byte2send[0] = 0x91; byte2send[1] = addr; } #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); #else status = send_command_LI100_SERIAL(busnumber, byte2send); #endif } else { #ifndef LI100_USB // Lenz USB interface started with firmware v3.0, therefore no need to check for versions less v3.0 /* version <= 1.50 */ if (__li100->version_zentrale <= 0x0150) { byte2send[0] = 0xb3; /* address */ byte2send[1] = gltmp.id; /* setting direction and speed */ byte2send[2] = gltmp.speed; if (gltmp.speed > 0) byte2send[2]++; if (gltmp.direction) { byte2send[2] |= 0x40; } if (gltmp.funcs & 1) { byte2send[2] |= 0x20; } /* functions f1..f4 */ byte2send[3] = (gltmp.funcs >> 1) & 0x000F; status = send_command_LI100_SERIAL(busnumber, byte2send); } /* version > 1.50 + < 3.00 */ else { if (__li100->version_zentrale < 0x0300) { byte2send[0] = 0xb4; /* address */ byte2send[1] = gltmp.id; /* mode */ switch (gltmp.n_fs) { case 14: byte2send[4] = 0x00; /* setting direction and speed */ byte2send[2] = gltmp.speed; if (gltmp.speed > 0) byte2send[2]++; if (gltmp.direction) { byte2send[2] |= 0x40; } if (gltmp.funcs & 1) { byte2send[2] |= 0x20; } break; case 27: byte2send[4] = 0x01; /* setting direction and speed */ byte2send[2] = gltmp.speed; if (gltmp.speed > 0) byte2send[2] += 3; if (byte2send[2] & 0x01) byte2send[2] |= 0x20; byte2send[2] >>= 1; if (gltmp.direction) { byte2send[2] |= 0x40; } if (gltmp.funcs & 1) { byte2send[2] |= 0x20; } break; case 28: byte2send[4] = 0x02; /* setting direction and speed */ byte2send[2] = gltmp.speed; if (gltmp.speed > 0) byte2send[2] += 3; if (byte2send[2] & 0x01) byte2send[2] |= 0x20; byte2send[2] >>= 1; if (gltmp.direction) { byte2send[2] |= 0x40; } if (gltmp.funcs & 1) { byte2send[2] |= 0x20; } break; default: byte2send[4] = 0x00; /* setting direction and speed */ byte2send[2] = gltmp.speed; if (gltmp.speed > 0) byte2send[2]++; if (gltmp.direction) { byte2send[2] |= 0x40; } if (gltmp.funcs & 1) { byte2send[2] |= 0x20; } } /* functions f1..f4 */ byte2send[3] = (gltmp.funcs >> 1) & 0x000F; status = send_command_LI100_SERIAL(busnumber, byte2send); } /* version > 3.00 */ /*else if (__li100->version_zentrale >= 0x0300) { */ else { #endif byte2send[0] = 0xe4; /* mode */ switch (gltmp.n_fs) { case 14: byte2send[1] = 0x10; break; case 27: byte2send[1] = 0x11; break; case 28: byte2send[1] = 0x12; break; case 126: byte2send[1] = 0x13; break; default: byte2send[1] = 0x12; } /* high byte of address */ temp = gltmp.id; temp >>= 8; byte2send[2] = temp; if (addr > 99) byte2send[2] |= 0xc0; /* low byte of address */ temp = gltmp.id; temp &= 0x00FF; byte2send[3] = temp; /* setting direction and speed */ byte2send[4] = gltmp.speed; if ((gltmp.n_fs == 27) || (gltmp.n_fs = 28)) { if (gltmp.speed > 0) byte2send[4] += 3; if (byte2send[4] & 0x01) byte2send[4] |= 0x20; byte2send[4] >>= 1; } else { if (gltmp.speed > 0) byte2send[4]++; } if (gltmp.direction) { byte2send[4] |= 0x80; } #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); #else status = send_command_LI100_SERIAL(busnumber, byte2send); #endif /* send functions */ byte2send[0] = 0xe4; /* function group 1: f0..f4 */ byte2send[1] = 0x20; /* high byte of address */ temp = gltmp.id; temp >>= 8; byte2send[2] = temp; if (addr > 99) byte2send[2] |= 0xc0; /* low byte of address */ temp = gltmp.id; temp &= 0x00FF; byte2send[3] = temp; /* setting F0-F4, map: 0 0 0 F0 F4 F3 F2 F1 */ byte2send[4] = (gltmp.funcs >> 1) & 0x00FF; if (gltmp.funcs & 1) { byte2send[4] |= 0x10; } #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); #else status = send_command_LI100_SERIAL(busnumber, byte2send); #endif /*function group 2: f5..f8 */ if (gltmp.n_func > 5) { byte2send[1] = 0x21; /* setting F5-F8, map: 0 0 0 0 F8 F7 F6 F5 */ byte2send[4] = (gltmp.funcs >> 5) & 0x00FF; #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); #else status = send_command_LI100_SERIAL(busnumber, byte2send); #endif } /* function group 3: f9..f12 */ if (gltmp.n_func > 9) { byte2send[1] = 0x22; /* setting F9-F12, map: 0 0 0 0 F12 F11 F10 F9 */ byte2send[4] = (gltmp.funcs >> 9) & 0x00FF; #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); #else status = send_command_LI100_SERIAL(busnumber, byte2send); #endif } /*support for functions > F12 since version 3.6 */ if (__li100->version_zentrale >= 0x0360) { /* function group 4: f13..f20 */ /* map: F20 F19 F18 F17 F16 F15 F14 F13 */ if (gltmp.n_func > 13) { byte2send[1] = 0x23; byte2send[4] = (gltmp.funcs >> 13) & 0xffff; #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); #else status = send_command_LI100_SERIAL(busnumber, byte2send); #endif } /* function group 5: f21..f28 */ /* map: F28 F27 F26 F25 F24 F23 F22 F21 */ if (gltmp.n_func > 21) { byte2send[1] = 0x28; byte2send[4] = (gltmp.funcs >> 21) & 0xffff; #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); #else status = send_command_LI100_SERIAL(busnumber, byte2send); #endif } } #ifndef LI100_USB } /* version > 3.00 */ } #endif } /* gltmp.direction != 2 */ if (status == 0) { cacheSetGL(busnumber, addr, gltmp); } } } } #ifdef LI100_USB static void check_extern_engines_USB(bus_t busnumber) #else static void check_extern_engines_SERIAL(bus_t busnumber) #endif { int i; int tmp_addr; unsigned char byte2send[20]; gl_data_t gltmp; if (__li100->extern_engine_ctr > 0) { for (i = 0; i < 100; i++) { tmp_addr = __li100->extern_engine[i]; if (tmp_addr != -1) { if (__li100->version_zentrale <= 0x0150) { __li100->last_value = tmp_addr; byte2send[0] = 0xa1; /* address */ byte2send[1] = tmp_addr; #ifdef LI100_USB send_command_LI100_USB(busnumber, byte2send); #else send_command_LI100_SERIAL(busnumber, byte2send); #endif } if ((__li100->version_zentrale > 0x0150) && (__li100->version_zentrale < 0x0300)) { __li100->last_value = tmp_addr; cacheGetGL(busnumber, tmp_addr, &gltmp); byte2send[0] = 0xa2; /* address */ byte2send[1] = tmp_addr; /* mode */ switch (gltmp.n_fs) { case 14: byte2send[2] = 0x00; break; case 27: byte2send[2] = 0x01; break; case 28: byte2send[2] = 0x02; break; default: byte2send[2] = 0x02; } #ifdef LI100_USB send_command_LI100_USB(busnumber, byte2send); #else send_command_LI100_SERIAL(busnumber, byte2send); #endif } if (__li100->version_zentrale >= 0x0300) { __li100->last_value = tmp_addr; byte2send[0] = 0xe3; byte2send[1] = 0x00; byte2send[2] = (tmp_addr & 0xff00) >> 8; byte2send[3] = tmp_addr & 0x00ff; #ifdef LI100_USB send_command_LI100_USB(busnumber, byte2send); check_status_LI100_USB(busnumber); #else send_command_LI100_SERIAL(busnumber, byte2send); check_status_LI100_SERIAL(busnumber); #endif } } } } __li100->last_value = -1; } #ifdef LI100_USB static int read_register_LI100_USB(bus_t busnumber, int reg) #else static int read_register_LI100_SERIAL(bus_t busnumber, int reg) #endif { unsigned char byte2send[20]; unsigned char status; byte2send[0] = 0x22; byte2send[1] = 0x11; byte2send[2] = reg; #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); get_status_sm_LI100_USB(busnumber); #else status = send_command_LI100_SERIAL(busnumber, byte2send); get_status_sm_LI100_SERIAL(busnumber); #endif return status; } #ifdef LI100_USB static int write_register_LI100_USB(bus_t busnumber, int reg, int value) #else static int write_register_LI100_SERIAL(bus_t busnumber, int reg, int value) #endif { unsigned char byte2send[20]; unsigned char status; byte2send[0] = 0x23; byte2send[1] = 0x12; byte2send[2] = reg; byte2send[3] = value; #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); #else status = send_command_LI100_SERIAL(busnumber, byte2send); #endif return status; } #ifdef LI100_USB static int read_page_LI100_USB(bus_t busnumber, int cv) #else static int read_page_LI100_SERIAL(bus_t busnumber, int cv) #endif { unsigned char byte2send[20]; unsigned char status; byte2send[0] = 0x22; byte2send[1] = 0x14; byte2send[2] = cv; #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); get_status_sm_LI100_USB(busnumber); #else status = send_command_LI100_SERIAL(busnumber, byte2send); get_status_sm_LI100_SERIAL(busnumber); #endif return status; } #ifdef LI100_USB static int write_page_LI100_USB(bus_t busnumber, int cv, int value) #else static int write_page_LI100_SERIAL(bus_t busnumber, int cv, int value) #endif { unsigned char byte2send[20]; unsigned char status; byte2send[0] = 0x23; byte2send[1] = 0x17; byte2send[2] = cv; byte2send[3] = value; #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); #else status = send_command_LI100_SERIAL(busnumber, byte2send); #endif return status; } #ifdef LI100_USB static int read_cv_LI100_USB(bus_t busnumber, int cv) #else static int read_cv_LI100_SERIAL(bus_t busnumber, int cv) #endif { unsigned char byte2send[20]; unsigned char status; byte2send[0] = 0x22; byte2send[1] = 0x15; byte2send[2] = cv; #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); get_status_sm_LI100_USB(busnumber); #else status = send_command_LI100_SERIAL(busnumber, byte2send); get_status_sm_LI100_SERIAL(busnumber); #endif return status; } #ifdef LI100_USB static int write_cv_LI100_USB(bus_t busnumber, int cv, int value) #else static int write_cv_LI100_SERIAL(bus_t busnumber, int cv, int value) #endif { unsigned char byte2send[20]; unsigned char status; byte2send[0] = 0x23; byte2send[1] = 0x16; byte2send[2] = cv; byte2send[3] = value; #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); #else status = send_command_LI100_SERIAL(busnumber, byte2send); #endif return status; } /* program decoder on the main */ #ifdef LI100_USB static int send_pom_cv_LI100_USB(bus_t busnumber, int addr, int cv, int value) #else static int send_pom_cv_LI100_SERIAL(bus_t busnumber, int addr, int cv, int value) #endif { unsigned char byte2send[20]; unsigned char status; int ret_val; int tmp; cv--; /* send pom-command */ byte2send[0] = 0xE6; byte2send[1] = 0x30; /* high-byte of decoder-address */ tmp = addr >> 8; byte2send[2] = tmp; /* low-byte of decoder-address */ tmp = addr & 0xFF; byte2send[3] = tmp; tmp = 0x7C | ((cv >> 8) & 0x03); byte2send[4] = tmp; byte2send[5] = cv & 0xff; byte2send[6] = value; #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); #else status = send_command_LI100_SERIAL(busnumber, byte2send); #endif ret_val = 0; if (status != 0) ret_val = -1; return ret_val; } /* program decoder on the main */ #ifdef LI100_USB static int send_pom_cvbit_LI100_USB(bus_t busnumber, int addr, int cv, int cvbit, int value) #else static int send_pom_cvbit_LI100_SERIAL(bus_t busnumber, int addr, int cv, int cvbit, int value) #endif { unsigned char byte2send[20]; unsigned char status; int ret_val; int tmp; cv--; /* send pom-command */ byte2send[0] = 0xE6; byte2send[1] = 0x30; /* high-byte of decoder-address */ tmp = addr >> 8; byte2send[2] = tmp; /* low-byte of decoder-address */ tmp = addr & 0xFF; byte2send[3] = tmp; tmp = 0x7C | ((cv >> 8) & 0x03); byte2send[4] = tmp; byte2send[5] = cv & 0xff; byte2send[6] = cvbit; if (value) byte2send[6] |= 0x08; #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); #else status = send_command_LI100_SERIAL(busnumber, byte2send); #endif ret_val = 0; if (status != 0) ret_val = -1; return ret_val; } #ifdef LI100_USB static int term_pgm_LI100_USB(bus_t busnumber) #else static int term_pgm_LI100_SERIAL(bus_t busnumber) #endif { unsigned char byte2send[20]; unsigned char status; /* send command "turn all on" */ byte2send[0] = 0x21; byte2send[1] = 0x81; #ifdef LI100_USB status = send_command_LI100_USB(busnumber, byte2send); #else status = send_command_LI100_SERIAL(busnumber, byte2send); #endif return status; } #ifdef LI100_USB static void send_command_sm_LI100_USB(bus_t busnumber) #else static void send_command_sm_LI100_SERIAL(bus_t busnumber) #endif { /* unsigned char byte2send; */ /* unsigned char status; */ struct _SM smakt; /* Locomotive decoder */ /* fprintf(stderr, "LOK's... "); */ /* nur senden, wenn wirklich etwas vorliegt */ if (!queue_SM_isempty(busnumber)) { dequeueNextSM(busnumber, &smakt); __li100->last_type = smakt.type; __li100->last_typeaddr = smakt.typeaddr; __li100->last_bit = smakt.bit; __li100->last_value = smakt.value; syslog_bus(busnumber, DBG_DEBUG, "in send_command_sm: last_type[%d] = %d", busnumber, __li100->last_type); switch (smakt.command) { case SET: if (smakt.addr == -1) { switch (smakt.type) { case REGISTER: #ifdef LI100_USB write_register_LI100_USB(busnumber, smakt.typeaddr, smakt.value); #else write_register_LI100_SERIAL(busnumber, smakt.typeaddr, smakt.value); #endif break; case CV: #ifdef LI100_USB write_cv_LI100_USB(busnumber, smakt.typeaddr, smakt.value); #else write_cv_LI100_SERIAL(busnumber, smakt.typeaddr, smakt.value); #endif break; /* case CV_BIT: write_cvbit( busnumber, smakt.typeaddr, smakt.bit, smakt.value ); break; */ case PAGE: #ifdef LI100_USB write_page_LI100_USB(busnumber, smakt.typeaddr, smakt.value); #else write_page_LI100_SERIAL(busnumber, smakt.typeaddr, smakt.value); #endif } } else { switch (smakt.type) { case CV: #ifdef LI100_USB send_pom_cv_LI100_USB(busnumber, smakt.addr, smakt.typeaddr, smakt.value); #else send_pom_cv_LI100_SERIAL(busnumber, smakt.addr, smakt.typeaddr, smakt.value); #endif break; case CV_BIT: #ifdef LI100_USB send_pom_cvbit_LI100_USB(busnumber, smakt.addr, smakt.typeaddr, smakt.bit, smakt.value); #else send_pom_cvbit_LI100_SERIAL(busnumber, smakt.addr, smakt.typeaddr, smakt.bit, smakt.value); #endif break; } } break; case GET: switch (smakt.type) { case REGISTER: #ifdef LI100_USB read_register_LI100_USB(busnumber, smakt.typeaddr); #else read_register_LI100_SERIAL(busnumber, smakt.typeaddr); #endif break; case CV: #ifdef LI100_USB read_cv_LI100_USB(busnumber, smakt.typeaddr); #else read_cv_LI100_SERIAL(busnumber, smakt.typeaddr); #endif break; /* case CV_BIT: read_cvbit( busnumber, smakt.typeaddr, smakt.bit ); break; */ case PAGE: #ifdef LI100_USB read_page_LI100_USB(busnumber, smakt.typeaddr); #else read_page_LI100_SERIAL(busnumber, smakt.typeaddr); #endif } break; case VERIFY: break; case INIT: break; case TERM: syslog_bus(busnumber, DBG_DEBUG, "on bus %i pgm_mode is %i", busnumber, __li100->pgm_mode); if (__li100->pgm_mode == 1) { #ifdef LI100_USB term_pgm_LI100_USB(busnumber); #else term_pgm_LI100_SERIAL(busnumber); #endif } break; } } } #ifdef LI100_USB static void get_status_sm_LI100_USB(bus_t busnumber) #else static void get_status_sm_LI100_SERIAL(bus_t busnumber) #endif { unsigned char byte2send[20]; byte2send[0] = 0x21; byte2send[1] = 0x10; #ifdef LI100_USB send_command_LI100_USB(busnumber, byte2send); #else send_command_LI100_SERIAL(busnumber, byte2send); #endif } #ifdef LI100_USB static void check_status_LI100_USB(bus_t busnumber) #else static void check_status_LI100_SERIAL(bus_t busnumber) #endif { int i; int status; /* with debug level beyond DBG_DEBUG, we will not really work on hardware */ if (buses[busnumber].debuglevel <= DBG_DEBUG) { i = 1; while (i > 0) { status = ioctl(buses[busnumber].device.file.fd, FIONREAD, &i); if (status < 0) { char msg[200]; strcpy(msg, strerror(errno)); syslog_bus(busnumber, DBG_ERROR, "readbyte(): IOCTL status: %d with errno = %d: %s", status, errno, msg); } syslog_bus(busnumber, DBG_DEBUG, "readbyte(): (fd = %d), there are %d bytes to read.", buses[busnumber].device.file.fd, i); /* read only, if there is really an input */ if (i > 0) #ifdef LI100_USB status = readAnswer_LI100_USB(busnumber); #else status = readAnswer_LI100_SERIAL(busnumber); #endif } } } #ifdef LI100_USB static int send_command_LI100_USB(bus_t busnumber, const unsigned char *str) #else static int send_command_LI100_SERIAL(bus_t busnumber, const unsigned char *str) #endif { int i, ctr; int status; unsigned char xor = 0x00; /* control-byte for xor */ #ifdef LI100_USB /* header for LI100_USB */ writeByte(busnumber, 0xff, 0); writeByte(busnumber, 0xfe, 0); #endif ctr = str[0] & 0x0f; /* generate length of command */ ctr++; for (i = 0; i < ctr; i++) { /* send command */ xor ^= str[i]; writeByte(busnumber, str[i], 0); } writeByte(busnumber, xor, 0); /* send X-Or-Byte */ #ifdef LI100_USB status = readAnswer_LI100_USB(busnumber); #else status = readAnswer_LI100_SERIAL(busnumber); #endif return status; } #ifdef LI100_USB static int readAnswer_LI100_USB(bus_t busnumber) #else static int readAnswer_LI100_SERIAL(bus_t busnumber) #endif { int status; int i, ctr; int tmp_addr; int message_processed; unsigned char cXor; unsigned char buffer[20]; gl_data_t gltmp, glakt; gltmp.speed = 0; gltmp.funcs = 0; message_processed = 0; status = -1; /* wait for answer */ ctr = 50; while (status == -1) { ctr--; if (ctr < 0) return status; if (usleep(2000) == -1) { syslog_bus(busnumber, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } status = readByte(busnumber, 1, &buffer[0]); #ifdef LI100_USB /* skip LI100_USB-header */ readByte(busnumber, 1, &buffer[0]); readByte(busnumber, 1, &buffer[0]); #endif ctr = buffer[0] & 0x0f; /* generate length of answer */ ctr += 2; /* read answer */ for (i = 1; i < ctr; i++) { readByte(busnumber, 1, &buffer[i]); } cXor = 0; for (i = 0; i < ctr; i++) { cXor ^= buffer[i]; } if (cXor != 0x00) /* must be 0x00 */ status = -1; /* error */ /* li100 reply message */ if (buffer[0] == 0x01) { switch (buffer[1]) { case 0x01: syslog_bus(busnumber, DBG_ERROR, "Interface/PC communication error\n"); break; case 0x02: syslog_bus(busnumber, DBG_ERROR, "Interface/central unit communication error\n"); break; case 0x03: syslog_bus(busnumber, DBG_ERROR, "Unknown error\n"); break; case 0x04: /* command send to central unit (normal operation) */ break; case 0x05: syslog_bus(busnumber, DBG_ERROR, "Central unit can not address LI101F\n"); break; case 0x06: syslog_bus(busnumber, DBG_ERROR, "LI101F buffer overflow\n"); break; default: syslog_bus(busnumber, DBG_ERROR, "Unknown command key received: 0x%02x\n", buffer[1]); break; } message_processed = 1; } /* version-number of interface */ else if (buffer[0] == 0x02) { __li100->version_interface = ((buffer[1] & 0xf0) << 4) + (buffer[1] & 0x0f); __li100->code_interface = (int) buffer[2]; message_processed = 1; } /* power on/off, service mode changes */ else if (buffer[0] == 0x61) { /* power off */ if (buffer[1] == 0x00) { syslog_bus(busnumber, DBG_DEBUG, "on bus %i no power detected; old-state is %i", busnumber, getPower(busnumber)); if ((__li100->emergency_on_LI100 == 0) && (getPower(busnumber))) { setPower(busnumber, 0, "Emergency Stop"); __li100->emergency_on_LI100 = 1; } message_processed = 1; } /* power on */ else if (buffer[1] == 0x01) { syslog_bus(busnumber, DBG_DEBUG, "on bus %i power detected; old-state is %i", busnumber, getPower(busnumber)); if ((__li100->emergency_on_LI100 == 1) || (!getPower(busnumber))) { setPower(busnumber, 1, "No Emergency Stop"); __li100->emergency_on_LI100 = 0; } else if (__li100->pgm_mode == 1) { session_endwait(busnumber, -1); setPower(busnumber, 1, "Service mode end"); __li100->pgm_mode = 0; } message_processed = 1; } /* service mode on */ else if (buffer[1] == 0x02) { if (__li100->pgm_mode == 0) { __li100->pgm_mode = 1; syslog_bus(busnumber, DBG_DEBUG, "Service mode activated on bus %i", busnumber); setPower(busnumber, -1, "Service mode start"); } message_processed = 1; } /*short circuit */ else if (buffer[1] == 0x12) { syslog_bus(busnumber, DBG_WARN, "Short circuit detected on bus %i", busnumber); message_processed = 1; } /*data byte not found */ else if (buffer[1] == 0x13) { if (__li100->last_type != -1) { session_endwait(busnumber, -1); setSM(busnumber, __li100->last_type, -1, __li100->last_typeaddr, __li100->last_bit, __li100->last_value, -1); __li100->last_type = -1; } message_processed = 1; } /*Command station ready */ else if (buffer[1] == 0x11) { syslog_bus(busnumber, DBG_WARN, "Command station ready on bus %i", busnumber); message_processed = 1; } /*Command station busy */ else if (buffer[1] == 0x1f) { syslog_bus(busnumber, DBG_WARN, "Command station busy on bus %i", busnumber); message_processed = 1; } /*Transfer error */ else if (buffer[1] == 0x80) { syslog_bus(busnumber, DBG_WARN, "Transfer error on bus %i", busnumber); message_processed = 1; } /*Command station busy */ else if (buffer[1] == 0x81) { syslog_bus(busnumber, DBG_WARN, "Command station busy on bus %i", busnumber); message_processed = 1; } /*Instruction not supported */ else if (buffer[1] == 0x82) { syslog_bus(busnumber, DBG_WARN, "Instruction not supported on bus %i", busnumber); message_processed = 1; } } /*FIXME: 0x62 and 0x63 are mixed, messing up the "if/else" sequence */ /* 0x62: X-Bus 1 + 2, 0x63: XpressNet */ else if ((buffer[0] == 0x62) || (buffer[0] == 0x63)) { /* version-number of central unit */ if (buffer[1] == 0x21) { __li100->version_zentrale = ((buffer[2] & 0xf0) << 4) + (buffer[2] & 0x0f); if (buffer[0] == 0x63) __li100->code_interface = (int) buffer[3]; else __li100->code_interface = -1; #ifndef LI100_USB /* check for address-range 1..99; 1..256 for version < V3.00 */ if (__li100->version_zentrale < 0x0300) { if (__li100->number_gl > 99) __li100->number_gl = 99; if (__li100->number_ga > 256) __li100->number_ga = 256; } #endif message_processed = 1; } /*central unit status */ else if (buffer[1] == 0x22) { int emergencystop = buffer[2] & 0x01; int emergencyoff = buffer[2] & 0x02; int startmode = buffer[2] & 0x04; int programmingmode = buffer[2] & 0x08; int coldstart = buffer[2] & 0x20; int ramcheckerror = buffer[2] & 0x40; syslog_bus(busnumber, DBG_INFO, "Central unit status: " "emergency stop: %d, " "emergency off: %d, " "start mode: %d, " "programming mode: %d, " "cold start: %d, " "RAM check error: %d\n", emergencystop, emergencyoff, startmode, programmingmode, coldstart, ramcheckerror); message_processed = 1; } } /* answer of programming */ if ((buffer[0] == 0x63) && ((buffer[1] & 0xf0) == 0x10)) { if (__li100->last_type != -1) { session_endwait(busnumber, (int) buffer[3]); setSM(busnumber, __li100->last_type, -1, __li100->last_typeaddr, __li100->last_bit, (int) buffer[3], 0); __li100->last_type = -1; } message_processed = 1; } /*0x83: Locomotive information response */ /*0x84: Locomotive information response (available for operation) not handled yet */ /*0xa3: Locomotive is being operated by another device */ /*0xa4: Locomotive is being operated by another device not handled yet */ else if ((buffer[0] == 0x83) || (buffer[0] == 0xa3)) { if (buffer[0] & 0x20) add_extern_engine(busnumber, buffer[1]); else remove_extern_engine(busnumber, buffer[1]); gltmp.id = buffer[1]; gltmp.direction = (buffer[2] & 0x40) ? 1 : 0; gltmp.speed = buffer[2] & 0x0f; if (gltmp.speed == 1) { gltmp.speed = 0; gltmp.direction = 2; } else { if (gltmp.speed > 0) gltmp.speed--; } gltmp.funcs = ((buffer[3] & 0x0f) << 1); if (buffer[2] & 0x20) gltmp.funcs |= 0x01; /* light is on */ /*functions f5..f12, map: F12 F11 F10 F9 F8 F7 F6 F5 */ unsigned int f5tof12 = buffer[4]; f5tof12 <<= 5; gltmp.funcs |= f5tof12; /* get old data, to send only if something changed */ int result = cacheGetGL(busnumber, gltmp.id, &glakt); /* If GL is unknown, show warning message */ if (SRCP_NODATA == result) { syslog_bus(busnumber, DBG_WARN, "Command for uninitialized GL received (address = %d)", gltmp.id); } gltmp.n_func = glakt.n_func; if ((glakt.speed != gltmp.speed) || (glakt.direction != gltmp.direction) || (glakt.funcs != gltmp.funcs)) cacheSetGL(busnumber, gltmp.id, gltmp); message_processed = 1; } /* Double Header information response (X-Bus V1) */ else if (buffer[0] == 0xc5) { syslog_bus(busnumber, DBG_WARN, "Double Header information response on bus %i " " (not supported)", busnumber); message_processed = 1; } /* XpressNet MU+DH error message response */ else if (buffer[0] == 0xe1) { syslog_bus(busnumber, DBG_WARN, "XpressNet MU+DH error message response on bus %i " " (not supported)", busnumber); switch (buffer[1]) { case 0x81: syslog_bus(busnumber, DBG_WARN, "Locomotive has not been operated on bus %i", busnumber); break; case 0x82: syslog_bus(busnumber, DBG_WARN, "Locomotive operated by another XpressNet " "device on bus %i", busnumber); break; case 0x83: syslog_bus(busnumber, DBG_WARN, "One of the locomotives already is in another " "Multi-Unit or Double Header on bus %i", busnumber); break; case 0x84: syslog_bus(busnumber, DBG_WARN, "The speed of one of the locomotives of the " "Double Header/Multi-Unit is not zero on bus %i", busnumber); break; case 0x85: syslog_bus(busnumber, DBG_WARN, "The locomotive is not in a multi-unit on bus %i", busnumber); break; case 0x86: syslog_bus(busnumber, DBG_WARN, "The locomotive address is not a multi-unit " "base address on bus %i", busnumber); break; case 0x87: syslog_bus(busnumber, DBG_WARN, "It is not possible to delete the locomotive " "on bus %i", busnumber); break; case 0x88: syslog_bus(busnumber, DBG_WARN, "The command station stack is full on bus %i", busnumber); break; default: syslog_bus(busnumber, DBG_WARN, "Unknown error code 0x%02x on bus %i", buffer[1], busnumber); break; } message_processed = 1; } /* Locomotive information for the Multi-unit address */ else if (buffer[0] == 0xe2) { syslog_bus(busnumber, DBG_WARN, "Multi-unit locomotive address response on bus %i " " (not supported)", busnumber); message_processed = 1; } /*Locomotive status response */ else if (buffer[0] == 0xe3) { /* Locomotive information response for address retrieval requests * (XpressNet only)*/ if ((buffer[1] & 0x30) == 0x30) { __li100->get_addr = 256 * (int) buffer[2]; __li100->get_addr += (int) buffer[3]; message_processed = 1; } /* Locomotive is being operated by another device response * (XpressNet only)*/ else if (buffer[1] == 0x40) { tmp_addr = buffer[3]; tmp_addr |= buffer[2] << 8; add_extern_engine(busnumber, tmp_addr); message_processed = 1; } /*not part of SRCP: function type report (switch/button) f0..f12 */ else if (buffer[1] == 0x50) { } /*not part of SRCP: function type report (switch/button) f13..f28 */ else if (buffer[1] == 0x51) { } /*function status report f13..f28 */ else if (buffer[1] == 0x52) { cacheGetGL(busnumber, __li100->get_addr, &gltmp); unsigned int fncblock = buffer[3]; fncblock <<= 8; fncblock |= buffer[2]; fncblock <<= 13; unsigned int tmpfuncs = gltmp.funcs; tmpfuncs &= ~0x1fffe000; tmpfuncs |= fncblock; if (gltmp.funcs != tmpfuncs) cacheSetGL(busnumber, __li100->get_addr, gltmp); } } /* Locomotive information normal locomotive (single traction) */ else if (buffer[0] == 0xe4) { gltmp.id = __li100->last_value & 0x3fff; /*CHECK: __li100->get_addr = gltmp.id; */ /* is engine always allocated by an external device? */ if (!(buffer[1] & 0x08)) { remove_extern_engine(busnumber, __li100->last_value); } gltmp.direction = (buffer[2] & 0x80) ? 1 : 0; switch (buffer[1] & 7) { case 0: /*14 speed steps */ case 4: /*128 speed steps */ gltmp.speed = buffer[2] & 0x7f; if (gltmp.speed == 1) { gltmp.speed = 0; /* gltmp.direction = 2; */ } else { if (gltmp.speed > 0) gltmp.speed--; } break; case 1: /*27 speed steps */ case 2: /*28 speed steps */ gltmp.speed = buffer[2] & 0x7f; gltmp.speed <<= 1; if (gltmp.speed & 0x20) gltmp.speed |= 0x01; gltmp.speed &= 0xdf; if (gltmp.speed == 2) { gltmp.speed = 0; /* gltmp.direction = 2; */ } else { if (gltmp.speed > 0) gltmp.speed -= 3; } break; } /*function map: F12 F11 F10 F9 F8 F7 F6 F5 */ gltmp.funcs = buffer[4]; gltmp.funcs <<= 5; /*function map: 0 0 0 F0 F4 F3 F2 F1 */ unsigned int tmpfuncs = buffer[3] & 0x0F; tmpfuncs <<= 1; if (buffer[3] & 0x10) tmpfuncs |= 0x01; /* light is on */ gltmp.funcs |= tmpfuncs; /* get old data, to send only if something changed */ int result = cacheGetGL(busnumber, gltmp.id, &glakt); /* If GL is unknown, show warning message */ if (SRCP_NODATA == result) { syslog_bus(busnumber, DBG_WARN, "Command for uninitialized GL received (address = %d)", gltmp.id); } gltmp.n_func = glakt.n_func; if ((glakt.speed != gltmp.speed) || (glakt.direction != gltmp.direction) || (glakt.funcs != gltmp.funcs)) cacheSetGL(busnumber, gltmp.id, gltmp); message_processed = 1; } /* Locomotive information for a locomotive in a multi-unit */ else if (buffer[0] == 0xe5) { syslog_bus(busnumber, DBG_WARN, "Multi-unit locomotive response on bus %i " " (not supported)", busnumber); message_processed = 1; } /*Locomotive information for a locomotive in a Double Header */ else if (buffer[0] == 0xe6) { syslog_bus(busnumber, DBG_WARN, "Double header locomotive response on bus %i " " (not supported)", busnumber); message_processed = 1; } /* information about feedback, bit pattern: AAAA AAAA ITTN ZZZZ */ /*0x42: Accessory Decoder information response */ if ((buffer[0] & 0xf0) == 0x40) { ga_data_t gatmp; ctr = buffer[0] & 0xf; for (i = 1; i < ctr; i += 2) { /*check for address type TT, mask: 0110 0000 */ switch (buffer[i + 1] & 0x60) { case 0x00: /* switch-decoder without feedback */ case 0x20: /* switch-decoder with feedback */ gatmp.id = buffer[i]; gatmp.id <<= 2; /*align li100 address (0..2047) to SRCP address (1..2048) */ gatmp.id++; /*check for upper nibble, mask: 0001 0000 */ if (buffer[i + 1] & 0x10) gatmp.id += 2; /*first address, mask 0011 */ tmp_addr = buffer[i + 1] & 0x03; /*position left, mask: 0001 */ if (tmp_addr == 0x01) { gatmp.port = 0; gatmp.action = 1; setGA(busnumber, gatmp.id, gatmp); } /*position right, mask: 0010 */ if (tmp_addr == 0x02) { gatmp.port = 1; gatmp.action = 1; setGA(busnumber, gatmp.id, gatmp); } /*second address, mask 1100 */ tmp_addr = buffer[i + 1] & 0x0C; gatmp.id++; /*position left, mask: 0100 */ if (tmp_addr == 0x04) { gatmp.port = 0; gatmp.action = 1; setGA(busnumber, gatmp.id, gatmp); } /*position right, mask: 1000 */ if (tmp_addr == 0x08) { gatmp.port = 1; gatmp.action = 1; setGA(busnumber, gatmp.id, gatmp); } break; case 0x40: /* feedback-decoder */ setFBmodul(busnumber, (buffer[i] * 2) + ((buffer[i + 1] & 0x10) ? 2 : 1), buffer[i + 1] & 0x0f); break; case 0x60: /* illegal decoder parameter; something in error? */ { char print_buf[300]; int i1; for (i1 = 0; i1 < ctr; i1++) { sprintf(&print_buf[i1 * 5], "0x%02x ", buffer[i1]); } print_buf[i1 * 5] = 0x00; syslog(LOG_INFO, "Illegal feedback received: %s", print_buf); break; } } } message_processed = 1; } else if (buffer[0] == 0xf2) { /* XpresssNet address answer */ if (buffer[1] == 0x01) { syslog_bus(busnumber, DBG_WARN, "XpressNet address changes not handled yet: " "currrent = 0x%02x", buffer[2]); message_processed = 1; } /* baud rate settings answer */ else if (buffer[1] == 0x02) { syslog_bus(busnumber, DBG_WARN, "Baud rate setting changes not handled yet: " "currrent = 0x%02x", buffer[2]); message_processed = 1; } } /* at last catch all unknown command keys and show a warning message */ if (message_processed == 0) { syslog_bus(busnumber, DBG_WARN, "Unknown command key received: 0x%02x 0x%02x", buffer[0], buffer[1]); } } return status; } srcpd-2.1.7/src/srcp-lock.h0000644000175000017500000000040212673554172012422 00000000000000/* $Id: srcp-lock.h 1725 2016-03-20 17:06:01Z gscholz $ */ /* * Vorliegende Software unterliegt der General Public License, * Version 2, 1991. (c) Matthias Trute, 2000-2001. * */ #ifndef _SRCP_LOCK_H #define _SRCP_LOCK_H void startup_LOCK(); #endif srcpd-2.1.7/src/srcp-session.h0000644000175000017500000000406612673553134013164 00000000000000/*************************************************************************** srcp-session.h - description ------------------- begin : Don Apr 25 2002 copyright : (C) 2002 by email : ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef _SRCP_SESSION_H #define _SRCP_SESSION_H #include #include #include "config-srcpd.h" /*session modes*/ typedef enum {smUndefined = 0, smCommand, smInfo} SessionMode; /*session list node to store session data*/ typedef struct sn { sessionid_t session; pthread_t thread; int socket; SessionMode mode; int pipefd[2]; struct sn *next; } session_node_t; void startup_SESSION(); void shutdown_SESSION(); session_node_t* create_anonymous_session(int); void register_session(session_node_t*); void destroy_anonymous_session(session_node_t*); void destroy_session(sessionid_t); void terminate_all_sessions(); bool is_valid_info_session(sessionid_t); void session_enqueue_info_message(sessionid_t, char*); int start_session(session_node_t*); int stop_session(sessionid_t); int describeSESSION(bus_t, sessionid_t, char*); int termSESSION(bus_t, sessionid_t, sessionid_t, char*); int session_lock_wait(bus_t); int session_condt_wait(bus_t, unsigned int timeout, int *result); int session_unlock_wait(bus_t); int session_endwait(bus_t, int returnvalue); #endif srcpd-2.1.7/src/clientservice.h0000644000175000017500000000050310732025401013344 00000000000000/* cvs: $Id: clientservice.h 990 2007-12-18 20:18:43Z gscholz $ */ /* * Vorliegende Software unterliegt der General Public License, * Version 2, 1991. (c) Matthias Trute, 2000-2001. * */ #ifndef _CLIENTSERVICE_H #define _CLIENTSERVICE_H #include "srcp-session.h" void* thr_doClient(void *v); #endif srcpd-2.1.7/src/i2c-dev.c0000664000175000017500000003700214564575125011763 00000000000000/*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /* * i2c-dev: Bus driver for i2c-dev-Interface of the Linux-Kernel * can be used to access hardware found on * http://www.matronix.de/ * * 2002-2005 by Manuel Borchers * */ #include "config.h" #ifdef linux #include #include #include #include /*#ifdef HAVE_LINUX_I2C_H #include #endif*/ #ifdef HAVE_LINUX_I2C_DEV_H #include #endif #ifndef I2C_SLAVE #define I2C_SLAVE 0x0703 #warning "Value for I2C_SLAVE defined due to a problem with system headers." #endif #include "config-srcpd.h" #include "io.h" #include "srcp-fb.h" #include "srcp-ga.h" #include "srcp-power.h" #include "srcp-server.h" #include "srcp-info.h" #include "srcp-error.h" #include "syslogmessage.h" #include "i2c-dev.h" #define __i2cdev ((I2CDEV_DATA*)buses[busnumber].driverdata) static int write_PCF8574(bus_t bus, int addr, uint8_t byte) { int busfd = buses[bus].device.file.fd; int result; result = ioctl(busfd, I2C_SLAVE, addr); if (result < 0) { syslog_bus(bus, DBG_INFO, "Couldn't access address %d (%s)", addr, strerror(errno)); return (result); } /* ret = i2c_smbus_write_byte(busfd, byte); */ if (result < 0) { syslog_bus(bus, DBG_INFO, "Couldn't send byte %d to address %d (%s)", byte, addr, strerror(errno)); return (result); } syslog_bus(bus, DBG_DEBUG, "Sent byte %d to address %d", byte, addr); return (0); } /* Currently feedback is not supported */ /* static int read_PCF8574(bus_t bus, int addr, __u8 *byte) { int busfd = buses[bus].fd; int ret; ret = ioctl(busfd, I2C_SLAVE, addr); if (ret < 0) { syslog_bus(bus, DBG_INFO, "Can't access address %d (%s)", addr, strerror(errno)); return (ret); } ret = i2c_smbus_read_byte(busfd); if (ret < 0) { syslog_bus(bus, DBG_INFO, "Can't read byte from address %d (%s)", addr, strerror(errno)); return (ret); } *byte = 0xFF & (ret); syslog_bus(bus, DBG_DEBUG, "Read byte %d from address %d", *byte, addr); return (ret); } */ /* Write value to a i2c device, determine i2c device by address */ static int write_i2c_dev(bus_t bus, int addr, I2C_VALUE value) { /* Currently we handle only PCF8574 */ if (((addr >= 32) && (addr < 39)) || ((addr >= 56) && (addr < 63))) { return (write_PCF8574(bus, addr, 0xFF & value)); } syslog_bus(bus, DBG_ERROR, "Unsupported i2c device at address %d", addr); return (-1); } static void select_bus(int mult_busnum, bus_t busnumber) { int addr, value = 0; /* addr = 224 + (2 * (int) (mult_busnum / 9)); */ addr = 224; if (mult_busnum > 8) mult_busnum = 0; if (buses[busnumber].power_state == 1) value = 64; value = value | (mult_busnum % 9); write_PCF8574(busnumber, (addr >> 1), value); /* result = ioctl(busfd, I2C_SLAVE, (addr >> 1)); writeByte(busnumber, value, 1); */ } /* Handle set command of GA */ static int handle_i2c_set_ga(bus_t bus, ga_data_t * gatmp) { I2C_ADDR i2c_addr; I2C_VALUE i2c_val; I2C_VALUE value; I2C_PORT port; I2C_MUX_BUS mult_busnum; I2CDEV_DATA *data = (I2CDEV_DATA *) buses[bus].driverdata; int addr; int reset_old_value; int ga_min_active_time = data->ga_min_active_time; int ga_hardware_inverters = data->ga_hardware_inverters; addr = gatmp->id; port = gatmp->port; value = gatmp->action; mult_busnum = (addr / 256) + 1; select_bus(mult_busnum, bus); i2c_addr = (addr % 256); /* gettimeofday(gatmp->tv[0], NULL); */ if (gatmp->activetime >= 0) { gatmp->activetime = (gatmp->activetime > ga_min_active_time) ? gatmp->activetime : ga_min_active_time; reset_old_value = 1; } else { gatmp->activetime = ga_min_active_time; /* always wait minimum time */ reset_old_value = 0; } syslog_bus(bus, DBG_DEBUG, "i2c_addr = %d on multiplexed bus #%d", i2c_addr, mult_busnum); /* port: 0 - direct write of value to device */ /* other - select port pins directly, value = {0,1} */ if (port == 0) { /* write directly to device */ if (ga_hardware_inverters == 1) { i2c_val = ~value; } else { i2c_val = value; } } else { /* set bit for selected port to 1 */ I2C_VALUE pin_bit = 1 << (port - 1); value = (value & 1); i2c_val = data->i2c_values[i2c_addr][mult_busnum - 1]; if (ga_hardware_inverters == 1) { value = (~value) & 1; } if (value != 0) { /* Set bit */ i2c_val |= pin_bit; } else { /* Reset bit */ i2c_val &= (~pin_bit); } } if (write_i2c_dev(bus, i2c_addr, i2c_val) < 0) { syslog_bus(bus, DBG_ERROR, "Device not found at address %d", addr); return (-1); } if (usleep((unsigned long) gatmp->activetime * 1000) == -1) { syslog_bus(bus, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } if (reset_old_value == 1) { if (write_i2c_dev (bus, i2c_addr, data->i2c_values[i2c_addr][mult_busnum - 1]) < 0) { syslog_bus(bus, DBG_ERROR, "Device not found at address %d", addr); return (-1); } if (usleep((unsigned long) gatmp->activetime * 1000) == -1) { syslog_bus(bus, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } } else { data->i2c_values[i2c_addr][mult_busnum - 1] = i2c_val; } return (0); } int readconfig_I2C_DEV(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber) { buses[busnumber].driverdata = malloc(sizeof(I2CDEV_DATA)); if (buses[busnumber].driverdata == NULL) { syslog_bus(busnumber, DBG_ERROR, "Memory allocation error in module '%s'.", node->name); return 0; } buses[busnumber].type = SERVER_I2C_DEV; buses[busnumber].init_func = &init_bus_I2C_DEV; buses[busnumber].thr_func = &thr_sendrec_I2C_DEV; strcpy(buses[busnumber].description, "GA POWER DESCRIPTION"); __i2cdev->number_ga = 0; __i2cdev->multiplex_buses = 0; __i2cdev->ga_hardware_inverters = 0; __i2cdev->ga_reset_devices = 1; __i2cdev->ga_min_active_time = 75; xmlNodePtr child = node->children; xmlChar *txt = NULL; while (child != NULL) { if ((xmlStrncmp(child->name, BAD_CAST "text", 4) == 0) || (xmlStrncmp(child->name, BAD_CAST "comment", 7) == 0)) { /* just do nothing, it is only formatting text or a comment */ } /* else if (xmlStrcmp(child->name, BAD_CAST "number_gl") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __i2cdev->number_gl = atoi((char*) txt); xmlFree(txt); } } */ else if (xmlStrcmp(child->name, BAD_CAST "multiplex_buses") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __i2cdev->multiplex_buses = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "ga_hardware_inverters") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __i2cdev->ga_hardware_inverters = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "ga_reset_devices") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __i2cdev->ga_reset_devices = atoi((char *) txt); xmlFree(txt); } } else syslog_bus(busnumber, DBG_WARN, "WARNING, unknown tag found: \"%s\"!\n", child->name);; child = child->next; } /* init the stuff */ __i2cdev->number_ga = 256 * (__i2cdev->multiplex_buses); if (init_GA(busnumber, __i2cdev->number_ga)) { __i2cdev->number_ga = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array for accessoires"); } /* if (init_GL(busnumber, __i2cdev->number_gl)) { __i2cdev->number_gl = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array for locomotives"); } */ /* if (init_FB(busnumber, __i2cdev->number_ga)) { __i2cdev->number_ga = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array for feedback"); } */ return (1); } int init_lineI2C_DEV(bus_t bus) { int fd; if (buses[bus].debuglevel > 0) { syslog_bus(bus, DBG_INFO, "Opening i2c-dev: %s", buses[bus].device.file.path); } fd = open(buses[bus].device.file.path, O_RDWR); if (fd == -1) { syslog_bus(bus, DBG_ERROR, "Open device '%s' failed: %s " "(errno = %d).\n", buses[bus].device.file.path, strerror(errno), errno); } return fd; } static void reset_ga(bus_t busnumber) { /* reset ga devices to values stored in data->i2c_values */ I2CDEV_DATA *data = (I2CDEV_DATA *) buses[busnumber].driverdata; int i, multiplexer_adr; int multiplex_buses; multiplex_buses = data->multiplex_buses; if (multiplex_buses > 0) { for (multiplexer_adr = 1; multiplexer_adr <= multiplex_buses; multiplexer_adr++) { select_bus(multiplexer_adr, busnumber); /* first PCF 8574 P */ for (i = 32; i <= 39; i++) { write_PCF8574(busnumber, i, data->i2c_values[i][multiplexer_adr - 1]); } /* now PCF 8574 AP */ for (i = 56; i <= 63; i++) { write_PCF8574(busnumber, i, data->i2c_values[i][multiplexer_adr - 1]); } } select_bus(0, busnumber); } } /* * * Initializes the I2C-Bus and sets fd for the bus * If bus unavailable, fd = -1 * */ int init_bus_I2C_DEV(bus_t i) { I2CDEV_DATA *data = (I2CDEV_DATA *) buses[i].driverdata; int ga_hardware_inverters; int j, multiplexer_adr; int multiplex_buses; char buf; static char *protocols = "P"; buses[i].protocols = protocols; syslog_bus(i, DBG_INFO, "i2c-dev init: bus #%ld, debug %d", i, buses[i].debuglevel); /* init the hardware interface */ if (buses[i].debuglevel < 6) { buses[i].device.file.fd = init_lineI2C_DEV(i); } else { buses[i].device.file.fd = -1; } /* init software */ ga_hardware_inverters = data->ga_hardware_inverters; multiplex_buses = data->multiplex_buses; memset(data->i2c_values, 0, sizeof(I2C_DEV_VALUES)); if (ga_hardware_inverters == 1) { buf = 0xFF; } else { buf = 0x00; } /* preload data->i2c_values */ if (multiplex_buses > 0) { for (multiplexer_adr = 1; multiplexer_adr <= multiplex_buses; multiplexer_adr++) { /* first PCF 8574 P */ for (j = 32; j <= 39; j++) { data->i2c_values[j][multiplexer_adr - 1] = buf; } /* now PCF 8574 AP */ for (j = 56; j <= 63; j++) { data->i2c_values[j][multiplexer_adr - 1] = buf; } } } syslog_bus(i, DBG_INFO, "i2c-dev init done"); return 0; } /*thread cleanup routine for this bus*/ static void end_bus_thread(bus_thread_t * btd) { int result; syslog_bus(btd->bus, DBG_INFO, "i2c-dev bus terminated."); close(buses[btd->bus].device.file.fd); result = pthread_mutex_destroy(&buses[btd->bus].transmit_mutex); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_destroy() failed: %s (errno = %d).", strerror(result), result); } result = pthread_cond_destroy(&buses[btd->bus].transmit_cond); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_init() failed: %s (errno = %d).", strerror(result), result); } free(buses[btd->bus].driverdata); free(btd); } /* * * The main worker-thread for the i2c-dev device * Enters an endless loop that waits for commands and * executes them. * * Currently we only support GA-devices * */ void *thr_sendrec_I2C_DEV(void *v) { char msg[1000]; ga_data_t gatmp; int last_cancel_state, last_cancel_type; bus_thread_t *btd = (bus_thread_t *) malloc(sizeof(bus_thread_t)); if (btd == NULL) pthread_exit((void *) 1); btd->bus = (bus_t) v; btd->fd = -1; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_cancel_state); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_cancel_type); /*register cleanup routine */ pthread_cleanup_push((void *) end_bus_thread, (void *) btd); syslog_bus(btd->bus, DBG_INFO, "i2c-dev bus started (device = %s).", buses[btd->bus].device.file.path); I2CDEV_DATA *data = buses[btd->bus].driverdata; int ga_reset_devices = data->ga_reset_devices; buses[btd->bus].watchdog = 1; /* command processing starts here */ while (true) { /* process POWER changes */ if (buses[btd->bus].power_changed == 1) { /* dummy select, power state is directly read by select_bus() */ select_bus(0, btd->bus); buses[btd->bus].power_changed = 0; infoPower(btd->bus, msg); enqueueInfoMessage(msg); if ((ga_reset_devices == 1) && (buses[btd->bus].power_state == 1)) { reset_ga(btd->bus); } } /* do nothing, if power is off */ if (buses[btd->bus].power_state == 0) { if (usleep(1000) == -1) { syslog_bus(btd->bus, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } continue; } buses[btd->bus].watchdog = 4; /* process GA commands */ if (!queue_GA_isempty(btd->bus)) { dequeueNextGA(btd->bus, &gatmp); handle_i2c_set_ga(btd->bus, &gatmp); setGA(btd->bus, gatmp.id, gatmp); select_bus(0, btd->bus); buses[btd->bus].watchdog = 6; } if (usleep(1000) == -1) { syslog_bus(btd->bus, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } } /*run the cleanup routine */ pthread_cleanup_pop(1); return NULL; } #endif srcpd-2.1.7/src/srcpd.c0000664000175000017500000002374714556420265011653 00000000000000/*************************************************************************** srcpd.c - description ----------------------- begin : Wed Jul 4 2001 copyright : (C) 2001 - 2007 by the srcpd team ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include "config-srcpd.h" #include "netservice.h" #include "srcp-descr.h" #include "srcp-fb.h" #include "srcp-ga.h" #include "srcp-gl.h" #include "srcp-info.h" #include "srcp-lock.h" #include "srcp-server.h" #include "srcp-session.h" #include "srcp-time.h" #include "syslogmessage.h" #define MAXFD 64 /* for daemon_init */ /* structures to determine which port needs to be served */ fd_set rfds; int maxfd; char conffile[255]; extern char PIDFILENAME; void CreatePIDFile(int pid) { FILE *f; f = fopen(&PIDFILENAME, "wb"); if (f == NULL) syslog(LOG_INFO, "Opening pid file '%s' failed: %s (errno = %d)\n", &PIDFILENAME, strerror(errno), errno); else { fprintf(f, "%d\n", pid); fflush(f); fclose(f); } } void DeletePIDFile() { int result; result = unlink(&PIDFILENAME); if (result != 0) syslog(LOG_INFO, "Unlinking pid file '%s' failed: %s (errno = %d)\n", &PIDFILENAME, strerror(errno), errno); } /* initialisize all found buses, communication line devices are opened */ void init_all_buses() { bus_t i; maxfd = 0; FD_ZERO(&rfds); for (i = 0; i <= num_buses; i++) { if (buses[i].init_func != NULL) { /* initialize each bus and report error on failure */ if ((*buses[i].init_func) (i) != 0) { syslog(LOG_INFO, "Initialization of bus %ld failed.", i); exit(EXIT_FAILURE); } /* Configure descriptors for Selectrix module to throw SIGIO */ if ((buses[i].device.file.fd != -1) && (buses[i].type == SERVER_SELECTRIX)) { FD_SET(buses[i].device.file.fd, &rfds); maxfd = (maxfd > buses[i].device.file.fd ? maxfd : buses[i].device.file.fd); fcntl(buses[i].device.file.fd, F_SETOWN, getpid()); #ifdef linux fcntl(buses[i].device.file.fd, F_SETFL, FASYNC); #endif } } } } /*create all kind of server threads*/ void create_all_threads() { set_server_state(ssInitializing); create_time_thread(); create_all_bus_threads(); create_netservice_thread(); set_server_state(ssRunning); syslog(LOG_INFO, "All threads started"); } /* cancel all server threads*/ void cancel_all_threads() { int result; syslog(LOG_INFO, "Terminating SRCP service..."); server_shutdown(); /* if service is going to terminate, first wait 2 seconds, * this is according to protocol specification */ result = sleep(2); if (result != 0) { syslog_bus(0, DBG_ERROR, "sleep() interrupted, %d seconds left\n", result); } cancel_netservice_thread(); cancel_time_thread(); cancel_all_bus_threads(); terminate_all_sessions(); syslog(LOG_INFO, "SRCP service terminated."); } /* signal SIGHUP(1) caught */ void sighup_handler(int s) { signal(s, sighup_handler); syslog(LOG_INFO, "SIGHUP(1) received, " "going to re-read configuration file."); cancel_all_threads(); if (0 == readConfig(conffile)) { syslog_bus(0, DBG_ERROR, "Error, no valid bus setup found in " "configuration file. Terminating.\n"); exit(EXIT_FAILURE); } init_all_buses(); create_all_threads(); } /* signal SIGTERM(15) caught */ void sigterm_handler(int s) { syslog(LOG_INFO, "SIGTERM(15) received! Terminating ..."); set_server_state(ssTerminating); } /** sigio_handler * Signal handler for I/O interrupt signal (SIGIO) */ void sigio_handler(int status) { struct timeval tv; int retval; bus_t i; /* Don't wait */ tv.tv_sec = 0; tv.tv_usec = 0; /* select descriptor that triggered SIGIO */ retval = select(maxfd + 1, &rfds, NULL, NULL, &tv); /* something strange happened, report error */ if (retval == -1) { syslog_bus(0, DBG_ERROR, "Select failed: %s (errno = %d)\n", strerror(errno), errno); } /* nothing changed */ else if (retval == 0) { return; } /* find bus matching the triggering descriptor */ else { for (i = 1; i <= num_buses; i++) { if ((buses[i].device.file.fd != -1) && (FD_ISSET(buses[i].device.file.fd, &rfds))) { if (buses[i].sigio_reader != NULL) { (*buses[i].sigio_reader) (i); } } } } } void install_signal_handlers() { struct sigaction saio; signal(SIGTERM, sigterm_handler); signal(SIGHUP, sighup_handler); /* important, because write() on sockets should return errors */ signal(SIGPIPE, SIG_IGN); /* Register signal handler for I/O interrupt handling */ saio.sa_flags = 0; saio.sa_handler = &sigio_handler; sigemptyset(&saio.sa_mask); sigaction(SIGIO, &saio, NULL); } /* * daemonize process * this is from "UNIX Network Programming, W. R. Stevens et al." */ int daemon_init(int flag) { int i, result; pid_t pid; if (!flag) { return (0); } if ((pid = fork()) < 0) return (-1); else if (pid) /* parent terminates */ _exit(0); /* child 1 continues... */ /* become session leader */ if (setsid() < 0) return (-1); signal(SIGHUP, SIG_IGN); if ((pid = fork()) < 0) return (-1); else if (pid) /* child 1 terminates */ _exit(0); /* child 2 continues... */ /* change working directory */ result = chdir("/"); if (-1 == result) { printf("chdir() failed: %s (errno = %d)\n", strerror(errno), errno); } /* close off file descriptors */ for (i = 0; i < MAXFD; i++) close(i); /* redirect stdin, stdout, and stderr to /dev/null */ open("/dev/null", O_RDONLY); open("/dev/null", O_RDWR); open("/dev/null", O_RDWR); /* success */ return 0; } int main(int argc, char **argv) { int sleep_ctr, c; int daemonflag = 1; /* First: Init the device data used internally */ startup_GL(); startup_GA(); startup_FB(); startup_INFO(); startup_LOCK(); startup_DESCRIPTION(); startup_TIME(); startup_SERVER(); startup_SESSION(); snprintf(conffile, sizeof(conffile), "%s/srcpd.conf", SYSCONFDIR); /* read command line parameters */ opterr = 0; while ((c = getopt(argc, argv, "f:hvn")) != EOF) { switch (c) { case 'f': snprintf(conffile, sizeof(conffile), "%s", optarg); break; case 'v': printf(WELCOME_MSG); exit(EXIT_FAILURE); break; case 'n': daemonflag = 0; break; case 'h': printf(WELCOME_MSG); printf("Usage: srcpd -f -v -h\n\n"); printf("Options:\n"); printf(" -v Show program version and quit.\n"); printf(" -f Use another config file (default %s).\n", conffile); printf(" -n Do not daemonize at startup.\n"); printf(" -h Show this help text and quit.\n"); exit(EXIT_FAILURE); break; default: printf("Unknown option: %c\n", c); printf("Use: \"srcpd -h\" for help, terminating.\n"); exit(EXIT_FAILURE); break; } } openlog("srcpd", LOG_PID, LOG_USER); syslog_bus(0, DBG_INFO, "conffile = \"%s\"\n", conffile); if (0 == readConfig(conffile)) { syslog_bus(0, DBG_ERROR, "Error, no valid bus setup found in " "configuration file '%s'.\n", conffile); exit(EXIT_FAILURE); } /*daemonize process */ if (0 != daemon_init(daemonflag)) { syslog_bus(0, DBG_ERROR, "Daemonization failed!\n"); exit(EXIT_FAILURE); } CreatePIDFile(getpid()); syslog(LOG_INFO, "%s", WELCOME_MSG); install_signal_handlers(); init_all_buses(); create_all_threads(); sleep_ctr = 10; /* * Main loop: Wait for _real_ tasks: shutdown, reset and watch for * hanging processes */ while (true) { if (get_server_state() == ssTerminating) break; /* wait 100 ms */ if (usleep(100000) == -1) { syslog_bus(0, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } sleep_ctr--; if (sleep_ctr == 0) { /* clear LOCKs */ unlock_gl_bytime(); unlock_ga_bytime(); run_bus_watchdog(); sleep_ctr = 10; } } cancel_all_threads(); if (seteuid(0) != 0) { syslog(LOG_INFO, "seteuid() failed: %s (errno = %d)\n", strerror(errno), errno); } shutdown_SESSION(); shutdown_GA(); shutdown_GL(); DeletePIDFile(); closelog(); exit(EXIT_SUCCESS); } srcpd-2.1.7/src/hsi-88.c0000644000175000017500000003670114564574703011556 00000000000000/*************************************************************************** hsi-88.c - description ------------------- begin : Mon Oct 29 2001 copyright : (C) 2001 by Dipl.-Ing. Frank Schmischke email : frank.schmischke@t-online.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include #include #include "config-srcpd.h" #include "hsi-88.h" #include "io.h" #include "srcp-fb.h" #include "syslogmessage.h" #define __hsi ((HSI_88_DATA*)buses[busnumber].driverdata) static int working_HSI88; int readConfig_HSI_88(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber) { int number; buses[busnumber].driverdata = malloc(sizeof(struct _HSI_88_DATA)); if (buses[busnumber].driverdata == NULL) { syslog_bus(busnumber, DBG_ERROR, "Memory allocation error in module '%s'.", node->name); return 0; } buses[busnumber].type = SERVER_HSI_88; buses[busnumber].init_func = &init_bus_HSI_88; buses[busnumber].thr_func = &thr_sendrec_HSI_88; buses[busnumber].flags |= FB_ORDER_0; buses[busnumber].flags |= FB_16_PORTS; strcpy(buses[busnumber].description, "FB POWER"); __hsi->refresh = 10000; __hsi->number_fb[0] = 0; __hsi->number_fb[1] = 0; __hsi->number_fb[2] = 0; xmlNodePtr child = node->children; xmlChar *txt = NULL; while (child != NULL) { if ((xmlStrncmp(child->name, BAD_CAST "text", 4) == 0) || (xmlStrncmp(child->name, BAD_CAST "comment", 7) == 0)) { /* just do nothing, it is only formatting text or a comment */ } else if (xmlStrcmp(child->name, BAD_CAST "refresh") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __hsi->refresh = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "fb_delay_time_0") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { set_min_time(busnumber, atoi((char *) txt)); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "number_fb_left") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __hsi->number_fb[0] = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "number_fb_center") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __hsi->number_fb[1] = atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "number_fb_right") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __hsi->number_fb[2] = atoi((char *) txt); xmlFree(txt); } } else syslog_bus(busnumber, DBG_WARN, "WARNING, unknown tag found: \"%s\"!\n", child->name); ; child = child->next; } /* create an array for feedbacks; */ number = __hsi->number_fb[0]; number += __hsi->number_fb[1]; number += __hsi->number_fb[2]; if (init_FB(busnumber, number * 16)) { __hsi->number_fb[0] = 0; __hsi->number_fb[1] = 0; __hsi->number_fb[2] = 0; syslog_bus(busnumber, DBG_ERROR, "Can't create array for feedback"); } return (1); } static int open_lineHSI88(bus_t bus, char *name) { int fd; struct termios interface; syslog_bus(bus, DBG_DEBUG, "try opening serial line %s for 9600 baud\n", name); fd = open(name, O_RDWR); if (fd == -1) { syslog_bus(bus, DBG_ERROR, "Open serial line failed: %s (errno = %d).\n", strerror(errno), errno); } else { tcgetattr(fd, &interface); interface.c_oflag = ONOCR; interface.c_cflag = CS8 | CRTSCTS | CSTOPB | CLOCAL | CREAD | HUPCL; interface.c_iflag = IGNBRK; interface.c_lflag = IEXTEN; cfsetispeed(&interface, B9600); cfsetospeed(&interface, B9600); interface.c_cc[VMIN] = 0; interface.c_cc[VTIME] = 1; tcsetattr(fd, TCSANOW, &interface); } return fd; } static int init_lineHSI88(bus_t busnumber, int modules_left, int modules_center, int modules_right) { int status; int i; int ctr; int result; unsigned char byte2send; unsigned char rr; result = sleep(1); if (result != 0) { syslog_bus(busnumber, DBG_ERROR, "sleep() interrupted, %d seconds left\n", result); } byte2send = 0x0d; for (i = 0; i < 10; i++) writeByte(busnumber, byte2send, 500); while (readByte(busnumber, 0, &rr) == 0) { } /* HSI-88 initialize */ /* switch off terminal-mode */ i = 1; while (i) { byte2send = 't'; writeByte(busnumber, byte2send, 0); byte2send = 0x0d; writeByte(busnumber, byte2send, 200); rr = 0; ctr = 0; status = readByte(busnumber, 0, &rr); while (rr != 't') { if (usleep(100000) == -1) { syslog_bus(busnumber, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } status = readByte(busnumber, 0, &rr); if (status == -1) ctr++; if (ctr > 20) return -1; } readByte(busnumber, 0, &rr); if (rr == '0') i = 0; readByte(busnumber, 0, &rr); } /* looking for version of HSI */ byte2send = 'v'; writeByte(busnumber, byte2send, 0); byte2send = 0x0d; writeByte(busnumber, byte2send, 500); for (i = 0; i < 49; i++) { status = readByte(busnumber, 1, &rr); if (status == -1) break; __hsi->v_text[i] = (char) rr; } __hsi->v_text[i] = 0x00; syslog_bus(busnumber, DBG_DEBUG, "HSI version: %s\n", __hsi->v_text); status = 1; while (status) { /* initialise module-numbers */ /* up to "GO", non feedback-module */ byte2send = 's'; writeByte(busnumber, byte2send, 0); byte2send = 0; writeByte(busnumber, byte2send, 0); writeByte(busnumber, byte2send, 0); writeByte(busnumber, byte2send, 0); byte2send = 0x0d; writeByte(busnumber, byte2send, 0); byte2send = 0x0d; writeByte(busnumber, byte2send, 0); byte2send = 0x0d; writeByte(busnumber, byte2send, 0); byte2send = 0x0d; writeByte(busnumber, byte2send, 5); rr = 0; readByte(busnumber, 1, &rr); /* read answer (three bytes) */ while (rr != 's') { if (usleep(100000) == -1) { syslog_bus(busnumber, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } readByte(busnumber, 0, &rr); } readByte(busnumber, 0, &rr); /* number of given modules */ status = 0; } return 0; } int init_bus_HSI_88(bus_t busnumber) { int fd; int status; int anzahl; status = 0; syslog_bus(busnumber, DBG_DEBUG, "HSI-88 with debuglevel %d\n", buses[busnumber].debuglevel); if (buses[busnumber].type != SERVER_HSI_88) { status = -2; } else { if (buses[busnumber].device.file.fd > 0) status = -3; /* bus is already in use */ } if (status == 0) { working_HSI88 = 0; anzahl = __hsi->number_fb[0]; anzahl += __hsi->number_fb[1]; anzahl += __hsi->number_fb[2]; if (anzahl > 31) { syslog_bus(busnumber, DBG_ERROR, "Number of feedback-modules greater than 31!"); status = -4; } } if (buses[busnumber].debuglevel < 7) { if (status == 0) { fd = open_lineHSI88(busnumber, buses[busnumber].device.file.path); if (fd > 0) { buses[busnumber].device.file.fd = fd; status = init_lineHSI88(busnumber, __hsi->number_fb[0], __hsi->number_fb[1], __hsi->number_fb[2]); } else status = -5; } } else buses[busnumber].device.file.fd = 9999; if (status == 0) working_HSI88 = 1; syslog_bus(busnumber, DBG_DEBUG, "INIT_BUS_HSI with code: %d\n", status); return status; } /*thread cleanup routine for this bus*/ static void end_bus_thread(bus_thread_t * btd) { int result; syslog_bus(btd->bus, DBG_INFO, "HSI-88 bus terminated."); working_HSI88 = 0; close_comport(btd->bus); result = pthread_mutex_destroy(&buses[btd->bus].transmit_mutex); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_destroy() failed: %s (errno = %d).", strerror(result), result); } result = pthread_cond_destroy(&buses[btd->bus].transmit_cond); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_init() failed: %s (errno = %d).", strerror(result), result); } free(buses[btd->bus].driverdata); free(btd); } void *thr_sendrec_HSI_88(void *v) { int refresh_time; int anzahl, i, temp; unsigned char byte2send; unsigned char rr; int status; int result; int zaehler1; int last_cancel_state, last_cancel_type; bus_thread_t *btd = (bus_thread_t *) malloc(sizeof(bus_thread_t)); if (btd == NULL) pthread_exit((void *) 1); btd->bus = (bus_t) v; btd->fd = -1; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_cancel_state); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_cancel_type); /*register cleanup routine */ pthread_cleanup_push((void *) end_bus_thread, (void *) btd); syslog_bus(btd->bus, DBG_INFO, "HSI-88 bus startet (device = %s).", buses[btd->bus].device.file.path); refresh_time = ((HSI_88_DATA *) buses[btd->bus].driverdata)->refresh; zaehler1 = 0; i = 0; temp = 1; if (buses[btd->bus].debuglevel <= DBG_DEBUG) { status = 1; while (status) { /* Modulbelegung initialisieren */ byte2send = 's'; writeByte(btd->bus, byte2send, 0); byte2send = ((HSI_88_DATA *) buses[btd->bus].driverdata)->number_fb[0]; writeByte(btd->bus, byte2send, 0); byte2send = ((HSI_88_DATA *) buses[btd->bus].driverdata)->number_fb[1]; writeByte(btd->bus, byte2send, 0); byte2send = ((HSI_88_DATA *) buses[btd->bus].driverdata)->number_fb[2]; writeByte(btd->bus, byte2send, 0); byte2send = 0x0d; writeByte(btd->bus, byte2send, 0); byte2send = 0x0d; writeByte(btd->bus, byte2send, 0); byte2send = 0x0d; writeByte(btd->bus, byte2send, 0); byte2send = 0x0d; writeByte(btd->bus, byte2send, 200); rr = 0; readByte(btd->bus, 0, &rr); /* read answer (three bytes) */ while (rr != 's') { if (usleep(100000) == -1) { syslog_bus(btd->bus, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } readByte(btd->bus, 0, &rr); } readByte(btd->bus, 0, &rr); /* number of given modules */ anzahl = (int) rr; syslog_bus(btd->bus, DBG_INFO, "Number of modules: %i", anzahl); anzahl -= ((HSI_88_DATA *) buses[btd->bus].driverdata)->number_fb[0]; anzahl -= ((HSI_88_DATA *) buses[btd->bus].driverdata)->number_fb[1]; anzahl -= ((HSI_88_DATA *) buses[btd->bus].driverdata)->number_fb[2]; /* HSI initialisation correct? */ if (anzahl == 0) { status = 0; } else { syslog_bus(btd->bus, DBG_ERROR, "error while initialising"); result = sleep(1); if (result != 0) { syslog_bus(btd->bus, DBG_ERROR, "sleep() interrupted, %d seconds left\n", result); } while (readByte(btd->bus, 0, &rr) == 0) { } } } } while (true) { pthread_testcancel(); if (buses[btd->bus].debuglevel <= DBG_DEBUG) { rr = 0; while (rr != 'i') { /* first check here for reset of feedbacks (do this check at the end, we will not run, until get new changes from HSI) */ check_reset_fb(btd->bus); if (usleep(refresh_time) == -1) { syslog_bus(btd->bus, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } readByte(btd->bus, 0, &rr); } readByte(btd->bus, 1, &rr); /* number of given modules */ anzahl = (int) rr; for (zaehler1 = 0; zaehler1 < anzahl; zaehler1++) { readByte(btd->bus, 1, &rr); i = rr; readByte(btd->bus, 1, &rr); temp = rr; temp <<= 8; readByte(btd->bus, 1, &rr); setFBmodul(btd->bus, i, temp | rr); syslog_bus(btd->bus, DBG_DEBUG, "feedback %i with 0x%04x", i, temp | rr); } readByte(btd->bus, 1, &rr); /* */ } else { /* only for testing */ setFBmodul(btd->bus, 1, temp); i++; temp <<= 1; if (i > 16) { i = 0; temp = 1; } result = sleep(2); if (result != 0) { syslog_bus(btd->bus, DBG_ERROR, "sleep() interrupted, %d seconds left\n", result); } } } /*run the cleanup routine */ pthread_cleanup_pop(1); return NULL; } srcpd-2.1.7/src/srcp-power.c0000644000175000017500000000243411342547242012620 00000000000000/* $Id: srcp-power.c 1456 2010-02-28 20:01:39Z gscholz $ */ /* * Vorliegende Software unterliegt der General Public License, * Version 2, 1991. (c) Matthias Trute, 2000-2001. */ #include #include #include "config-srcpd.h" #include "srcp-error.h" #include "srcp-info.h" #include "srcp-power.h" int setPower(bus_t bus, int state, char *msg) { gettimeofday(&buses[bus].power_change_time, NULL); buses[bus].power_state = (state == -1) ? 0 : state; /* buses[bus].power_state = state; */ strcpy(buses[bus].power_msg, msg); buses[bus].power_changed = (state == -1) ? 0 : 1; /* buses[bus].power_changed = 1; */ /* Resume thread to transmit power change */ resume_bus_thread(bus); return SRCP_OK; } int getPower(bus_t bus) { return buses[bus].power_state; } int infoPower(bus_t bus, char *msg) { sprintf(msg, "%lu.%.3lu 100 INFO %ld POWER %s %s\n", buses[bus].power_change_time.tv_sec, buses[bus].power_change_time.tv_usec / 1000, bus, buses[bus].power_state ? "ON" : "OFF", buses[bus].power_msg); return SRCP_INFO; } int initPower(bus_t bus) { return SRCP_OK; } int termPower(bus_t bus) { if (1 == getPower(bus)) return setPower(bus, 0, "Device Termination"); return SRCP_OK; } srcpd-2.1.7/src/loopback.h0000644000175000017500000000103712673514675012330 00000000000000/* $Id: loopback.h 1720 2016-03-20 12:38:21Z gscholz $ */ #ifndef _LOOPBACK_H #define _LOOPBACK_H #include /*xmlDocPtr, xmlNodePtr*/ typedef struct _LOOPBACK_DATA { int number_ga; int number_gl; int number_fb; ga_data_t tga[50]; } LOOPBACK_DATA; int readconfig_LOOPBACK(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber); int init_bus_LOOPBACK(bus_t ); int init_gl_LOOPBACK(gl_data_t *); int init_ga_LOOPBACK(ga_data_t *); int getDescription_LOOPBACK(char *reply); void* thr_sendrec_LOOPBACK(void *); #endif srcpd-2.1.7/src/ttycygwin.h0000644000175000017500000000161710763545202012567 00000000000000/*************************************************************************** * copyright : (C) 2002 by Guido Scholz * * mail : guido.scholz@bayernline.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef TTYCYGWIN_H #define TTYCYGWIN_H #include "config.h" #ifdef NO_CFMAKERAW int cfmakeraw(struct termios *termios_p); #endif #endif srcpd-2.1.7/src/portio.c0000644000175000017500000001112411342547242012027 00000000000000/** * C Implementation: portio * * Description: * A wrapper around the serial interface (termios) * * Author: Ing. Gerard van der Sel * * Copyright: See COPYING file that comes with this distribution * * Information about configuring the Comport is found on: * Serial programming HOW-TO: * http://www.tldp.org/HOWTO/Serial-Programming-HOWTO/index.html * Test for serial transmission and reception for thread and interrupt control * http://www.easysw.com/~mike/serial */ #include /* for strerror() */ #include /* for errno */ #include #include #include #ifdef __CYGWIN__ #include /*for FIONREAD */ #endif #include "config-srcpd.h" #include "ttycygwin.h" #include "portio.h" #include "syslogmessage.h" /** * open_port: * Open and initialise the serial port * Port is opened for read/write * 8 bits and 1 stop bit, no parity. * No timeout at reading the port * Input: Number of the bus * Output: >=0 a device is successfully attached * <0 a error is reported. */ int open_port(bus_t bus) { int serial; struct termios settings; serial = open(buses[bus].device.file.path, O_RDWR | O_NOCTTY); if (serial < 0) { syslog_bus(bus, DBG_ERROR, "Open serial line '%s' failed: %s (errno = %d)\n", buses[bus].device.file.path, strerror(errno), errno); buses[bus].device.file.fd = -1; return -errno; } buses[bus].device.file.fd = serial; /* Get default settings from OS */ tcgetattr(serial, &buses[bus].device.file.devicesettings); /* Ignore default setting from the OS */ bzero(&settings, sizeof(struct termios)); /* Setup settings for serial port */ /* Baud rate, enable read, local mode, 8 bits, 1 stop bit, no parity */ settings.c_cflag = buses[bus].device.file.baudrate | CREAD | CLOCAL | CS8; /* No parity control or generation */ settings.c_iflag = IGNPAR; settings.c_oflag = 0; settings.c_lflag = 0; settings.c_cc[VMIN] = 1; /* Block size is 1 character */ settings.c_cc[VTIME] = 0; /* never a timeout */ /* Apply baud rate (new style) */ cfsetospeed(&settings, buses[bus].device.file.baudrate); cfsetispeed(&settings, buses[bus].device.file.baudrate); /* Apply settings for serial port */ tcsetattr(serial, TCSANOW, &settings); /* Flush serial buffers */ tcflush(serial, TCIFLUSH); tcflush(serial, TCOFLUSH); return serial; } /** * close_port: * closes a comport and restores its old settings */ void close_port(bus_t bus) { tcsetattr(buses[bus].device.file.fd, TCSANOW, &buses[bus].device.file.devicesettings); close(buses[bus].device.file.fd); buses[bus].device.file.fd = -1; } /** * write_port */ void write_port(bus_t bus, unsigned char b) { ssize_t i; i = 0; if (buses[bus].debuglevel <= DBG_DEBUG) { /* Wait for transmit queue to go empty */ tcdrain(buses[bus].device.file.fd); i = write(buses[bus].device.file.fd, &b, 1); } if (i < 0) { /* Error reported from write */ syslog_bus(bus, DBG_ERROR, "write_port(): Failed for %s (errno = %d)\n", strerror(errno), errno); } if (i == 0) { /* Error reported from write */ syslog_bus(bus, DBG_ERROR, "write_port(): No data written to port.\n"); } } /** * read_port */ unsigned int read_port(bus_t bus) { ssize_t i; unsigned int in; /* Default value in case of no real port or debugging */ in = 0x00; if (buses[bus].debuglevel <= DBG_DEBUG) { /* read input port */ i = read(buses[bus].device.file.fd, &in, 1); /* Error reading port */ if (i < 0) { syslog_bus(bus, DBG_ERROR, "read_port(): Failed for %s (errno = %d)\n", strerror(errno), errno); in = 0x200 + errno; /* Result all blocked */ } /* Empty port buffer */ if (i == 0) { syslog_bus(bus, DBG_ERROR, "read_port(): Port buffer empty.\n"); in = 0x1FF; /* Result all blocked */ } } return in; } /** * check_port */ int check_port(bus_t bus) { int temp; int result; result = ioctl(buses[bus].device.file.fd, FIONREAD, &temp); if (result == -1) { syslog_bus(bus, DBG_ERROR, "ioctl() failed for %s (errno = %d)\n", strerror(errno), errno); } return (temp > 0 ? -1 : 0); } srcpd-2.1.7/src/m605x.h0000644000175000017500000000156112673514675011417 00000000000000/* cvs: $Id: m605x.h 1720 2016-03-20 12:38:21Z gscholz $ */ /* * Vorliegende Software unterliegt der General Public License, * Version 2, 1991. (c) Matthias Trute, 2000-2001. * */ #ifndef _M605X_H #define _M605X_H #include /*xmlDocPtr, xmlNodePtr*/ #define M6020_MODE 0x0001 /* Subtyp zum M605X */ typedef struct _M6051_DATA { int number_fb; int number_ga; int number_gl; int cmd32_pending; int flags; unsigned int ga_min_active_time; unsigned int pause_between_cmd; unsigned int pause_between_bytes; } M6051_DATA; int readconfig_m605x(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber); int init_line6051(bus_t bus); int init_bus_M6051(bus_t bus); int init_gl_M6051(gl_data_t *gl); int init_ga_M6051(ga_data_t *ga); int getDescription_M6051(char *reply); void *thr_sendrec_M6051(void *); #endif srcpd-2.1.7/src/dccar.h0000664000175000017500000000111313663753750011606 00000000000000/* $Id: dccar.c 2012-02-19 15:00 achim_marikar $ */ #ifndef _DCCAR_H #define _DCCAR_H #include #include "srcp-gl.h" #define DCCAR 0 #define INFRACAR 1 typedef struct _DCCAR_DATA { int mode; int number_gl; unsigned int pause_between_cmd; } DCCAR_DATA; int readconfig_DCCAR(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber); int init_bus_DCCAR(bus_t ); int init_gl_DCCAR(gl_data_t *); int getDescription_DCCAR(char *reply); void* thr_sendrec_DCCAR(void *); void set_address_bytes(unsigned char[3], int); void write_command(unsigned char*, int, int, bus_t); #endif srcpd-2.1.7/src/ttycygwin.c0000644000175000017500000000232311342547242012555 00000000000000/*************************************************************************** * copyright : (C) 2005 by Guido Scholz * * mail : guido.scholz@bayernline.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include "ttycygwin.h" /* cfmakeraw() support for cygwin */ #ifdef NO_CFMAKERAW int cfmakeraw(struct termios *termios_p) { termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); termios_p->c_oflag &= ~OPOST; termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); termios_p->c_cflag &= ~(CSIZE | PARENB); termios_p->c_cflag |= CS8; return 1; } #endif srcpd-2.1.7/src/loconet.c0000664000175000017500000011046714564575735012213 00000000000000/* $Id: loconet.c 1788 2024-02-19 06:57:33Z gscholz $ */ /* * loconet: loconet/srcp gateway */ #include #include #include #include #include #include #include #include #include #include "config.h" #ifdef HAVE_LINUX_SERIAL_H #include #else #warning "MS100 support for Linux only!" #endif #include "config-srcpd.h" #include "io.h" #include "loconet.h" #include "srcp-fb.h" #include "srcp-ga.h" #include "srcp-gl.h" #include "srcp-sm.h" #include "srcp-power.h" #include "srcp-server.h" #include "srcp-time.h" #include "srcp-info.h" #include "srcp-session.h" #include "srcp-error.h" #include "syslogmessage.h" #define __loconet ((LOCONET_DATA*)buses[busnumber].driverdata) #define __loconett ((LOCONET_DATA*)buses[btd->bus].driverdata) static int init_gl_LOCONET(gl_data_t *); static int init_ga_LOCONET(ga_data_t *); /** * Read and analyze the XML subtree for the configuration. * */ int readConfig_LOCONET(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber) { xmlNodePtr child = node->children; xmlChar *txt; buses[busnumber].driverdata = malloc(sizeof(struct _LOCONET_DATA)); if (buses[busnumber].driverdata == NULL) { syslog_bus(busnumber, DBG_ERROR, "Memory allocation error in module '%s'.", node->name); return 0; } buses[busnumber].type = SERVER_LOCONET; buses[busnumber].init_func = &init_bus_LOCONET; buses[busnumber].thr_func = &thr_sendrec_LOCONET; buses[busnumber].init_gl_func = &init_gl_LOCONET; buses[busnumber].init_ga_func = &init_ga_LOCONET; __loconet->number_fb = 2048; /* max address for OPC_INPUT_REP (10+1 bit) */ __loconet->number_ga = 2048; /* max address for OPC_SW_REQ */ __loconet->number_gl = 9999; /* DCC address range */ __loconet->loconetID = 0x50; /* Loconet ID */ buses[busnumber].device.file.baudrate = B57600; memset(__loconet->slotmap, 0, sizeof(__loconet->slotmap)); strcpy(buses[busnumber].description, "GA GL FB POWER DESCRIPTION"); while (child != NULL) { if ((xmlStrncmp(child->name, BAD_CAST "text", 4) == 0) || (xmlStrncmp(child->name, BAD_CAST "comment", 7) == 0)) { /* just do nothing, it is only formatting text or a comment */ } else if (xmlStrcmp(child->name, BAD_CAST "loconet-id") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { __loconet->loconetID = (unsigned char) atoi((char *) txt); xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "sync-time-from-loconet") == 0) { txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { if (xmlStrcmp(txt, BAD_CAST "yes") == 0) { __loconet->flags |= LN_FLAG_GETTIME; } else { __loconet->flags &= ~LN_FLAG_GETTIME; } xmlFree(txt); } } else if (xmlStrcmp(child->name, BAD_CAST "ms100") == 0) { #ifdef HAVE_LINUX_SERIAL_H txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); if (txt != NULL) { if (xmlStrcmp(txt, BAD_CAST "yes") == 0) { __loconet->flags |= LN_FLAG_MS100; } else { __loconet->flags &= ~LN_FLAG_MS100; } xmlFree(txt); } #endif } else syslog_bus(busnumber, DBG_WARN, "WARNING, unknown tag found: \"%s\"!\n", child->name);; child = child->next; } /* while */ if (init_FB(busnumber, __loconet->number_fb)) { syslog_bus(busnumber, DBG_ERROR, "Can't create array for feedback"); } if (init_GA(busnumber, __loconet->number_ga)) { syslog_bus(busnumber, DBG_ERROR, "Can't create array for GA"); } if (init_GL(busnumber, __loconet->number_gl)) { syslog_bus(busnumber, DBG_ERROR, "Can't create array for GL"); } return (1); } static int cacheGetSlotNumberforAddr(bus_t busnumber, unsigned int addr) { int i; syslog_bus(busnumber, DBG_DEBUG, "looking up slot number for address %d", addr); for (i = 1; i < 128; i++) { if (__loconet->slotmap[i] == addr) { syslog_bus(busnumber, DBG_DEBUG, "found slot %d for address %d", i, addr); return i; } } return -1; } static int init_lineLOCONET_serial(bus_t busnumber) { int fd; int result; struct termios interface; fd = open(buses[busnumber].device.file.path, O_RDWR | O_NDELAY | O_NOCTTY); if (fd == -1) { syslog_bus(busnumber, DBG_ERROR, "Device open failed: %s (errno = %d). " "Terminating...\n", strerror(errno), errno); return 1; } buses[busnumber].device.file.fd = fd; #ifdef HAVE_LINUX_SERIAL_H if ((__loconet->flags & LN_FLAG_MS100) == LN_FLAG_MS100) { struct serial_struct serial; struct termios tios; unsigned int cm; result = ioctl(fd, TIOCGSERIAL, &serial); if (result == -1) { syslog_bus(busnumber, DBG_ERROR, "ioctl() failed: %s (errno = %d)\n", strerror(errno), errno); } serial.custom_divisor = 7; serial.flags &= ~ASYNC_USR_MASK; serial.flags |= ASYNC_SPD_CUST | ASYNC_LOW_LATENCY; result = ioctl(fd, TIOCSSERIAL, &serial); if (result == -1) { syslog_bus(busnumber, DBG_ERROR, "ioctl() failed: %s (errno = %d)\n", strerror(errno), errno); } tcgetattr(fd, &tios); tios.c_iflag = IGNBRK | IGNPAR; tios.c_oflag = 0; tios.c_cflag = CS8 | CREAD | CLOCAL; tios.c_lflag = 0; cfsetospeed(&tios, buses[busnumber].device.file.baudrate); tcsetattr(fd, TCSANOW, &tios); tcflow(fd, TCOON); tcflow(fd, TCION); result = ioctl(fd, TIOCMGET, &cm); if (result == -1) { syslog_bus(busnumber, DBG_ERROR, "ioctl() failed: %s (errno = %d)\n", strerror(errno), errno); } cm &= ~TIOCM_DTR; cm |= TIOCM_RTS | TIOCM_CTS; result = ioctl(fd, TIOCMSET, &cm); if (result == -1) { syslog_bus(busnumber, DBG_ERROR, "ioctl() failed: %s (errno = %d)\n", strerror(errno), errno); } tcflush(fd, TCOFLUSH); tcflush(fd, TCIFLUSH); } else { #endif tcgetattr(fd, &interface); interface.c_oflag = ONOCR; interface.c_cflag = CS8 | CLOCAL | CREAD | HUPCL; if ((buses[busnumber].device.file.settings & SER_FC_HARD) == SER_FC_HARD) { interface.c_cflag |= CRTSCTS; syslog_bus(busnumber, DBG_DEBUG, "using hardware flow control (CRTRTS)"); } if ((buses[busnumber].device.file.settings & SER_FC_SOFT) == SER_FC_SOFT) { interface.c_oflag |= IXON; syslog_bus(busnumber, DBG_DEBUG, "using soft flow control (XON/XOFF)"); } interface.c_iflag = IGNBRK; interface.c_lflag = IEXTEN; interface.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); cfsetispeed(&interface, buses[busnumber].device.file.baudrate); cfsetospeed(&interface, buses[busnumber].device.file.baudrate); interface.c_cc[VMIN] = 0; interface.c_cc[VTIME] = 0; tcsetattr(fd, TCSANOW, &interface); #ifdef HAVE_LINUX_SERIAL_H } #endif return 1; } static int init_lineLOCONET_lbserver(bus_t busnumber) { struct addrinfo hints; struct addrinfo *result, *rp; int sfd = -1; int err; char msg[256]; memset(&hints, '\0', sizeof(hints)); /* Set preferred network connection options, for Cygwin use IPv4-only * as IPv6 is not supported yet */ #if defined(__CYGWIN__) || defined(__OpenBSD__) hints.ai_family = AF_INET; hints.ai_protocol = IPPROTO_TCP; #else hints.ai_flags = AI_ADDRCONFIG; #endif hints.ai_socktype = SOCK_STREAM; err = getaddrinfo(buses[busnumber].device.net.hostname, buses[busnumber].device.net.port, &hints, &result); if (err != 0) { syslog_bus(busnumber, DBG_ERROR, "getaddrinfo: %s", gai_strerror(err)); return 0; } for (rp = result; rp != NULL; rp = rp->ai_next) { sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sfd == -1) continue; alarm(30); /*?*/ if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) break; /* Success */ alarm(0); /*?*/ close(sfd); } if (rp == NULL) { /* No address succeeded */ syslog_bus(busnumber, DBG_ERROR, "Could not connect Loconet network device\n"); return -1; } freeaddrinfo(result); /* No longer needed */ /*start communication*/ err = socket_readline(sfd, msg, sizeof(msg) - 1); /* client terminated connection */ if (0 == err) { shutdown(sfd, SHUT_RDWR); return 0; } /* read errror */ if (-1 == err) { syslog_bus(busnumber, DBG_ERROR, "Socket read failed: %s (errno = %d)\n", strerror(errno), errno); return (-1); } syslog_bus(busnumber, DBG_INFO, "connected to %s", msg); buses[busnumber].device.net.sockfd = sfd; return 1; } static int init_lineLOCONET(bus_t busnumber) { DeviceState rc = devNONE; switch (buses[busnumber].devicetype) { case HW_FILENAME: rc = init_lineLOCONET_serial(busnumber); break; case HW_NETWORK: rc = init_lineLOCONET_lbserver(busnumber); break; } buses[busnumber].devicestate = rc; return rc; } /** * */ static int init_gl_LOCONET(gl_data_t *gl) { /* this is a complex transaction 1. send out a BF Message. 2. wait for the E7 response, if a B4 comes, the slot table is full, exit 3. check the slot status. If it is IN_USE or CONSISTED, mark the address as (SRCP-)locked and exit 4. mark the slot as IN_USE with a BA message */ return SRCP_OK; } /** * GA don't need initialization */ static int init_ga_LOCONET(ga_data_t *ga) { return SRCP_OK; } /* * @param srcp busnumber * @return 0 if OK, -1 on error */ int init_bus_LOCONET(bus_t busnumber) { int result = 0; static char *protocols = "LPMN"; buses[busnumber].protocols = protocols; __loconet->sent_packets = __loconet->recv_packets = 0; __loconet->ibufferin = 0; syslog_bus(busnumber, DBG_INFO, "Loconet init: bus #%d, debug %d", busnumber, buses[busnumber].debuglevel); if (buses[busnumber].debuglevel <= 5) result = (init_lineLOCONET(busnumber) == 0) ? -1 : 0; syslog_bus(busnumber, DBG_INFO, "Loconet bus %ld init done", busnumber); return result; } static unsigned char ln_checksum(const unsigned char *cmd, int len) { unsigned char chksum = 0xff; for (int i = 0; i < len; i++) { chksum ^= cmd[i]; } return chksum; } static int ln_read_serial(bus_t busnumber, unsigned char *cmd, int len) { /* two tasks: first check the serial line for a character, append it to the buffer. Second: check the buffer for a complete loconet packet, remove it from the buffer and transfer it to the caller if complete. */ int fd = buses[busnumber].device.file.fd; fd_set fds; struct timeval t = { 0, 0 }; int retval; unsigned char c; ssize_t pktlen = 0; FD_ZERO(&fds); FD_SET(fd, &fds); retval = select(fd + 1, &fds, NULL, NULL, &t); /* read data from locobuffer, we skip everthing before the first ln-packet later */ if (retval > 0 && FD_ISSET(fd, &fds)) { pktlen = read(fd, &c, 1); __loconet->ibuffer[__loconet->ibufferin++] = c; } /* now examine the buffer */ __loconet->ibufferout = 0; if (__loconet->ibufferin < 2) return (0); /* first skip everything up to the next loconet packet start */ while ((__loconet->ibuffer[__loconet->ibufferout] & 0x80) != 0x80) __loconet->ibufferout++; switch (__loconet->ibuffer[__loconet->ibufferout] & 0xe0) { case 0x80: pktlen = 2; break; case 0xa0: pktlen = 4; break; case 0xc0: pktlen = 6; break; case 0xe0: pktlen = __loconet->ibuffer[__loconet->ibufferout + 1]; break; } /* complete packet ? */ if (__loconet->ibufferout + pktlen > __loconet->ibufferin) { return (0); } syslog_bus(busnumber, DBG_DEBUG, "got a packet size %d, first 2 byte: 0x%02x%02x ", pktlen, __loconet->ibuffer[__loconet->ibufferout], __loconet->ibuffer[__loconet->ibufferout + 1]); /* copy the packet to the transfer buffer and mark the input buffer empty */ memcpy(cmd, &__loconet->ibuffer[__loconet->ibufferout], pktlen); __loconet->ibufferin = 0; __loconet->recv_packets++; return pktlen; } static int ln_read_lbserver(bus_t busnumber, unsigned char *cmd, int len) { int fd = buses[busnumber].device.net.sockfd; fd_set fds; struct timeval t = { 0, 0 }; int retval = 0; char line[256]; ssize_t result; FD_ZERO(&fds); FD_SET(fd, &fds); retval = select(fd + 1, &fds, NULL, NULL, &t); if (retval > 0 && FD_ISSET(fd, &fds)) { result = socket_readline(fd, line, sizeof(line) - 1); /* client terminated connection */ if (0 == result) { shutdown(fd, SHUT_RDWR); close(fd); buses[busnumber].devicestate = devFAIL; return 0; } /* read errror */ else if (-1 == result) { buses[busnumber].devicestate = devFAIL; shutdown(fd, SHUT_RDWR); close(fd); syslog_bus(busnumber, DBG_WARN, "Socket read failed: %s (errno = %d)\n", strerror(errno), errno); return 0; } /* line may begin with SENT message: last command was sent (or not) RECEIVE message: new message from Loconet VERSION text: VERSION information about the server */ if (strstr(line, "RECEIVE ")) { /* we have a fixed format */ size_t len = strlen(line) - 7; int pktlen = len / 3; int i; char *d; for (i = 0; i < pktlen; i++) { cmd[i] = strtol(line + 7 + 3 * i, &d, 16); /* syslog_bus(busnumber, DBG_DEBUG, " * %d %d ", i, cmd[i]); */ } retval = pktlen; } __loconet->recv_packets++; } else if (retval == -1) { syslog_bus(busnumber, DBG_ERROR, "Select failed: %s (errno = %d)\n", strerror(errno), errno); } return retval; } static int ln_read(bus_t busnumber, unsigned char *cmd, int len) { int rc = 0; /* re-establish a lost connection, nothing else can be done at this point */ while (buses[busnumber].devicestate != devOK) { sleep(1); init_lineLOCONET(busnumber); } switch (buses[busnumber].devicetype) { case HW_FILENAME: rc = ln_read_serial(busnumber, cmd, len); break; case HW_NETWORK: rc = ln_read_lbserver(busnumber, cmd, len); break; } if (rc > 0) { syslog_bus(busnumber, DBG_DEBUG, "received Loconet packet with OPC 0x%02X. %s to " "send commands to loconet", cmd[0], cmd[0] & 0x08 ? "block" : "ok"); } return rc; } static int ln_write_lbserver(long int busnumber, const unsigned char *cmd, unsigned char len) { unsigned char i; ssize_t result; char msg[256], tmp[10]; snprintf(msg, sizeof(msg), "SEND"); for (i = 0; i < len; i++) { snprintf(tmp, sizeof(tmp), " %02X", cmd[i]); strcat(msg, tmp); } strcat(msg, "\r\n"); result = writen(buses[busnumber].device.net.sockfd, msg, strlen(msg)); if (result == -1) { buses[busnumber].devicestate = devFAIL; shutdown(buses[busnumber].device.net.sockfd, SHUT_RDWR); close(buses[busnumber].device.net.sockfd); syslog_bus(busnumber, DBG_WARN, "Socket write failed: %s (errno = %d)\n", strerror(errno), errno); } __loconet->sent_packets++; return 0; } static int ln_write_serial(bus_t busnumber, const unsigned char *cmd, unsigned char len) { unsigned char i; for (i = 0; i < len; i++) { writeByte(busnumber, cmd[i], 0); } __loconet->sent_packets++; return 0; } static int ln_write(bus_t busnumber, const unsigned char *cmd, unsigned char len) { syslog_bus(busnumber, DBG_DEBUG, "sent Loconet packet with OPC 0x%02X, %d bytes", cmd[0], len); switch (buses[busnumber].devicetype) { case HW_FILENAME: return ln_write_serial(busnumber, cmd, len); break; case HW_NETWORK: return ln_write_lbserver(busnumber, cmd, len); break; } return 0; } /*thread cleanup routine for this bus*/ static void end_bus_thread(bus_thread_t * btd) { int result; syslog_bus(btd->bus, DBG_INFO, "Loconet bus terminated."); switch (buses[btd->bus].devicetype) { case HW_FILENAME: close(buses[btd->bus].device.file.fd); break; case HW_NETWORK: shutdown(buses[btd->bus].device.net.sockfd, SHUT_RDWR); close(buses[btd->bus].device.net.sockfd); break; } syslog_bus(btd->bus, DBG_INFO, "Loconet bus: %u packets sent, %u packets received", __loconett->sent_packets, __loconett->recv_packets); result = pthread_mutex_destroy(&buses[btd->bus].transmit_mutex); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_destroy() failed: %s (errno = %d).", strerror(result), result); } result = pthread_cond_destroy(&buses[btd->bus].transmit_cond); if (result != 0) { syslog_bus(btd->bus, DBG_WARN, "pthread_mutex_init() failed: %s (errno = %d).", strerror(result), result); } free(buses[btd->bus].driverdata); free(btd); } /* check if the loconet is available, there are two message transfers, * that shall not be disturbed */ static int ln_sendmessage(bus_t bus, int ln_packetlen, unsigned char *ln_packet) { ln_packet[ln_packetlen - 1] = ln_checksum(ln_packet, ln_packetlen - 1); if (ln_packet[0] != OPC_IDLE) { ln_write(bus, ln_packet, ln_packetlen); return 0; } return 1; } /* static int speed_list[] = {28,28,14,128,28,0,0,128}; */ void *thr_sendrec_LOCONET(void *v) { unsigned char ln_packet[128]; /* max length is coded with 7 bit */ unsigned char ln_packetlen = 2; unsigned int addr, twomessageflag; unsigned int startup_slot_index = 1; /* read the slot numbers upon start up */ /*int code, src, dst, data[8], i; */ int value, port, tmp; int speed = 0; char msg[110]; ga_data_t gatmp; gl_data_t gltmp; int last_cancel_state, last_cancel_type; bus_thread_t *btd = (bus_thread_t *) malloc(sizeof(bus_thread_t)); if (btd == NULL) pthread_exit((void *) 1); btd->bus = (bus_t) v; btd->fd = -1; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_cancel_state); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_cancel_type); /*register cleanup routine */ pthread_cleanup_push((void *) end_bus_thread, (void *) btd); while (true) { pthread_testcancel(); buses[btd->bus].watchdog = 1; memset(ln_packet, 0, sizeof(ln_packet)); twomessageflag = 0; /* first action is always a read _from_ Loconet */ if ((ln_packetlen = ln_read(btd->bus, ln_packet, sizeof(ln_packet))) > 1) { twomessageflag = (ln_packet[0] & 0x08) ? 0 : 1; /* block:ok */ switch (ln_packet[0]) { /* basic operations, 2byte Commands on Loconet */ case OPC_GPOFF: buses[btd->bus].power_state = 0; strcpy(buses[btd->bus].power_msg, "from Loconet"); infoPower(btd->bus, msg); enqueueInfoMessage(msg); break; case OPC_GPON: buses[btd->bus].power_state = 1; strcpy(buses[btd->bus].power_msg, "from Loconet"); infoPower(btd->bus, msg); enqueueInfoMessage(msg); break; /* 4byte Commands and Reports on Loconet */ /* loco data, unfortunatly with slot addresses and not decoder addresses */ case OPC_LOCO_SPD: /* A0 */ addr = ln_packet[1]; speed = ln_packet[2]; syslog_bus(btd->bus, DBG_DEBUG, "Set loco speed (OPC_LOCO_SPD: /* A0 */) %d: %d", addr, speed); if (__loconett->slotmap[addr] == 0) { syslog_bus(btd->bus, DBG_DEBUG, "slot %d still unknown", addr); } else { syslog_bus(btd->bus, DBG_DEBUG, "GL decoder address %d found in slot %d", __loconett->slotmap[addr], addr); cacheGetGL(btd->bus, __loconett->slotmap[addr], &gltmp); if (speed == 1) { /* gltmp.direction = 2; */ gltmp.speed = 0; } else { gltmp.speed = speed; } cacheSetGL(btd->bus, __loconett->slotmap[addr], gltmp); } break; case OPC_LOCO_DIRF: /* A1 */ addr = ln_packet[1]; if (__loconett->slotmap[addr] == 0) { syslog_bus(btd->bus, DBG_DEBUG, "slot %d still unknown", addr); } else { syslog_bus(btd->bus, DBG_DEBUG, "GL decoder address %d found in slot %d", __loconett->slotmap[addr], addr); cacheGetGL(btd->bus, __loconett->slotmap[addr], &gltmp); tmp = gltmp.funcs & 0xffe0; /* bit shuffling */ tmp |= (ln_packet[2] & 0x0010) >> 4 | (ln_packet[2] & 0x000f) << 1; gltmp.funcs = tmp; gltmp.direction = (ln_packet[2] & DIRF_DIR) ? 0 : 1; cacheSetGL(btd->bus, __loconett->slotmap[addr], gltmp); } break; case OPC_LOCO_SND: /* A2 */ addr = ln_packet[1]; if (__loconett->slotmap[addr] == 0) { syslog_bus(btd->bus, DBG_DEBUG, "slot %d still unknown", addr); } else { syslog_bus(btd->bus, DBG_DEBUG, "GL decoder address %d found in slot %d", __loconett->slotmap[addr], addr); cacheGetGL(btd->bus, __loconett->slotmap[addr], &gltmp); tmp = gltmp.funcs & 0xfe1f; /* bit shuffling */ tmp |= (ln_packet[2] & 0x000f) << 5; gltmp.funcs = tmp; cacheSetGL(btd->bus, __loconett->slotmap[addr], gltmp); } break; case OPC_SW_REQ: /* B0 */ case OPC_SW_REP: /* B1 */ addr = (ln_packet[1] | ((ln_packet[2] & 0x0f) << 7)) + 1; value = (ln_packet[2] & 0x10) >> 4; port = (ln_packet[2] & 0x20) >> 5; getGA(btd->bus, addr, &gatmp); gatmp.action = value; gatmp.port = port; syslog_bus(btd->bus, DBG_DEBUG, "Infomational: switch request (OPC_SW_REQ: /* B0 */) #%d:%d -> %d", addr, port, value); setGA(btd->bus, addr, gatmp); break; case OPC_INPUT_REP: /* B2 */ addr = ln_packet[1] | ((ln_packet[2] & 0x000f) << 7); addr = 1 + addr * 2 + ((ln_packet[2] & 0x0020) >> 5); value = (ln_packet[2] & 0x10) >> 4; updateFB(btd->bus, addr, value); break; case OPC_LONG_ACK: /* B4 */ syslog_bus(btd->bus, DBG_DEBUG, "Infomational: LONG ACK for command 0x%0X: 0x%0X", ln_packet[1] == 0 ? ln_packet[1] : ln_packet[1] | 0x0080, ln_packet[2]); break; case OPC_SLOT_STAT1: /* B5 */ addr = ln_packet[1]; if (__loconett->slotmap[addr] == 0) { syslog_bus(btd->bus, DBG_DEBUG, "slot %d still unknown", addr); } else { syslog_bus(btd->bus, DBG_DEBUG, "GL decoder address %d found in slot %d", __loconett->slotmap[addr], addr); if (ln_packet[2] == 2) { cacheTermGL(btd->bus, __loconett->slotmap[addr]); } } break; case OPC_RQ_SL_DATA: /* BB, E7 Message follows */ addr = ln_packet[1]; syslog_bus(btd->bus, DBG_DEBUG, "Infomational: Request SLOT DATA (OPC_RQ_SL_DATA: /* BB */) #%d", addr); break; case OPC_LOCO_ADR: /* BF, E7 Message follows */ addr = (ln_packet[1] << 7) | ln_packet[2]; syslog_bus(btd->bus, DBG_DEBUG, "Informational: request loco address (OPC_LOCO_ADR: /* BF */) #%d", addr); break; case OPC_SL_RD_DATA: /* E7 */ switch (ln_packet[1]) { case 0x0e: addr = ln_packet[4] | (ln_packet[9] << 7); syslog_bus(btd->bus, DBG_DEBUG, "OPC_SL_RD_DATA: /* E7 %0X */ slot #%d: status=0x%0x addr=%d", ln_packet[1], ln_packet[2], ln_packet[3], addr); __loconett->slotmap[ln_packet[2]] = addr; if (!isInitializedGL(btd->bus, addr)) { cacheInitGL(btd->bus, addr, 'L', 1, 128, 9); } cacheGetGL(btd->bus, addr, &gltmp); gltmp.speed = ln_packet[5]; tmp = ln_packet[6]; tmp = (tmp & 0x0010) >> 4 | (tmp & 0x000f) << 1; tmp = tmp | ln_packet[7] << 5; gltmp.funcs = tmp; cacheSetGL(btd->bus, addr, gltmp); break; default: syslog_bus(btd->bus, DBG_DEBUG, "Unknown or not decoded Loconet Message OPC_SL_RD_DATA: /* 0x%0X */", ln_packet[1]); } break; case OPC_WR_SL_DATA: switch (ln_packet[1]) { case 0x0e: if (ln_packet[2] == 0x7b) { int day, hour, minute, clkrate, clkstate; clkrate = ln_packet[3]; clkstate = ln_packet[10] & 0x20; if (!clkstate) { day = ln_packet[9]; minute = ((256 - ln_packet[6]) & 0x7f) % 60; hour = ((256 - ln_packet[8]) & 0x7f) % 24; hour = (24 - hour) % 24; minute = (60 - minute) % 60; syslog_bus(btd->bus, DBG_DEBUG, "fast clock update: day %d %02d:%02d", day, hour, minute); if ((__loconett-> flags & LN_FLAG_GETTIME) == LN_FLAG_GETTIME) { initTIME(clkrate, 1); setTIME(day, hour, minute, 0); } } else { syslog_bus(btd->bus, DBG_DEBUG, "clock frozen"); } } break; default: syslog_bus(btd->bus, DBG_DEBUG, "Unknown or not decoded Loconet Message OPC_WR_SL_DATA: /* 0x%0X */", ln_packet[1]); ; } break; default: syslog_bus(btd->bus, DBG_DEBUG, "Unknown or not decoded Loconet Message (0x%0X), packet length is %d bytes", ln_packet[0], ln_packetlen); /* unknown Loconet packet received, ignored */ break; } } if (!twomessageflag && (ln_packetlen == 0)) { /* now we process the way back _to_ Loconet */ ln_packet[0] = OPC_IDLE; ln_packetlen = 2; if (buses[btd->bus].power_changed == 1) { ln_packet[0] = 0x82 + buses[btd->bus].power_state; ln_packetlen = 2; buses[btd->bus].power_changed = 0; infoPower(btd->bus, msg); enqueueInfoMessage(msg); } else if (!queue_GL_isempty(btd->bus)) { gl_data_t gltmp, glcur; int slot; dequeueNextGL(btd->bus, &gltmp); addr = gltmp.id; slot = cacheGetSlotNumberforAddr(btd->bus, addr); cacheGetGL(btd->bus, addr, &glcur); /* we may have to send out 3 different messages OPC_LOCO_SPD for speed changes OPC_LOCO_DIRF for direction and function 0-4 OPC_LOCO_SND for function 5-8 */ if (gltmp.speed != glcur.speed) { ln_packetlen = 4; ln_packet[0] = OPC_LOCO_SPD; ln_packet[1] = slot; ln_packet[2] = gltmp.speed + (gltmp.speed > 0 ? 1 : 0); /* speed step in loconet 1 is a emergency stop */ ln_sendmessage(btd->bus, ln_packetlen, ln_packet); syslog_bus(btd->bus, DBG_DEBUG, "Loconet: GL SET slot %d with addr %d to speed %d.", slot, addr, speed); } if (gltmp.direction != glcur.direction || ((gltmp.funcs & 0x001f) != (glcur.funcs & 0x001f))) { ln_packetlen = 4; ln_packet[0] = OPC_LOCO_DIRF; ln_packet[1] = slot; ln_packet[2] = (gltmp.direction ? 0 : DIRF_DIR) + ((gltmp.funcs & 0x0001) ? DIRF_F0 : 0) + ((gltmp.funcs >> 1) & 0x000f); ln_sendmessage(btd->bus, ln_packetlen, ln_packet); syslog_bus(btd->bus, DBG_DEBUG, "Loconet: GL SET slot %d with addr %d to direction/funcs 0x%x.", slot, addr, ln_packet[2]); } if ((gltmp.funcs & 0x01e0) != (glcur.funcs & 0x01e0)) { ln_packetlen = 4; ln_packet[0] = OPC_LOCO_SND; ln_packet[1] = slot; ln_packet[2] = (gltmp.funcs >> 5) & 0x000f; ln_sendmessage(btd->bus, ln_packetlen, ln_packet); syslog_bus(btd->bus, DBG_DEBUG, "Loconet: GL SET slot %d with addr %d to sound funcs 0x%x.", slot, addr, ln_packet[2]); } cacheSetGL(btd->bus, gltmp.id, gltmp); } else if (!queue_GA_isempty(btd->bus)) { ga_data_t gatmp; dequeueNextGA(btd->bus, &gatmp); addr = gatmp.id - 1; ln_packetlen = 4; ln_packet[0] = OPC_SW_REQ; ln_packet[1] = (unsigned short int) (addr & 0x0007f); ln_packet[2] = (unsigned short int) ((addr >> 7) & 0x000f); ln_packet[2] |= (unsigned short int) ((gatmp.port & 0x0001) << 5); ln_packet[2] |= (unsigned short int) ((gatmp.action & 0x0001) << 4); if (gatmp.action == 1) { gettimeofday(&gatmp.tv[gatmp.port], NULL); } setGA(btd->bus, gatmp.id, gatmp); syslog_bus(btd->bus, DBG_DEBUG, "Loconet: GA SET #%d %02X", gatmp.id, gatmp.action); } else { /* send out a slot read message to collect the current state. Do this only once at startup time */ if (startup_slot_index < 120) { syslog_bus(btd->bus, DBG_DEBUG, "Loconet: requesting startup slot info %d", startup_slot_index); ln_packetlen = 4; ln_packet[0] = OPC_RQ_SL_DATA; ln_packet[1] = startup_slot_index++; ln_packet[2] = 0; } } ln_sendmessage(btd->bus, ln_packetlen, ln_packet); } /* wait 1 ms */ if (usleep(1000) == -1) { syslog_bus(btd->bus, DBG_ERROR, "usleep() failed: %s (errno = %d)\n", strerror(errno), errno); } } /*run the cleanup routine */ pthread_cleanup_pop(1); return NULL; } srcpd-2.1.7/src/srcp-server.h0000644000175000017500000000220314401372520012763 00000000000000/* $Id: srcp-server.h 1725 2016-03-20 17:06:01Z gscholz $ */ /* * Vorliegende Software unterliegt der General Public License, * Version 2, 1991. (c) Matthias Trute, 2000-2001. * */ #ifndef _SRCP_SERVER_H #define _SRCP_SERVER_H #include #include #include #include #include #include #include "config-srcpd.h" /*for bus_t*/ #include "config.h" /*for VERSION*/ /* SRCP server welcome message */ static const char WELCOME_MSG[] = "srcpd V" VERSION "; SRCP 0.8.4; SRCPOTHER 0.8.3\n"; typedef struct _SERVER_DATA { unsigned short int TCPPORT; char *listenip; char *username; char *groupname; } SERVER_DATA; typedef enum { ssInitializing = 0, ssRunning, ssTerminating, ssResetting } server_state_t; void set_server_state(server_state_t); server_state_t get_server_state(); int readconfig_server(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber); void startup_SERVER(); int init_bus_server(bus_t); void server_reset(void); void server_shutdown(void); int describeSERVER(bus_t bus, int addr, char *reply); int infoSERVER(char *msg); #endif srcpd-2.1.7/src/srcp-gm.c0000644000175000017500000000165511342547242012073 00000000000000/* $Id: srcp-gm.c 1456 2010-02-28 20:01:39Z gscholz $ */ #include #include #include #include "config-srcpd.h" #include "srcp-error.h" #include "srcp-info.h" #include "srcp-gm.h" #include "syslogmessage.h" int setGM(sessionid_t sid, sessionid_t rid, char *msg) { struct timeval akt_time; char msgtmp[MAXSRCPLINELEN]; syslog_bus(0, DBG_DEBUG, "GM message: %s", msg); if (sid != 0 && !is_valid_info_session(sid)) return SRCP_WRONGVALUE; if (rid != 0 && !is_valid_info_session(rid)) return SRCP_WRONGVALUE; /*