3.10.2013 - PIPeer release, PIConsole now can work as server and remote client. Remote console test program in directory "remote_console"

This commit is contained in:
peri4
2013-10-03 16:04:02 +04:00
parent 9111640ca8
commit 4b90f2818e
56 changed files with 6422 additions and 673 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
doc

View File

@@ -5,6 +5,7 @@ activity=pip
activityId=
desktop=-1
formfactor=0
geometry=0,0,1644,997
immutability=1
lastDesktop=-1
lastScreen=0
@@ -14,6 +15,7 @@ plugin=newspaper
screen=0
wallpaperplugin=color
wallpaperpluginmode=
zvalue=0
[Containments][1][Wallpaper][color]
backgroundMode=0

View File

@@ -1,29 +1,86 @@
project(pip)
cmake_minimum_required(VERSION 2.6)
include_directories(${CMAKE_CURRENT_SOURCE_DIR} .)
set(VERSION "0.0304")
include(CheckFunctionExists)
set(VERSION "0.0305")
set(SOVERSION ${VERSION})
set(CMAKE_BUILD_TYPE "Release")
set(LIBS)
file(GLOB CPPS "pi*.cpp")
# Check Bessel functions
set(CMAKE_REQUIRED_INCLUDES math.h)
set(CMAKE_REQUIRED_LIBRARIES m)
CHECK_FUNCTION_EXISTS(j0 PIP_MATH_J0)
CHECK_FUNCTION_EXISTS(j1 PIP_MATH_J1)
CHECK_FUNCTION_EXISTS(jn PIP_MATH_JN)
CHECK_FUNCTION_EXISTS(y0 PIP_MATH_Y0)
CHECK_FUNCTION_EXISTS(y1 PIP_MATH_Y1)
CHECK_FUNCTION_EXISTS(yn PIP_MATH_YN)
if (DEFINED PIP_MATH_J0)
add_definitions("-DPIP_MATH_J0")
endif ()
if (DEFINED PIP_MATH_J1)
add_definitions("-DPIP_MATH_J1")
endif ()
if (DEFINED PIP_MATH_JN)
add_definitions("-DPIP_MATH_JN")
endif ()
if (DEFINED PIP_MATH_Y0)
add_definitions("-DPIP_MATH_Y0")
endif ()
if (DEFINED PIP_MATH_Y1)
add_definitions("-DPIP_MATH_Y1")
endif ()
if (DEFINED PIP_MATH_YN)
add_definitions("-DPIP_MATH_YN")
endif ()
# Check if USB is on (to enable use "-DUSB=" argument of cmake)
if (DEFINED USB)
message(STATUS "Building with USB support")
unset(USB)
add_definitions("-DPIP_USB")
list(APPEND LIBS usb)
else ()
message(STATUS "Building without USB support")
endif ()
if (${WIN32})
list(APPEND LIBS ws2_32 Iphlpapi)
include(GenerateExportHeader)
execute_process(COMMAND "make_rc_win.bat")
add_definitions("-O2")
#add_definitions(-DEF)
execute_process(COMMAND "make_rc_win.bat" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
list(APPEND CPPS "pip_resource_win.o")
add_library(pip SHARED ${CPPS})
generate_export_header(pip)
target_link_libraries(pip ws2_32 Iphlpapi)
else (${WIN32})
if(DEFINED ENV{QNX_HOST})
if (${CMAKE_C_COMPILER} STREQUAL "cl")
add_definitions("/O2 /Ob2 /Ot")
else ()
add_definitions("-O2")
endif ()
else ()
add_definitions("-O2")
if (DEFINED ENV{QNX_HOST})
list(APPEND LIBS socket)
add_library(pip STATIC ${CPPS})
else()
add_definitions("-Wall -O2 -g3")
else ()
list(APPEND LIBS pthread rt)
include(GenerateExportHeader)
add_definitions("-Wall -g3")
add_library(pip SHARED ${CPPS})
endif()
target_link_libraries(pip pthread rt)
endif (${WIN32})
generate_export_header(pip)
endif ()
endif ()
target_link_libraries(pip ${LIBS})
# Test program
add_executable(pip_test "main.cpp")
target_link_libraries(pip_test pip)
add_subdirectory(system_test)
add_subdirectory(remote_console)

1905
Doxyfile Normal file
View File

@@ -0,0 +1,1905 @@
# Doxyfile 1.8.3.1
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project
#
# All text after a hash (#) is considered a comment and will be ignored
# The format is:
# TAG = value [value, ...]
# For lists items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (" ")
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
# This tag specifies the encoding used for all characters in the config file
# that follow. The default is UTF-8 which is also the encoding used for all
# text before the first occurrence of this tag. Doxygen uses libiconv (or the
# iconv built into libc) for the transcoding. See
# http://www.gnu.org/software/libiconv for the list of possible encodings.
DOXYFILE_ENCODING = UTF-8
# The PROJECT_NAME tag is a single word (or sequence of words) that should
# identify the project. Note that if you do not use Doxywizard you need
# to put quotes around the project name if it contains spaces.
PROJECT_NAME = PIP
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = 0.3.6
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
# a quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = "Platform-Independent Primitives"
# With the PROJECT_LOGO tag one can specify an logo or icon that is
# included in the documentation. The maximum height of the logo should not
# exceed 55 pixels and the maximum width should not exceed 200 pixels.
# Doxygen will copy the logo to the output directory.
PROJECT_LOGO =
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
OUTPUT_DIRECTORY = doc
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
# 4096 sub-directories (in 2 levels) under the output directory of each output
# format and will distribute the generated files over these directories.
# Enabling this option can be useful when feeding doxygen a huge amount of
# source files, where putting all generated files in the same directory would
# otherwise cause performance problems for the file system.
CREATE_SUBDIRS = NO
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# The default language is English, other supported languages are:
# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
OUTPUT_LANGUAGE = English
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
# include brief member descriptions after the members that are listed in
# the file and class documentation (similar to JavaDoc).
# Set to NO to disable this.
BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
# the brief description of a member or function before the detailed description.
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
REPEAT_BRIEF = YES
# This tag implements a quasi-intelligent brief description abbreviator
# that is used to form the text in various listings. Each string
# in this list, if found as the leading text of the brief description, will be
# stripped from the text and the result after processing the whole list, is
# used as the annotated text. Otherwise, the brief description is used as-is.
# If left blank, the following values are used ("$name" is automatically
# replaced with the name of the entity): "The $name class" "The $name widget"
# "The $name file" "is" "provides" "specifies" "contains"
# "represents" "a" "an" "the"
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# Doxygen will generate a detailed section even if there is only a brief
# description.
ALWAYS_DETAILED_SEC = NO
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
# inherited members of a class in the documentation of that class as if those
# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
INLINE_INHERITED_MEMB = NO
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
# path before files name in the file list and in the header files. If set
# to NO the shortest path that makes the file name unique will be used.
FULL_PATH_NAMES = YES
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
# can be used to strip a user-defined part of the path. Stripping is
# only done if one of the specified strings matches the left-hand part of
# the path. The tag can be used to show relative paths in the file list.
# If left blank the directory from which doxygen is run is used as the
# path to strip. Note that you specify absolute paths here, but also
# relative paths, which will be relative from the directory where doxygen is
# started.
STRIP_FROM_PATH =
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
# the path mentioned in the documentation of a class, which tells
# the reader which header file to include in order to use a class.
# If left blank only the name of the header file containing the class
# definition is used. Otherwise one should specify the include paths that
# are normally passed to the compiler using the -I flag.
STRIP_FROM_INC_PATH =
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
# (but less readable) file names. This can be useful if your file system
# doesn't support long names like on DOS, Mac, or CD-ROM.
SHORT_NAMES = NO
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
# will interpret the first line (until the first dot) of a JavaDoc-style
# comment as the brief description. If set to NO, the JavaDoc
# comments will behave just like regular Qt-style comments
# (thus requiring an explicit @brief command for a brief description.)
JAVADOC_AUTOBRIEF = NO
# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
# interpret the first line (until the first dot) of a Qt-style
# comment as the brief description. If set to NO, the comments
# will behave just like regular Qt-style comments (thus requiring
# an explicit \brief command for a brief description.)
QT_AUTOBRIEF = NO
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
# treat a multi-line C++ special comment block (i.e. a block of //! or ///
# comments) as a brief description. This used to be the default behaviour.
# The new default is to treat a multi-line C++ comment block as a detailed
# description. Set this tag to YES if you prefer the old behaviour instead.
MULTILINE_CPP_IS_BRIEF = NO
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
# member inherits the documentation from any documented member that it
# re-implements.
INHERIT_DOCS = YES
# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
# a new page for each member. If set to NO, the documentation of a member will
# be part of the file/class/namespace that contains it.
SEPARATE_MEMBER_PAGES = NO
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
# Doxygen uses this value to replace tabs by spaces in code fragments.
TAB_SIZE = 4
# This tag can be used to specify a number of aliases that acts
# as commands in the documentation. An alias has the form "name=value".
# For example adding "sideeffect=\par Side Effects:\n" will allow you to
# put the command \sideeffect (or @sideeffect) in the documentation, which
# will result in a user-defined paragraph with heading "Side Effects:".
# You can put \n's in the value part of an alias to insert newlines.
ALIASES = "handlers=\name Handlers" \
"vhandlers=\name Virtual handlers" \
"events=\name Events"
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding
# "class=itcl::class" will allow you to use the command class in the
# itcl::class meaning.
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
# sources only. Doxygen will then generate output that is more tailored for C.
# For instance, some of the names that are used will be different. The list
# of all members will be omitted, etc.
OPTIMIZE_OUTPUT_FOR_C = NO
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
# sources only. Doxygen will then generate output that is more tailored for
# Java. For instance, namespaces will be presented as packages, qualified
# scopes will look different, etc.
OPTIMIZE_OUTPUT_JAVA = NO
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
# sources only. Doxygen will then generate output that is more tailored for
# Fortran.
OPTIMIZE_FOR_FORTRAN = NO
# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
# sources. Doxygen will then generate output that is tailored for
# VHDL.
OPTIMIZE_OUTPUT_VHDL = NO
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension,
# and language is one of the parsers supported by doxygen: IDL, Java,
# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
# C++. For instance to make doxygen treat .inc files as Fortran files (default
# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
# that for custom extensions you also need to set FILE_PATTERNS otherwise the
# files are not read by doxygen.
EXTENSION_MAPPING =
# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
# comments according to the Markdown format, which allows for more readable
# documentation. See http://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you
# can mix doxygen, HTML, and XML commands with Markdown formatting.
# Disable only in case of backward compatibilities issues.
MARKDOWN_SUPPORT = YES
# When enabled doxygen tries to link words that correspond to documented classes,
# or namespaces to their corresponding documentation. Such a link can be
# prevented in individual cases by by putting a % sign in front of the word or
# globally by setting AUTOLINK_SUPPORT to NO.
AUTOLINK_SUPPORT = YES
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should
# set this tag to YES in order to let doxygen match functions declarations and
# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
# func(std::string) {}). This also makes the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
BUILTIN_STL_SUPPORT = NO
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
CPP_CLI_SUPPORT = NO
# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
# Doxygen will parse them like normal C++ but will assume all classes use public
# instead of private inheritance when no explicit protection keyword is present.
SIP_SUPPORT = NO
# For Microsoft's IDL there are propget and propput attributes to indicate
# getter and setter methods for a property. Setting this option to YES (the
# default) will make doxygen replace the get and set methods by a property in
# the documentation. This will only work if the methods are indeed getting or
# setting a simple type. If this is not the case, or you want to show the
# methods anyway, you should set this option to NO.
IDL_PROPERTY_SUPPORT = NO
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES, then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
DISTRIBUTE_GROUP_DOC = NO
# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
# the same type (for instance a group of public functions) to be put as a
# subgroup of that type (e.g. under the Public Functions section). Set it to
# NO to prevent subgrouping. Alternatively, this can be done per class using
# the \nosubgrouping command.
SUBGROUPING = NO
# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
# unions are shown inside the group in which they are included (e.g. using
# @ingroup) instead of on a separate page (for HTML and Man pages) or
# section (for LaTeX and RTF).
INLINE_GROUPED_CLASSES = NO
# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
# unions with only public data fields will be shown inline in the documentation
# of the scope in which they are defined (i.e. file, namespace, or group
# documentation), provided this scope is documented. If set to NO (the default),
# structs, classes, and unions are shown on a separate page (for HTML and Man
# pages) or section (for LaTeX and RTF).
INLINE_SIMPLE_STRUCTS = NO
# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
# is documented as struct, union, or enum with the name of the typedef. So
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
# with name TypeT. When disabled the typedef will appear as a member of a file,
# namespace, or class. And the struct will be named TypeS. This can typically
# be useful for C code in case the coding convention dictates that all compound
# types are typedef'ed and only the typedef is referenced, never the tag name.
TYPEDEF_HIDES_STRUCT = NO
# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
# determine which symbols to keep in memory and which to flush to disk.
# When the cache is full, less often used symbols will be written to disk.
# For small to medium size projects (<1000 input files) the default value is
# probably good enough. For larger projects a too small cache size can cause
# doxygen to be busy swapping symbols to and from disk most of the time
# causing a significant performance penalty.
# If the system has enough physical memory increasing the cache will improve the
# performance by keeping more symbols in memory. Note that the value works on
# a logarithmic scale so increasing the size by one will roughly double the
# memory usage. The cache size is given by this formula:
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
# corresponding to a cache size of 2^16 = 65536 symbols.
SYMBOL_CACHE_SIZE = 0
# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
# their name and scope. Since this can be an expensive process and often the
# same symbol appear multiple times in the code, doxygen keeps a cache of
# pre-resolved symbols. If the cache is too small doxygen will become slower.
# If the cache is too large, memory is wasted. The cache size is given by this
# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
# corresponding to a cache size of 2^16 = 65536 symbols.
LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# documentation are documented, even if no documentation was available.
# Private class members and static file members will be hidden unless
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
EXTRACT_ALL = NO
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
# will be included in the documentation.
EXTRACT_PRIVATE = NO
# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
# scope will be included in the documentation.
EXTRACT_PACKAGE = NO
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
EXTRACT_STATIC = NO
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
# defined locally in source files will be included in the documentation.
# If set to NO only classes defined in header files are included.
EXTRACT_LOCAL_CLASSES = YES
# This flag is only useful for Objective-C code. When set to YES local
# methods, which are defined in the implementation section but not in
# the interface are included in the documentation.
# If set to NO (the default) only methods in the interface are included.
EXTRACT_LOCAL_METHODS = YES
# If this flag is set to YES, the members of anonymous namespaces will be
# extracted and appear in the documentation as a namespace called
# 'anonymous_namespace{file}', where file will be replaced with the base
# name of the file that contains the anonymous namespace. By default
# anonymous namespaces are hidden.
EXTRACT_ANON_NSPACES = NO
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
# undocumented members of documented classes, files or namespaces.
# If set to NO (the default) these members will be included in the
# various overviews, but no documentation section is generated.
# This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_MEMBERS = YES
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy.
# If set to NO (the default) these classes will be included in the various
# overviews. This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_CLASSES = YES
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
# friend (class|struct|union) declarations.
# If set to NO (the default) these declarations will be included in the
# documentation.
HIDE_FRIEND_COMPOUNDS = YES
# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
# documentation blocks found inside the body of a function.
# If set to NO (the default) these blocks will be appended to the
# function's detailed documentation block.
HIDE_IN_BODY_DOCS = NO
# The INTERNAL_DOCS tag determines if documentation
# that is typed after a \internal command is included. If the tag is set
# to NO (the default) then the documentation will be excluded.
# Set it to YES to include the internal documentation.
INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
# file names in lower-case letters. If set to YES upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
CASE_SENSE_NAMES = NO
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
# will show members with their full class and namespace scopes in the
# documentation. If set to YES the scope will be hidden.
HIDE_SCOPE_NAMES = NO
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put a list of the files that are included by a file in the documentation
# of that file.
SHOW_INCLUDE_FILES = NO
# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
# will list include files with double quotes in the documentation
# rather than with sharp brackets.
FORCE_LOCAL_INCLUDES = NO
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
# is inserted in the documentation for inline members.
INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
# will sort the (detailed) documentation of file and class members
# alphabetically by member name. If set to NO the members will appear in
# declaration order.
SORT_MEMBER_DOCS = NO
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
# brief documentation of file, namespace and class members alphabetically
# by member name. If set to NO (the default) the members will appear in
# declaration order.
SORT_BRIEF_DOCS = NO
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
# will sort the (brief and detailed) documentation of class members so that
# constructors and destructors are listed first. If set to NO (the default)
# the constructors will appear in the respective orders defined by
# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
SORT_MEMBERS_CTORS_1ST = NO
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
# hierarchy of group names into alphabetical order. If set to NO (the default)
# the group names will appear in their defined order.
SORT_GROUP_NAMES = NO
# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
# sorted by fully-qualified names, including namespaces. If set to
# NO (the default), the class list will be sorted only by class name,
# not including the namespace part.
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
# Note: This option applies only to the class list, not to the
# alphabetical list.
SORT_BY_SCOPE_NAME = NO
# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
# do proper type resolution of all parameters of a function it will reject a
# match between the prototype and the implementation of a member function even
# if there is only one candidate or it is obvious which candidate to choose
# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
# will still accept a match between prototype and implementation in such cases.
STRICT_PROTO_MATCHING = NO
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
# commands in the documentation.
GENERATE_TODOLIST = YES
# The GENERATE_TESTLIST tag can be used to enable (YES) or
# disable (NO) the test list. This list is created by putting \test
# commands in the documentation.
GENERATE_TESTLIST = YES
# The GENERATE_BUGLIST tag can be used to enable (YES) or
# disable (NO) the bug list. This list is created by putting \bug
# commands in the documentation.
GENERATE_BUGLIST = YES
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
# disable (NO) the deprecated list. This list is created by putting
# \deprecated commands in the documentation.
GENERATE_DEPRECATEDLIST= YES
# The ENABLED_SECTIONS tag can be used to enable conditional
# documentation sections, marked by \if section-label ... \endif
# and \cond section-label ... \endcond blocks.
ENABLED_SECTIONS =
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
# the initial value of a variable or macro consists of for it to appear in
# the documentation. If the initializer consists of more lines than specified
# here it will be hidden. Use a value of 0 to hide initializers completely.
# The appearance of the initializer of individual variables and macros in the
# documentation can be controlled using \showinitializer or \hideinitializer
# command in the documentation regardless of this setting.
MAX_INITIALIZER_LINES = 30
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
# at the bottom of the documentation of classes and structs. If set to YES the
# list will mention the files that were used to generate the documentation.
SHOW_USED_FILES = NO
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
# This will remove the Files entry from the Quick Index and from the
# Folder Tree View (if specified). The default is YES.
SHOW_FILES = YES
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
# Namespaces page. This will remove the Namespaces entry from the Quick Index
# and from the Folder Tree View (if specified). The default is YES.
SHOW_NAMESPACES = YES
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
# the version control system). Doxygen will invoke the program by executing (via
# popen()) the command <command> <input-file>, where <command> is the value of
# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
# provided by doxygen. Whatever the program writes to standard output
# is used as the file version. See the manual for examples.
FILE_VERSION_FILTER =
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
# by doxygen. The layout file controls the global structure of the generated
# output files in an output format independent way. To create the layout file
# that represents doxygen's defaults, run doxygen with the -l option.
# You can optionally specify a file name after the option, if omitted
# DoxygenLayout.xml will be used as the name of the layout file.
LAYOUT_FILE =
# The CITE_BIB_FILES tag can be used to specify one or more bib files
# containing the references data. This must be a list of .bib files. The
# .bib extension is automatically appended if omitted. Using this command
# requires the bibtex tool to be installed. See also
# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
# feature you need bibtex and perl available in the search path. Do not use
# file names with spaces, bibtex cannot handle them.
CITE_BIB_FILES =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
# The QUIET tag can be used to turn on/off the messages that are generated
# by doxygen. Possible values are YES and NO. If left blank NO is used.
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated by doxygen. Possible values are YES and NO. If left blank
# NO is used.
WARNINGS = YES
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
# automatically be disabled.
WARN_IF_UNDOCUMENTED = YES
# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
# potential errors in the documentation, such as not documenting some
# parameters in a documented function, or documenting parameters that
# don't exist or using markup commands wrongly.
WARN_IF_DOC_ERROR = YES
# The WARN_NO_PARAMDOC option can be enabled to get warnings for
# functions that are documented, but have no documentation for their parameters
# or return value. If set to NO (the default) doxygen will only warn about
# wrong or incomplete parameter documentation, but not about the absence of
# documentation.
WARN_NO_PARAMDOC = NO
# The WARN_FORMAT tag determines the format of the warning messages that
# doxygen can produce. The string should contain the $file, $line, and $text
# tags, which will be replaced by the file and line number from which the
# warning originated and the warning text. Optionally the format may contain
# $version, which will be replaced by the version of the file (if it could
# be obtained via FILE_VERSION_FILTER)
WARN_FORMAT = "$file:$line: $text"
# The WARN_LOGFILE tag can be used to specify a file to which warning
# and error messages should be written. If left blank the output is written
# to stderr.
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
# The INPUT tag can be used to specify the files and/or directories that contain
# documented source files. You may enter file names like "myfile.cpp" or
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = .
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
# also the default input encoding. Doxygen uses libiconv (or the iconv built
# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
# the list of possible encodings.
INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank the following patterns are tested:
# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
# *.f90 *.f *.for *.vhd *.vhdl
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.d \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.idl \
*.odl \
*.cs \
*.php \
*.php3 \
*.inc \
*.m \
*.markdown \
*.md \
*.mm \
*.dox \
*.py \
*.f90 \
*.f \
*.for \
*.vhd \
*.vhdl
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
# If left blank NO is used.
RECURSIVE = NO
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
# Note that relative paths are relative to the directory from which doxygen is
# run.
EXCLUDE =
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
EXCLUDE_SYMLINKS = NO
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
# certain files from those directories. Note that the wildcards are matched
# against the file with absolute path, so to exclude all test directories
# for example use the pattern */test/*
EXCLUDE_PATTERNS =
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
EXCLUDE_SYMBOLS =
# The EXAMPLE_PATH tag can be used to specify one or more files or
# directories that contain example code fragments that are included (see
# the \include command).
EXAMPLE_PATH = doc/examples
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank all files are included.
EXAMPLE_PATTERNS = *
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
# searched for input files to be used with the \include or \dontinclude
# commands irrespective of the value of the RECURSIVE tag.
# Possible values are YES and NO. If left blank NO is used.
EXAMPLE_RECURSIVE = NO
# The IMAGE_PATH tag can be used to specify one or more files or
# directories that contain image that are included in the documentation (see
# the \image command).
IMAGE_PATH =
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
# by executing (via popen()) the command <filter> <input-file>, where <filter>
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
# input file. Doxygen will then use the output that the filter program writes
# to standard output. If FILTER_PATTERNS is specified, this tag will be
# ignored.
INPUT_FILTER =
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis. Doxygen will compare the file name with each pattern and apply the
# filter if there is a match. The filters are a list of the form:
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
# info on how filters are used. If FILTER_PATTERNS is empty or if
# non of the patterns match the file name, INPUT_FILTER is applied.
FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will be used to filter the input files when producing source
# files to browse (i.e. when SOURCE_BROWSER is set to YES).
FILTER_SOURCE_FILES = NO
# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
# and it is also possible to disable source filtering for a specific pattern
# using *.ext= (so without naming a filter). This option only has effect when
# FILTER_SOURCE_FILES is enabled.
FILTER_SOURCE_PATTERNS =
# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
# is part of the input, its contents will be placed on the main page (index.html).
# This can be useful if you have a project on for instance GitHub and want reuse
# the introduction page also for the doxygen output.
USE_MDFILE_AS_MAINPAGE =
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
# be generated. Documented entities will be cross-referenced with these sources.
# Note: To get rid of all source code in the generated output, make sure also
# VERBATIM_HEADERS is set to NO.
SOURCE_BROWSER = NO
# Setting the INLINE_SOURCES tag to YES will include the body
# of functions and classes directly in the documentation.
INLINE_SOURCES = NO
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
# doxygen to hide any special comment blocks from generated source code
# fragments. Normal C, C++ and Fortran comments will always remain visible.
STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES
# then for each documented function all documented
# functions referencing it will be listed.
REFERENCED_BY_RELATION = NO
# If the REFERENCES_RELATION tag is set to YES
# then for each documented function all documented entities
# called/used by that function will be listed.
REFERENCES_RELATION = NO
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
# link to the source code. Otherwise they will link to the documentation.
REFERENCES_LINK_SOURCE = YES
# If the USE_HTAGS tag is set to YES then the references to source code
# will point to the HTML generated by the htags(1) tool instead of doxygen
# built-in source browser. The htags tool is part of GNU's global source
# tagging system (see http://www.gnu.org/software/global/global.html). You
# will need version 4.8.6 or higher.
USE_HTAGS = NO
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
# will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
VERBATIM_HEADERS = NO
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
# of all compounds will be generated. Enable this if the project
# contains a lot of classes, structs, unions or interfaces.
ALPHABETICAL_INDEX = YES
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
# in which this list will be split (can be a number in the range [1..20])
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all
# classes will be put under the same header in the alphabetical index.
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
# should be ignored while generating the index headers.
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
# generate HTML output.
GENERATE_HTML = YES
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `html' will be used as the default path.
HTML_OUTPUT = html
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
# doxygen will generate files with .html extension.
HTML_FILE_EXTENSION = .html
# The HTML_HEADER tag can be used to specify a personal HTML header for
# each generated HTML page. If it is left blank doxygen will generate a
# standard header. Note that when using a custom header you are responsible
# for the proper inclusion of any scripts and style sheets that doxygen
# needs, which is dependent on the configuration options used.
# It is advised to generate a default header using "doxygen -w html
# header.html footer.html stylesheet.css YourConfigFile" and then modify
# that header. Note that the header is subject to change so you typically
# have to redo this when upgrading to a newer version of doxygen or when
# changing the value of configuration settings such as GENERATE_TREEVIEW!
HTML_HEADER =
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
# each generated HTML page. If it is left blank doxygen will generate a
# standard footer.
HTML_FOOTER =
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
# style sheet that is used by each HTML page. It can be used to
# fine-tune the look of the HTML output. If left blank doxygen will
# generate a default style sheet. Note that it is recommended to use
# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
# tag will in the future become obsolete.
HTML_STYLESHEET =
# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
# user-defined cascading style sheet that is included after the standard
# style sheets created by doxygen. Using this option one can overrule
# certain style aspects. This is preferred over using HTML_STYLESHEET
# since it does not replace the standard style sheet and is therefor more
# robust against future updates. Doxygen will copy the style sheet file to
# the output directory.
HTML_EXTRA_STYLESHEET =
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note
# that these files will be copied to the base HTML output directory. Use the
# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
# files. In the HTML_STYLESHEET file, use the file name only. Also note that
# the files will be copied as-is; there are no commands or markers available.
HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
# Doxygen will adjust the colors in the style sheet and background images
# according to this color. Hue is specified as an angle on a colorwheel,
# see http://en.wikipedia.org/wiki/Hue for more information.
# For instance the value 0 represents red, 60 is yellow, 120 is green,
# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
# The allowed range is 0 to 359.
HTML_COLORSTYLE_HUE = 246
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
# the colors in the HTML output. For a value of 0 the output will use
# grayscales only. A value of 255 will produce the most vivid colors.
HTML_COLORSTYLE_SAT = 79
# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
# the luminance component of the colors in the HTML output. Values below
# 100 gradually make the output lighter, whereas values above 100 make
# the output darker. The value divided by 100 is the actual gamma applied,
# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
# and 100 does not change the gamma.
HTML_COLORSTYLE_GAMMA = 75
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting
# this to NO can help when comparing the output of multiple runs.
HTML_TIMESTAMP = YES
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
HTML_DYNAMIC_SECTIONS = YES
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
# entries shown in the various tree structured indices initially; the user
# can expand and collapse entries dynamically later on. Doxygen will expand
# the tree to such a level that at most the specified number of entries are
# visible (unless a fully collapsed tree already exceeds this amount).
# So setting the number of entries 1 will produce a full collapsed tree by
# default. 0 is a special value representing an infinite number of entries
# and will result in a full expanded tree by default.
HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files
# will be generated that can be used as input for Apple's Xcode 3
# integrated development environment, introduced with OSX 10.5 (Leopard).
# To create a documentation set, doxygen will generate a Makefile in the
# HTML output directory. Running make will produce the docset in that
# directory and running "make install" will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
# it at startup.
# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
GENERATE_DOCSET = NO
# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
# feed. A documentation feed provides an umbrella under which multiple
# documentation sets from a single provider (such as a company or product suite)
# can be grouped.
DOCSET_FEEDNAME = "Doxygen generated docs"
# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
# should uniquely identify the documentation set bundle. This should be a
# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
# will append .docset to the name.
DOCSET_BUNDLE_ID = org.doxygen.Project
# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
# identify the documentation publisher. This should be a reverse domain-name
# style string, e.g. com.mycompany.MyDocSet.documentation.
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
# of the generated HTML documentation.
GENERATE_HTMLHELP = NO
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
# be used to specify the file name of the resulting .chm file. You
# can add a path in front of the file if the result should not be
# written to the html output directory.
CHM_FILE =
# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
# be used to specify the location (absolute path including file name) of
# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
# the HTML help compiler on the generated index.hhp.
HHC_LOCATION =
# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
# controls if a separate .chi index file is generated (YES) or that
# it should be included in the master .chm file (NO).
GENERATE_CHI = NO
# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
# is used to encode HtmlHelp index (hhk), content (hhc) and project file
# content.
CHM_INDEX_ENCODING =
# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
# controls whether a binary table of contents is generated (YES) or a
# normal table of contents (NO) in the .chm file.
BINARY_TOC = NO
# The TOC_EXPAND flag can be set to YES to add extra items for group members
# to the contents of the HTML help documentation and to the tree view.
TOC_EXPAND = NO
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
# that can be used as input for Qt's qhelpgenerator to generate a
# Qt Compressed Help (.qch) of the generated HTML documentation.
GENERATE_QHP = YES
# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
# be used to specify the file name of the resulting .qch file.
# The path specified is relative to the HTML output folder.
QCH_FILE = pip.qhp
# The QHP_NAMESPACE tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#namespace
QHP_NAMESPACE = PIP
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
# Qt Help Project output. For more information please see
# http://doc.trolltech.com/qthelpproject.html#virtual-folders
QHP_VIRTUAL_FOLDER = doc
# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
# add. For more information please see
# http://doc.trolltech.com/qthelpproject.html#custom-filters
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see
# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
# Qt Help Project / Custom Filters</a>.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's
# filter section matches.
# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
# Qt Help Project / Filter Attributes</a>.
QHP_SECT_FILTER_ATTRS =
# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
# be used to specify the location of Qt's qhelpgenerator.
# If non-empty doxygen will try to run qhelpgenerator on the generated
# .qhp file.
QHG_LOCATION =
# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
# will be generated, which together with the HTML files, form an Eclipse help
# plugin. To install this plugin and make it available under the help contents
# menu in Eclipse, the contents of the directory containing the HTML and XML
# files needs to be copied into the plugins directory of eclipse. The name of
# the directory within the plugins directory should be the same as
# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
# the help appears.
GENERATE_ECLIPSEHELP = NO
# A unique identifier for the eclipse help plugin. When installing the plugin
# the directory name containing the HTML and XML files should also have
# this name.
ECLIPSE_DOC_ID = org.doxygen.Project
# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
# at top of each HTML page. The value NO (the default) enables the index and
# the value YES disables it. Since the tabs have the same information as the
# navigation tree you can set this option to NO if you already set
# GENERATE_TREEVIEW to YES.
DISABLE_INDEX = NO
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information.
# If the tag value is set to YES, a side panel will be generated
# containing a tree-like index structure (just like the one that
# is generated for HTML Help). For this to work a browser that supports
# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
# Windows users are probably better off using the HTML help feature.
# Since the tree basically has the same information as the tab index you
# could consider to set DISABLE_INDEX to NO when enabling this option.
GENERATE_TREEVIEW = YES
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
# (range [0,1..20]) that doxygen will group on one line in the generated HTML
# documentation. Note that a value of 0 will completely suppress the enum
# values from appearing in the overview section.
ENUM_VALUES_PER_LINE = 4
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
# used to set the initial width (in pixels) of the frame in which the tree
# is shown.
TREEVIEW_WIDTH = 250
# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
# links to external symbols imported via tag files in a separate window.
EXT_LINKS_IN_WINDOW = NO
# Use this tag to change the font size of Latex formulas included
# as images in the HTML documentation. The default is 10. Note that
# when you change the font size after a successful doxygen run you need
# to manually remove any form_*.png images from the HTML output directory
# to force them to be regenerated.
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are
# not supported properly for IE 6.0, but are supported on all modern browsers.
# Note that when changing this option you need to delete any form_*.png files
# in the HTML output before the changes have effect.
FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
# (see http://www.mathjax.org) which uses client side Javascript for the
# rendering instead of using prerendered bitmaps. Use this if you do not
# have LaTeX installed or if you want to formulas look prettier in the HTML
# output. When enabled you may also need to install MathJax separately and
# configure the path to it using the MATHJAX_RELPATH option.
USE_MATHJAX = NO
# When MathJax is enabled you can set the default output format to be used for
# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
# SVG. The default value is HTML-CSS, which is slower, but has the best
# compatibility.
MATHJAX_FORMAT = HTML-CSS
# When MathJax is enabled you need to specify the location relative to the
# HTML output directory using the MATHJAX_RELPATH option. The destination
# directory should contain the MathJax.js script. For instance, if the mathjax
# directory is located at the same level as the HTML output directory, then
# MATHJAX_RELPATH should be ../mathjax. The default value points to
# the MathJax Content Delivery Network so you can quickly see the result without
# installing MathJax. However, it is strongly recommended to install a local
# copy of MathJax from http://www.mathjax.org before deployment.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
# names that should be enabled during MathJax rendering.
MATHJAX_EXTENSIONS =
# When the SEARCHENGINE tag is enabled doxygen will generate a search box
# for the HTML output. The underlying search engine uses javascript
# and DHTML and should work on any modern browser. Note that when using
# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
# (GENERATE_DOCSET) there is already a search function so this one should
# typically be disabled. For large projects the javascript based search engine
# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using Javascript.
# There are two flavours of web server based search depending on the
# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
# searching and an index file used by the script. When EXTERNAL_SEARCH is
# enabled the indexing and searching needs to be provided by external tools.
# See the manual for details.
SERVER_BASED_SEARCH = NO
# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
# script for searching. Instead the search results are written to an XML file
# which needs to be processed by an external indexer. Doxygen will invoke an
# external search engine pointed to by the SEARCHENGINE_URL option to obtain
# the search results. Doxygen ships with an example indexer (doxyindexer) and
# search engine (doxysearch.cgi) which are based on the open source search engine
# library Xapian. See the manual for configuration details.
EXTERNAL_SEARCH = NO
# The SEARCHENGINE_URL should point to a search engine hosted by a web server
# which will returned the search results when EXTERNAL_SEARCH is enabled.
# Doxygen ships with an example search engine (doxysearch) which is based on
# the open source search engine library Xapian. See the manual for configuration
# details.
SEARCHENGINE_URL =
# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
# search data is written to a file for indexing by an external tool. With the
# SEARCHDATA_FILE tag the name of this file can be specified.
SEARCHDATA_FILE = searchdata.xml
# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
# projects and redirect the results back to the right project.
EXTERNAL_SEARCH_ID =
# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
# projects other than the one defined by this configuration file, but that are
# all added to the same external search index. Each project needs to have a
# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
# of to a relative location where the documentation can be found.
# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
# generate Latex output.
GENERATE_LATEX = NO
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `latex' will be used as the default path.
LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked. If left blank `latex' will be used as the default command name.
# Note that when enabling USE_PDFLATEX this option is only used for
# generating bitmaps for formulas in the HTML output, but not in the
# Makefile that is written to the output directory.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
# generate index for LaTeX. If left blank `makeindex' will be used as the
# default command name.
MAKEINDEX_CMD_NAME = makeindex
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
# LaTeX documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, letter, legal and
# executive. If left blank a4wide will be used.
PAPER_TYPE = a4
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
EXTRA_PACKAGES =
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
# the generated latex document. The header should contain everything until
# the first chapter. If it is left blank doxygen will generate a
# standard header. Notice: only use this tag if you know what you are doing!
LATEX_HEADER =
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
# the generated latex document. The footer should contain everything after
# the last chapter. If it is left blank doxygen will generate a
# standard footer. Notice: only use this tag if you know what you are doing!
LATEX_FOOTER =
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
# contain links (just like the HTML output) instead of page references
# This makes the output suitable for online browsing using a pdf viewer.
PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
# plain latex in the generated Makefile. Set this option to YES to get a
# higher quality PDF documentation.
USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
# command to the generated LaTeX files. This will instruct LaTeX to keep
# running if errors occur, instead of asking the user for help.
# This option is also used when generating formulas in HTML.
LATEX_BATCHMODE = NO
# If LATEX_HIDE_INDICES is set to YES then doxygen will not
# include the index chapters (such as File Index, Compound Index, etc.)
# in the output.
LATEX_HIDE_INDICES = NO
# If LATEX_SOURCE_CODE is set to YES then doxygen will include
# source code with syntax highlighting in the LaTeX output.
# Note that which sources are shown also depends on other settings
# such as SOURCE_BROWSER.
LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
# http://en.wikipedia.org/wiki/BibTeX for more info.
LATEX_BIB_STYLE = plain
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
# The RTF output is optimized for Word 97 and may not look very pretty with
# other RTF readers or editors.
GENERATE_RTF = NO
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `rtf' will be used as the default path.
RTF_OUTPUT = rtf
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
# RTF documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_RTF = NO
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
# will contain hyperlink fields. The RTF file will
# contain links (just like the HTML output) instead of page references.
# This makes the output suitable for online browsing using WORD or other
# programs which support those fields.
# Note: wordpad (write) and others do not support links.
RTF_HYPERLINKS = NO
# Load style sheet definitions from file. Syntax is similar to doxygen's
# config file, i.e. a series of assignments. You only have to provide
# replacements, missing definitions are set to their default value.
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an rtf document.
# Syntax is similar to doxygen's config file.
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
# generate man pages
GENERATE_MAN = NO
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `man' will be used as the default path.
MAN_OUTPUT = man
# The MAN_EXTENSION tag determines the extension that is added to
# the generated man pages (default is the subroutine's section .3)
MAN_EXTENSION = .3
# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
# then it will generate one additional man file for each entity
# documented in the real man page(s). These additional files
# only source the real man page, but without them the man command
# would be unable to find the correct page. The default is NO.
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
# If the GENERATE_XML tag is set to YES Doxygen will
# generate an XML file that captures the structure of
# the code including all documentation.
GENERATE_XML = NO
# The XML_OUTPUT tag is used to specify where the XML pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `xml' will be used as the default path.
XML_OUTPUT = xml
# The XML_SCHEMA tag can be used to specify an XML schema,
# which can be used by a validating XML parser to check the
# syntax of the XML files.
XML_SCHEMA =
# The XML_DTD tag can be used to specify an XML DTD,
# which can be used by a validating XML parser to check the
# syntax of the XML files.
XML_DTD =
# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
# dump the program listings (including syntax highlighting
# and cross-referencing information) to the XML output. Note that
# enabling this will significantly increase the size of the XML output.
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
# generate an AutoGen Definitions (see autogen.sf.net) file
# that captures the structure of the code including all
# documentation. Note that this feature is still experimental
# and incomplete at the moment.
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
# If the GENERATE_PERLMOD tag is set to YES Doxygen will
# generate a Perl module file that captures the structure of
# the code including all documentation. Note that this
# feature is still experimental and incomplete at the
# moment.
GENERATE_PERLMOD = NO
# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
# the necessary Makefile rules, Perl scripts and LaTeX code to be able
# to generate PDF and DVI output from the Perl module output.
PERLMOD_LATEX = NO
# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
# nicely formatted so it can be parsed by a human reader. This is useful
# if you want to understand what is going on. On the other hand, if this
# tag is set to NO the size of the Perl module output will be much smaller
# and Perl will parse it just the same.
PERLMOD_PRETTY = YES
# The names of the make variables in the generated doxyrules.make file
# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
# This is useful so different doxyrules.make files included by the same
# Makefile don't overwrite each other's variables.
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
# evaluate all C-preprocessor directives found in the sources and include
# files.
ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
# names in the source code. If set to NO (the default) only conditional
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
# PREDEFINED and EXPAND_AS_DEFINED tags.
EXPAND_ONLY_PREDEF = NO
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# pointed to by INCLUDE_PATH will be searched when a #include is found.
SEARCH_INCLUDES = NO
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by
# the preprocessor.
INCLUDE_PATH =
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
# directories. If left blank, the patterns specified with FILE_PATTERNS will
# be used.
INCLUDE_FILE_PATTERNS =
# The PREDEFINED tag can be used to specify one or more macro names that
# are defined before the preprocessor is started (similar to the -D option of
# gcc). The argument of the tag is a list of macros of the form: name
# or name=definition (no spaces). If the definition and the = are
# omitted =1 is assumed. To prevent a macro definition from being
# undefined via #undef or recursively expanded use the := operator
# instead of the = operator.
PREDEFINED = DOXYGEN \
PIP_EXPORT
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
# Use the PREDEFINED tag if you want to use a different macro definition that
# overrules the definition found in the source code.
EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
# doxygen's preprocessor will remove all references to function-like macros
# that are alone on a line, have an all uppercase name, and do not end with a
# semicolon, because these will confuse the parser if not removed.
SKIP_FUNCTION_MACROS = NO
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
# The TAGFILES option can be used to specify one or more tagfiles. For each
# tag file the location of the external documentation should be added. The
# format of a tag file without this location is as follows:
# TAGFILES = file1 file2 ...
# Adding location for the tag files is done as follows:
# TAGFILES = file1=loc1 "file2 = loc2" ...
# where "loc1" and "loc2" can be relative or absolute paths
# or URLs. Note that each tag file must have a unique name (where the name does
# NOT include the path). If a tag file is not located in the directory in which
# doxygen is run, you must also specify the path to the tagfile here.
TAGFILES =
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
# a tag file that is based on the input files it reads.
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
# in the class index. If set to NO only the inherited external classes
# will be listed.
ALLEXTERNALS = NO
# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
# in the modules index. If set to NO, only the current project's groups will
# be listed.
EXTERNAL_GROUPS = YES
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of `which perl').
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
# or super classes. Setting the tag to NO turns the diagrams off. Note that
# this option also works with HAVE_DOT disabled, but it is recommended to
# install and use dot, since it yields more powerful graphs.
CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see
# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH =
# If set to YES, the inheritance and collaboration graphs will hide
# inheritance and usage relations if the target is undocumented
# or is not a class.
HIDE_UNDOC_RELATIONS = YES
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz, a graph visualization
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
# have no effect if this option is set to NO (the default)
HAVE_DOT = YES
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
# allowed to run in parallel. When set to 0 (the default) doxygen will
# base this on the number of processors available in the system. You can set it
# explicitly to a value larger than 0 to get control over the balance
# between CPU load and processing speed.
DOT_NUM_THREADS = 8
# By default doxygen will use the Helvetica font for all dot files that
# doxygen generates. When you want a differently looking font you can specify
# the font name using DOT_FONTNAME. You need to make sure dot is able to find
# the font, which can be done by putting it in a standard location or by setting
# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
# directory containing the font.
DOT_FONTNAME = Helvetica
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
# The default size is 10pt.
DOT_FONTSIZE = 10
# By default doxygen will tell dot to use the Helvetica font.
# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
# set the path where dot can find it.
DOT_FONTPATH =
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect inheritance relations. Setting this tag to YES will force the
# CLASS_DIAGRAMS tag to NO.
CLASS_GRAPH = YES
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect implementation dependencies (inheritance, containment, and
# class references variables) of the class with other documented classes.
COLLABORATION_GRAPH = NO
# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for groups, showing the direct groups dependencies
GROUP_GRAPHS = NO
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
UML_LOOK = NO
# If the UML_LOOK tag is enabled, the fields and methods are shown inside
# the class node. If there are many fields or methods and many nodes the
# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
# threshold limits the number of items for each type to make the size more
# managable. Set this to 0 for no limit. Note that the threshold may be
# exceeded by 50% before the limit is enforced.
UML_LIMIT_NUM_FIELDS = 12
# If set to YES, the inheritance and collaboration graphs will show the
# relations between templates and their instances.
TEMPLATE_RELATIONS = NO
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
# tags are set to YES then doxygen will generate a graph for each documented
# file showing the direct and indirect include dependencies of the file with
# other documented files.
INCLUDE_GRAPH = NO
# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
# documented header file showing the documented files that directly or
# indirectly include this file.
INCLUDED_BY_GRAPH = NO
# If the CALL_GRAPH and HAVE_DOT options are set to YES then
# doxygen will generate a call dependency graph for every global function
# or class method. Note that enabling this option will significantly increase
# the time of a run. So in most cases it will be better to enable call graphs
# for selected functions only using the \callgraph command.
CALL_GRAPH = NO
# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
# doxygen will generate a caller dependency graph for every global function
# or class method. Note that enabling this option will significantly increase
# the time of a run. So in most cases it will be better to enable caller
# graphs for selected functions only using the \callergraph command.
CALLER_GRAPH = NO
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
# will generate a graphical hierarchy of all classes instead of a textual one.
GRAPHICAL_HIERARCHY = YES
# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
# then doxygen will show the dependencies a directory has on other directories
# in a graphical way. The dependency relations are determined by the #include
# relations between the files in the directories.
DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. Possible values are svg, png, jpg, or gif.
# If left blank png will be used. If you choose svg you need to set
# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
# visible in IE 9+ (other browsers do not have this requirement).
DOT_IMAGE_FORMAT = svg
# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
# enable generation of interactive SVG images that allow zooming and panning.
# Note that this requires a modern browser other than Internet Explorer.
# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
# visible. Older versions of IE do not have SVG support.
INTERACTIVE_SVG = YES
# The tag DOT_PATH can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found in the path.
DOT_PATH =
# The DOTFILE_DIRS tag can be used to specify one or more directories that
# contain dot files that are included in the documentation (see the
# \dotfile command).
DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the
# \mscfile command).
MSCFILE_DIRS =
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
# nodes that will be shown in the graph. If the number of nodes in a graph
# becomes larger than this value, doxygen will truncate the graph, which is
# visualized by representing a node as a red box. Note that doxygen if the
# number of direct children of the root node in a graph is already larger than
# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
DOT_GRAPH_MAX_NODES = 50
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
# graphs generated by dot. A depth value of 3 means that only nodes reachable
# from the root by following a path via at most 3 edges will be shown. Nodes
# that lay further from the root node will be omitted. Note that setting this
# option to 1 or 2 may greatly reduce the computation time needed for large
# code bases. Also note that the size of a graph can be further restricted by
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not
# seem to support this out of the box. Warning: Depending on the platform used,
# enabling this option may lead to badly anti-aliased labels on the edges of
# a graph (i.e. they become hard to read).
DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10)
# support this, this feature is disabled by default.
DOT_MULTI_TARGETS = NO
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
# generate a legend page explaining the meaning of the various boxes and
# arrows in the dot generated graphs.
GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
# remove the intermediate dot files that are used to generate
# the various graphs.
DOT_CLEANUP = YES

5
clean
View File

@@ -5,3 +5,8 @@ rm -vf ./CMakeCache.txt ./Makefile ./cmake_install.cmake ./install_manifest.txt
cd system_test
rm -rvf ./CMakeFiles
rm -vf ./CMakeCache.txt ./Makefile ./cmake_install.cmake ./install_manifest.txt ./*~ ./*cxx ./moc_* ./*.o ./core
cd ..
cd remote_console
rm -rvf ./CMakeFiles
rm -vf ./CMakeCache.txt ./Makefile ./cmake_install.cmake ./install_manifest.txt ./*~ ./*cxx ./moc_* ./*.o ./core
cd ..

14
clean.bat Executable file
View File

@@ -0,0 +1,14 @@
#make clean
del /q /f /s CMakeFiles
rmdir /q /s CMakeFiles
del /q /f CMakeCache.txt Makefile cmake_install.cmake install_manifest.txt *~ *cxx moc_* *.o *.exe *.a *.dll *.lib core
cd system_test
del /q /f /s CMakeFiles
rmdir /q /s CMakeFiles
del /q /f CMakeCache.txt Makefile cmake_install.cmake install_manifest.txt *~ *cxx moc_* *.o *.exe *.a *.dll *.lib core
cd ..
cd remote_console
del /q /f /s CMakeFiles
rmdir /q /s CMakeFiles
del /q /f CMakeCache.txt Makefile cmake_install.cmake install_manifest.txt *~ *cxx moc_* *.o *.exe *.a *.dll *.lib core
cd ..

119
main.cpp
View File

@@ -202,95 +202,68 @@ struct msg2105base {
float tangaj_CP;
};
struct InpuData {
InpuData() {header.msg_id = 2113;}
msgHeader header;
uint first_number;
struct {
uchar packet_number: 7;
uchar packet_last : 1;
};
struct {
uchar antenna_number : 3;
uchar frequency_number: 3;
uchar data_type : 2;
};
uchar data[122];
};
#pragma pack(pop)
class RC: public PIObject {
PIOBJECT(RC)
public:
EVENT_HANDLER2(void, peer, const PIString & , from, const PIByteArray &, data) {piCout << "received from" << from << "\"" << PIString(data) << "\"";}
EVENT_HANDLER2(void, slot, void * , data, int, size) {piCout << "read" << PIString((char*)data, size);}
EVENT_HANDLER2(void, re, ullong, id, int, size) {piCout << "written id =" << id << "size =" << size;}
};
int main (int argc, char * argv[]) {
//PIKbdListener kbd;
//kbd.enableExitCapture();
/*PIEthernet::InterfaceList il = PIEthernet::interfaces();
//const PIEthernet::Interface & i(*(il.getByName("lo")));
piForeachC (PIEthernet::Interface & i, il)
piCout << NewLine << i.name << NewLine
<< "index" << i.index << NewLine
<< "address" << i.address << NewLine
<< "netmask" << i.netmask << NewLine
<< "mac" << i.mac << NewLine
<< "broadcast" << i.broadcast << NewLine
<< "isActive" << i.isActive() << NewLine
<< "isRunning" << i.isRunning() << NewLine
<< "isBroadcast" << i.isBroadcast() << NewLine
<< "isMulticast" << i.isMulticast() << NewLine
<< "isLoopback" << i.isLoopback() << NewLine
<< "isPTP" << i.isPTP();*/
//return 0;
int main(int argc, char ** argv) {
InpuData data;
PIEthernet eth(PIEthernet::UDP);
data.antenna_number = data.frequency_number = data.data_type = 0;
float t = 0.f;
int pc = 20, cnt = 0;
for (int p = 0; p < pc; ++p) {
data.packet_number = p;
data.packet_last = (p == pc - 1 ? 1 : 0);
data.first_number = p * 97;
PIBitArray ba_;
int ci = 0;
for (int i = 0; i < 97; ++i) {
t += M_PI/4;
ci = sin(t) * 511 + 511;
if (cnt % 500 > 80) ci = 512;
cnt++;
for (int b = 0; b < 10; ++b)
ba_.push_back(((ci >> b) & 1) == 1);
}
//cout << ba_.byteSize() << ", " << ba_.bitSize() << endl;
memcpy(data.data, ba_.data(), 122);
eth.send("127.0.0.1:5000", &data, sizeof(data));
}
/*cout << ba_ << endl;
for (int i = 0; i < 122; ++i)
cout << int(data.data[i]) << ", ";
cout << endl;*/
/*RC rc__;
PIPeer peer(argv[1]);
CONNECT2(void, const PIString & , const PIByteArray &, &peer, dataReceivedEvent, &rc__, peer);
msleep(1000);
peer.send("a", ("hello a from '" + PIString(argv[1]) + "'!").data());
peer.send("b", ("hello b from '" + PIString(argv[1]) + "'!").data());
peer.send("c", ("hello c from '" + PIString(argv[1]) + "'!").data());*/
int a__, b__;
PIConsole console(false);
console.enableExitCapture();
PIProtocol p("/home/peri4/work/ISPUM/nosit_VM6/protocols.conf", "gas", 0, 0, &a__, 4, &b__, 4);
p.start();
console.addVariable("service", &p);
console.start();
console.startServer("cons");
console.waitForFinish();
return 0;
/*PIKbdListener kbd;
kbd.enableExitCapture();
PIEthernet * _eth;
PIByteArray ba_(16);
if (PIString(argv[argc - 1]) == "s") {
_eth = new PIEthernet(PIEthernet::TCP_Server);
piCout << "listen" << _eth->listen("127.0.0.1:1111");
int cc = 0;
while (!PIKbdListener::exiting) {
if (cc != _eth->clientsCount()) {
piCout << "new client";
_eth->clients().back()->startThreadedRead();
cc++;
}
msleep(1);
}
} else {
_eth = new PIEthernet(PIEthernet::TCP_Client);
piCout << "connection" << _eth->connect("127.0.0.1:1111");
_eth->send(PIString("0123456789101112").data(), 16);
while (!PIKbdListener::exiting) {
msleep(1);
}
PIFile f("picontainers.h");
PIString all = f.readAll();
while (!all.isEmpty()) {
PIString line = all.takeLine();
if (line.takeWord() == "class")
piCout << "class" << line.trim();
}
delete _eth;
return 0;
msg2105base msg;
msg.header.size = sizeof(msg);
msg.header.msg_id = 2105;
msg.msgTime = 1;
//PIKbdListener kbd;
//kbd.enableExitCapture();
RC rc_;
PIEthernet eth;
CONNECT2(void, ullong, int, &eth, threadedWriteEvent, &rc_, re);
@@ -313,7 +286,7 @@ int main(int argc, char ** argv) {
piMSleep(50);
if (PIKbdListener::exiting) break;
}
return 0;*/
return 0;
PISignals::setSlot(signalFunc);
//PISignals::grabSignals(PISignals::Interrupt);

0
make.sh Normal file → Executable file
View File

1
make_rc_win.bat Executable file
View File

@@ -0,0 +1 @@
windres -i pip_resource_win.rc -o pip_resource_win.o --include-dir=.

View File

@@ -117,19 +117,20 @@ public:
PIByteArray & compressRLE(uchar threshold = 192);
PIByteArray & decompressRLE(uchar threshold = 192);
PIByteArray compressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.compressedRLE(threshold); return ba;}
PIByteArray decompressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.decompressedRLE(threshold); return ba;}
PIByteArray compressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.compressRLE(threshold); return ba;}
PIByteArray decompressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.decompressRLE(threshold); return ba;}
PIByteArray & compressHuffman() {*this = huffman.compress(*this); return *this;}
PIByteArray & append(void * data, int size) {for (int i = 0; i < size; ++i) push_back(((uchar*)data)[i]); return *this;}
PIByteArray & append(const PIByteArray & data) {for (int i = 0; i < data.size_s(); ++i) push_back(data[i]); return *this;}
/*PIByteArray & operator <<(short v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;}
PIByteArray & operator <<(ushort v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;}
PIByteArray & operator <<(int v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;}
PIByteArray & operator <<(uint v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;}
PIByteArray & operator <<(llong v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;}
PIByteArray & operator <<(ullong v) {for (uint i = 0; i < sizeof(v); ++i) push_back(((uchar*)(&v))[i]); return *this;}*/
PIByteArray & operator <<(const PIByteArray & v) {for (uint i = 0; i < v.size(); ++i) push_back(v[i]); return *this;}
//PIByteArray & operator <<(const PIByteArray & v) {for (uint i = 0; i < v.size(); ++i) push_back(v[i]); return *this;}
uchar checksumPlain8();
uint checksumPlain32();
@@ -141,6 +142,7 @@ public:
private:
union base64HelpStruct {
base64HelpStruct() {memset(this, 0, sizeof(base64HelpStruct));}
struct {
uchar ascii0: 6;
uchar ascii1: 6;
@@ -174,15 +176,16 @@ inline PIByteArray & operator <<(PIByteArray & s, const ulong & v) {PBA_OPERATOR
inline PIByteArray & operator <<(PIByteArray & s, const ullong & v) {PBA_OPERATOR_TO return s;}
inline PIByteArray & operator <<(PIByteArray & s, const float v) {PBA_OPERATOR_TO return s;}
inline PIByteArray & operator <<(PIByteArray & s, const double & v) {PBA_OPERATOR_TO return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) {int os = s.size_s(); s.enlarge(v.s); memcpy(s.data(os), v.d, v.s); return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v) {s << v.size_s(); int os = s.size_s(); s.enlarge(v.size_s()); if (v.size_s() > 0) memcpy(s.data(os), v.data(), v.size()); return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) {int os = s.size_s(); s.enlarge(v.s); if (v.s > 0) memcpy(s.data(os), v.d, v.s); return s;}
template <typename T>
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {s << v.size_s(); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;}
template <typename T>
inline PIByteArray & operator <<(PIByteArray & s, const PIList<T> & v) {s << v.size_s(); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;}
template <typename T>
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {s << v.size_s(); for (uint i = 0; i < v.size(); ++i) s << v[i]; return s;}
template <typename T>
inline PIByteArray & operator <<(PIByteArray & s, const T & v) {PBA_OPERATOR_TO return s;}
//template <typename T>
//inline PIByteArray & operator <<(PIByteArray & s, const T & v) {PBA_OPERATOR_TO return s;}
#undef PBA_OPERATOR_TO
#define PBA_OPERATOR_FROM memcpy(&v, s.data(), sizeof(v)); s.remove(0, sizeof(v));
@@ -198,16 +201,20 @@ inline PIByteArray & operator >>(PIByteArray & s, ulong & v) {assert(s.size() >=
inline PIByteArray & operator >>(PIByteArray & s, ullong & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
inline PIByteArray & operator >>(PIByteArray & s, float & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
inline PIByteArray & operator >>(PIByteArray & s, double & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {assert(s.size_s() >= v.s); memcpy(v.d, s.data(), v.s); s.remove(0, v.s); return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIByteArray & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); if (sz > 0) memcpy(v.data(), s.data(), v.size()); s.remove(0, v.size()); return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {assert(s.size_s() >= v.s); if (v.s > 0) memcpy(v.d, s.data(), v.s); s.remove(0, v.s); return s;}
template <typename T>
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
template <typename T>
inline PIByteArray & operator >>(PIByteArray & s, PIList<T> & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIList<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
template <typename T>
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
template <typename T>
inline PIByteArray & operator >>(PIByteArray & s, T & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {assert(s.size_s() >= 4); int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
//template <typename T>
//inline PIByteArray & operator >>(PIByteArray & s, T & v) {assert(s.size() >= sizeof(v)); PBA_OPERATOR_FROM return s;}
#undef PBA_OPERATOR_FROM
inline bool operator ==(PIByteArray & f, PIByteArray & s) {if (f.size_s() != s.size_s()) return false; for (int i = 0; i < f.size_s(); ++i) if (f[i] != s[i]) return false; return true;}
inline bool operator !=(PIByteArray & f, PIByteArray & s) {if (f.size_s() != s.size_s()) return true; for (int i = 0; i < f.size_s(); ++i) if (f[i] != s[i]) return true; return false;}
#endif // PIBYTEARRAY_H

View File

@@ -20,6 +20,18 @@
#include "picli.h"
/*! \class PICLI
* \brief Command-line arguments parser
*
* \section PICLI_sec0 Synopsis
* This class provide handy parsing of command-line arguments. First you should add
* arguments to PICLI with function \a addArgument(). Then you can check if there
* is some argument in application command-line with function \a hasArgument();
* \section PICLI_sec1 Example
* \snippet picli.cpp main
*/
PICLI::PICLI(int argc, char * argv[]) {
needParse = true;
_prefix_short = "-";
@@ -69,7 +81,7 @@ void PICLI::parse() {
_args_opt << cra;
continue;
}
piCout << "[PICli] Arguments overflow, \"" << cra << "\" ignored";
piCoutObj << "[PICli] Arguments overflow, \"" << cra << "\" ignored";
}
if (last == 0 ? false : last->has_value) {
last->value = cra;

39
picli.h
View File

@@ -1,3 +1,6 @@
/*! \file picli.h
* \brief Command-Line parser
*/
/*
PIP - Platform Independent Primitives
Command-Line Parser
@@ -20,26 +23,44 @@
#ifndef PICLI_H
#define PICLI_H
#include "pistring.h"
#include "piobject.h"
class PIP_EXPORT PICLI
class PIP_EXPORT PICLI: protected PIObject
{
PIOBJECT(PICLI)
public:
//! Constructor
PICLI(int argc, char * argv[]);
//! Add argument with name "name", short key = name first letter, full key = name
void addArgument(const PIString & name, bool value = false) {_args << Argument(name, name[0], name, value); needParse = true;}
//! Add argument with name "name", short key = "shortKey", full key = name
void addArgument(const PIString & name, const PIChar & shortKey, bool value = false) {_args << Argument(name, shortKey, name, value); needParse = true;}
//! Add argument with name "name", short key = "shortKey", full key = name
void addArgument(const PIString & name, const char * shortKey, bool value = false) {_args << Argument(name, PIChar(shortKey), name, value); needParse = true;}
//! Add argument with name "name", short key = "shortKey", full key = "fullKey"
void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, shortKey, fullKey, value); needParse = true;}
//! Add argument with name "name", short key = "shortKey", full key = "fullKey"
void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, PIChar(shortKey), fullKey, value); needParse = true;}
PIString rawArgument(int index) {return _args_raw[index];}
PIString mandatoryArgument(int index) {return _args_mand[index];}
PIString optionalArgument(int index) {return _args_opt[index];}
const PIStringList & rawArguments() const {return _args_raw;}
const PIStringList & mandatoryArguments() const {return _args_mand;}
const PIStringList & optionalArguments() const {return _args_opt;}
const PIString programCommand() const {return _args_raw.size() > 0 ? _args_raw.front() : PIString();}
//! Returns unparsed command-line argument by index "index". Index 0 is program execute command.
PIString rawArgument(int index) {parse(); return _args_raw[index];}
PIString mandatoryArgument(int index) {parse(); return _args_mand[index];}
PIString optionalArgument(int index) {parse(); return _args_opt[index];}
//! Returns unparsed command-line arguments
const PIStringList & rawArguments() {parse(); return _args_raw;}
const PIStringList & mandatoryArguments() {parse(); return _args_mand;}
const PIStringList & optionalArguments() {parse(); return _args_opt;}
//! Returns program execute command without arguments
const PIString programCommand() {parse(); return _args_raw.size() > 0 ? _args_raw.front() : PIString();}
bool hasArgument(const PIString & name) {parse(); piForeach (Argument & i, _args) if (i.name == name && i.found) return true; return false;}
PIString argumentValue(const PIString & name) {parse(); piForeach (Argument &i, _args) if (i.name == name && i.found) return i.value; return PIString();}
PIString argumentShortKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.short_key; return PIString();}

View File

@@ -18,6 +18,7 @@
*/
#include "piconsole.h"
#include "pipeer.h"
extern PIMutex __PICout_mutex__;
@@ -28,6 +29,7 @@ PIConsole::PIConsole(bool startNow, KBFunc slot): PIThread() {
needLockRun(true);
ret_func = slot;
num_format = 0;
vid = 0;
cur_tab = width = height = pwidth = pheight = max_y = 0;
def_align = Nothing;
#ifdef WINDOWS
@@ -40,13 +42,20 @@ PIConsole::PIConsole(bool startNow, KBFunc slot): PIThread() {
GetConsoleMode(hOut, &smode);
GetConsoleCursorInfo(hOut, &curinfo);
#endif
tabs.reserve(16);
addTab("main");
listener = new PIKbdListener(key_event, this);
peer = 0;
server_mode = false;
state = Disconnected;
peer_timer.addDelimiter(20);
CONNECT2(void, void * , int, &peer_timer, timeout, this, peerTimer);
if (startNow) start();
}
PIConsole::~PIConsole() {
stopPeer();
if (isRunning())
stop();
clearTabs(false);
@@ -227,6 +236,7 @@ PIString PIConsole::fstr(PIFlags<PIConsole::Format> f) {
attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
}
if (f[PIConsole::Bold]) attr |= FOREGROUND_INTENSITY;
if (f[PIConsole::Underline]) attr |= COMMON_LVB_UNDERSCORE;
SetConsoleTextAttribute(hOut, attr);
return PIString();
@@ -317,6 +327,7 @@ void PIConsole::run() {
width = ws.ws_col;
height = ws.ws_row;
#endif
//fflush(0); return;
__PICout_mutex__.lock();
if (pwidth != width || pheight != height) {
clearScreen();
@@ -336,27 +347,37 @@ void PIConsole::run() {
if (j > height - 3) continue;
j++;
moveRight(cx);
if (tv.type == 0 && tv.s == 0) {
if (tv.type == 15) {
newLine();
continue;
}
moveRight(tv.offset);
PIString rstr;
const void * ptr = 0;
if (tv.remote) {
if (tv.type == 0) {
rstr << PIByteArray(tv.rdata);
ptr = &rstr;
} else
ptr = tv.rdata.data();
} else
ptr = tv.ptr;
switch (tv.type) {
case 0: clen = printValue(tv.s != 0 ? *tv.s : PIString(), tv.format); break;
case 1: clen = printValue(tv.b != 0 ? *tv.b : false, tv.format); break;
case 2: clen = printValue(tv.i != 0 ? *tv.i : 0, tv.format); break;
case 3: clen = printValue(tv.l != 0 ? *tv.l : 0l, tv.format); break;
case 4: clen = printValue(tv.c != 0 ? *tv.c : char(0), tv.format); break;
case 5: clen = printValue(tv.f != 0 ? *tv.f : 0.f, tv.format); break;
case 6: clen = printValue(tv.d != 0 ? *tv.d : 0., tv.format); break;
case 7: clen = printValue(tv.sh != 0 ? *tv.sh : short(0), tv.format); break;
case 8: clen = printValue(tv.ui != 0 ? *tv.ui : 0u, tv.format); break;
case 9: clen = printValue(tv.ul != 0 ? *tv.ul : 0ul, tv.format); break;
case 10: clen = printValue(tv.ush != 0 ? *tv.ush : ushort(0), tv.format); break;
case 11: clen = printValue(tv.uc != 0 ? *tv.uc : uchar(0), tv.format); break;
case 12: clen = printValue(tv.ll != 0 ? *tv.ll : 0l, tv.format); break;
case 13: clen = printValue(tv.ull != 0 ? *tv.ull : 0ull, tv.format); break;
case 14: clen = printValue(bitsValue(tv.ptr, tv.bitFrom, tv.bitCount), tv.format); break;
case 0: clen = printValue(ptr != 0 ? *(const PIString*)ptr : PIString(), tv.format); break;
case 1: clen = printValue(ptr != 0 ? *(const bool*)ptr : false, tv.format); break;
case 2: clen = printValue(ptr != 0 ? *(const int*)ptr : 0, tv.format); break;
case 3: clen = printValue(ptr != 0 ? *(const long*)ptr : 0l, tv.format); break;
case 4: clen = printValue(ptr != 0 ? *(const char*)ptr : char(0), tv.format); break;
case 5: clen = printValue(ptr != 0 ? *(const float*)ptr : 0.f, tv.format); break;
case 6: clen = printValue(ptr != 0 ? *(const double*)ptr : 0., tv.format); break;
case 7: clen = printValue(ptr != 0 ? *(const short*)ptr : short(0), tv.format); break;
case 8: clen = printValue(ptr != 0 ? *(const uint*)ptr : 0u, tv.format); break;
case 9: clen = printValue(ptr != 0 ? *(const ulong*)ptr : 0ul, tv.format); break;
case 10: clen = printValue(ptr != 0 ? *(const ushort*)ptr : ushort(0), tv.format); break;
case 11: clen = printValue(ptr != 0 ? *(const uchar*)ptr : uchar(0), tv.format); break;
case 12: clen = printValue(ptr != 0 ? *(const llong*)ptr : 0l, tv.format); break;
case 13: clen = printValue(ptr != 0 ? *(const ullong*)ptr: 0ull, tv.format); break;
case 14: clen = printValue(bitsValue(ptr, tv.bitFrom, tv.bitCount), tv.format); break;
}
if (clen + tv.offset < (uint)col_wid) {
#if defined(QNX) || defined(FREE_BSD)
@@ -401,7 +422,7 @@ void PIConsole::fillLabels() {
if (ccol.alignment != Nothing) {
mx = 0;
piForeachC (Variable & j, cvars)
if (j.s != 0)
if (!j.isEmpty())
if (mx < j.name.size())
mx = j.name.size();
mx += 2;
@@ -416,7 +437,7 @@ void PIConsole::fillLabels() {
Variable & tv(cvars[j]);
cvars[j].nx = cx;
cvars[j].ny = cy;
if (tv.name.size() == 0) {
if (tv.name.isEmpty()) {
cvars[j].offset = 0;
clearLine();
newLine();
@@ -424,7 +445,8 @@ void PIConsole::fillLabels() {
continue;
}
clearLine();
if (tv.type == 0 && tv.s == 0) {
//piCout << tv.name << tv.type << tv.ptr;
if (tv.type == 15) {
cvars[j].offset = cvars[j].name.length();
cvars[j].nx += cvars[j].offset;
printLine(tv.name, cx, tv.format);
@@ -432,7 +454,7 @@ void PIConsole::fillLabels() {
cy++;
continue;
}
if (tv.s != 0) {
if (!tv.isEmpty()) {
switch (ccol.alignment) {
case Nothing:
cvars[j].offset = (tv.name + ": ").length();
@@ -489,7 +511,7 @@ void PIConsole::status() {
}
int PIConsole::bitsValue(const void * src, int offset, int count) {
int PIConsole::bitsValue(const void * src, int offset, int count) const {
int ret = 0, stbyte = offset / 8, cbit = offset - stbyte * 8;
char cbyte = reinterpret_cast<const char * >(src)[stbyte];
for (int i = 0; i < count; i++) {
@@ -522,38 +544,38 @@ const char * PIConsole::toBin(const void * d, int s) {
}
#define ADD_VAR_BODY tv.name = name; tv.bitFrom = tv.bitCount = 0; tv.format = format; checkColumn(col);
#define ADD_VAR_BODY vid++; tv.id = vid; tv.name = name; tv.bitFrom = tv.bitCount = 0; tv.format = format; tv.remote = false; checkColumn(col);
void PIConsole::addString(const PIString & name, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 0; tv.s = 0; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const PIString* ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 0; tv.s = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 15; tv.size = 0; tv.ptr = 0; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const PIString * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 0; tv.size = 0; tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const bool * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 1; tv.b = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 1; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const int * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 2; tv.i = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 2; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const long * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 3; tv.l = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 3; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const char * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 4; tv.c = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 4; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const float * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 5; tv.f = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 5; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const double * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 6; tv.d = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 6; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const short * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 7; tv.sh = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 7; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const uint * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 8; tv.ui = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 8; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const ulong * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 9; tv.ul = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 9; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const ushort * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 10; tv.ush = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 10; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const uchar * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 11; tv.uc = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 11; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const llong * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 12; tv.ll = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 12; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const ullong * ptr, int col, PIFlags<PIConsole::Format> format) {
ADD_VAR_BODY tv.type = 13; tv.ull = ptr; column(col).push_back(tv);}
ADD_VAR_BODY tv.type = 13; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
void PIConsole::addVariable(const PIString & name, const PIProtocol * ptr, int col, PIFlags<PIConsole::Format> format) {
addString("protocol " + name, col, format | PIConsole::Bold);
addVariable("Rec - " + ptr->receiverDeviceName(), ptr->receiverDeviceState_ptr(), col, format);
@@ -592,10 +614,10 @@ void PIConsole::addVariable(const PIString & name, const PISystemMonitor * ptr,
addVariable("cpu load", &(ptr->statistic().cpu_load_system), col, format);
}
void PIConsole::addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitCount, int col, PIFlags<PIConsole::Format> format) {
tv.name = name; tv.bitFrom = fromBit; tv.bitCount = bitCount; tv.type = 14; tv.ptr = ptr; tv.format = format;
vid++; tv.id = vid; tv.size = sizeof(ullong); tv.name = name; tv.bitFrom = fromBit; tv.bitCount = bitCount; tv.type = 14; tv.ptr = ptr; tv.format = format;
checkColumn(col); column(col).push_back(tv);}
void PIConsole::addEmptyLine(int col, uint count) {
tv.name = ""; tv.type = 0; tv.d = 0; tv.format = Normal;
tv.id = 0; tv.size = 0; tv.name = ""; tv.type = 0; tv.ptr = 0; tv.format = Normal;
for (uint i = 0; i < count; ++i) {
checkColumn(col);
column(col).push_back(tv);
@@ -670,3 +692,226 @@ inline int PIConsole::printValue(const ushort value, PIFlags<PIConsole::Format>
inline int PIConsole::printValue(const uint value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const ulong value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
inline int PIConsole::printValue(const ullong value, PIFlags<PIConsole::Format> format) {PRINT_VAR_BODY}
void PIConsole::startServer(const PIString & name) {
stopPeer();
server_mode = true;
peer = new PIPeer("_rcs_:" + name);
CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived);
peer_timer.start(50.);
serverSendInfo();
}
void PIConsole::stopPeer() {
remote_clients.clear();
peer_timer.stop();
if (peer != 0) delete peer;
peer = 0;
state = Disconnected;
}
PIStringList PIConsole::clients() const {
PIStringList sl;
if (peer == 0) return sl;
piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) {
if (i.name.left(6) != "_rcc_:") continue;
sl << i.name.right(i.name.length() - 6);
}
return sl;
}
void PIConsole::listenServers() {
stopPeer();
server_mode = false;
server_name.clear();
srand(currentSystemTime().nanoseconds);
peer = new PIPeer("_rcc_:" + currentDateTime().toString("hhmmssddMMyy_") + PIString::fromNumber(rand()));
CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived);
peer_timer.start(100.);
}
PIStringList PIConsole::availableServers() const {
PIStringList sl;
if (peer == 0) return sl;
piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) {
if (i.name.left(6) != "_rcs_:") continue;
sl << i.name.right(i.name.length() - 6);
}
return sl;
}
void PIConsole::connectToServer(const PIString & name) {
if (peer == 0) listenServers();
server_name = name;
}
void PIConsole::disconnect() {
stopPeer();
}
void PIConsole::serverSendInfo() {
if (peer == 0) return;
PIByteArray ba;
ba << int(0xAA);
peer->sendToAll(ba);
}
void PIConsole::serverSendData() {
if (peer == 0) return;
PIByteArray ba;
PIVector<VariableContent> content;
piForeach (Tab & t, tabs)
piForeach (Column & c, t.columns)
piForeach (Variable & v, c.variables)
if (!v.isEmpty() && v.id > 0) {
VariableContent vc;
vc.id = v.id;
v.writeData(vc.rdata);
content << vc;
}
piForeach (RemoteClient & rc, remote_clients) {
ba.clear();
switch (rc.state) {
case FetchingData:
ba << int(0xCC) << tabs;
//piCout << "server send const data" << rc.name << ba.size_s();
break;
case Committing:
ba << int(0xDD);
break;
case Connected:
ba << int(0xEE) << content;
break;
default: break;
}
if (!ba.isEmpty())
peer->send(rc.name, ba);
}
}
PIConsole::RemoteClient & PIConsole::remoteClient(const PIString & fname) {
piForeach (RemoteClient & i, remote_clients)
if (i.name == fname)
return i;
remote_clients << RemoteClient(fname);
return remote_clients.back();
}
void PIConsole::peerReceived(const PIString & from, const PIByteArray & data) {
int type;
PIByteArray ba(data);
ba >> type;
//piCout << "rec packet from" << from << "type" << PICoutManipulators::Hex << type;
if (server_mode) {
if (from.left(5) != "_rcc_") return;
//PIString rcn = from.right(from.length() - 6);
RemoteClient & rc(remoteClient(from));
switch (type) {
case 0xBB: // fetch const data request
//piCout << "fetch data request from" << from << rc.state;
if (rc.state != Connected)
rc.state = FetchingData;
break;
case 0xCC: // const data commit
//piCout << "commit from" << from;
if (rc.state != Connected)
rc.state = Connected;
break;
default: break;
}
} else {
PIVector<VariableContent> content;
PIMap<int, Variable * > vids;
if (from.left(5) != "_rcs_") return;
PIString rcn = from.right(from.length() - 6);
switch (type) {
case 0xAA: // new server
//piCout << "new server" << rcn;
break;
case 0xCC: // const data
//piCout << "received const data";
state = Committing;
ba >> tabs;
cur_tab = tabs.isEmpty() ? -1 : 0;
piForeach (Tab & t, tabs)
piForeach (Column & c, t.columns)
piForeach (Variable & v, c.variables)
v.remote = true;
break;
case 0xDD: // const data commit
//piCout << "received commit";
state = Connected;
break;
case 0xEE: // dynamic data
//piCout << "received data" << ba.size_s();
piForeach (Tab & t, tabs)
piForeach (Column & c, t.columns)
piForeach (Variable & v, c.variables)
if (!v.isEmpty() && v.id > 0)
vids[v.id] = &v;
ba >> content;
piForeach (VariableContent & vc, content) {
if (vc.id <= 0) continue;
Variable * v = vids.at(vc.id);
if (v == 0) continue;
//piCout << "read" << v->name << vc.rdata.size_s();
v->rdata = vc.rdata;
}
break;
default: break;
}
}
}
void PIConsole::peerTimer(void * data, int delim) {
if (peer == 0) return;
if (server_mode) {
if (delim == 20)
serverSendInfo();
else
serverSendData();
} else {
if (delim != 1 || server_name.isEmpty()) return;
const PIPeer::PeerInfo * p = peer->getPeerByName("_rcs_:" + server_name);
if (p == 0) return;
PIByteArray ba;
switch (state) {
case Disconnected:
peer_timer.reset();
ba << int(0xBB);
//piCout << "send to" << server_name << "fetch request disc";
peer->send(p, ba);
state = FetchingData;
break;
case FetchingData:
if (peer_timer.elapsed_s() < 3.)
return;
peer_timer.reset();
ba << int(0xBB);
//piCout << "send to" << server_name << "fetch request fd";
peer->send(p, ba);
break;
case Committing:
peer_timer.reset();
ba << int(0xCC);
//piCout << "send to" << server_name << "committing";
state = Connected;
peer->send(p, ba);
break;
default: break;
};
}
}

View File

@@ -27,8 +27,12 @@
#ifndef WINDOWS
# include <sys/ioctl.h>
# include <fcntl.h>
#else
# define COMMON_LVB_UNDERSCORE 0x8000
#endif
class PIPeer;
/// handlers:
/// void clearVariables(bool clearScreen = true)
/// void start(bool wait = false)
@@ -134,15 +138,22 @@ public:
void disableExitCapture() {listener->disableExitCapture();}
bool exitCaptured() const {return listener->exitCaptured();}
char exitKey() const {return listener->exitKey();}
private:
void begin();
void run();
void fillLabels();
// Server functions
void startServer(const PIString & name);
void stopPeer();
bool isServerStarted() const {return peer != 0;}
PIStringList clients() const;
// Client functions
void listenServers();
PIStringList availableServers() const;
PIString selectedServer() const {return server_name;}
void connectToServer(const PIString & name);
void disconnect();
bool isConnected() const {return state == Connected;}
#ifdef WINDOWS
void getWinCurCoord() {GetConsoleScreenBufferInfo(hOut, &csbi); ccoord = csbi.dwCursorPosition;}
COORD & getWinCoord(int dx = 0, int dy = 0) {getWinCurCoord(); ccoord.X += dx; ccoord.Y += dy; return ccoord;}
void toUpperLeft() {SetConsoleCursorPosition(hOut, ulcoord);}
void moveRight(int n = 1) {SetConsoleCursorPosition(hOut, getWinCoord(n));}
void moveLeft(int n = 1) {SetConsoleCursorPosition(hOut, getWinCoord(-n));}
@@ -168,9 +179,19 @@ private:
void hideCursor() {printf("\e[?25l");}
void showCursor() {printf("\e[?25h");}
#endif
private:
#ifdef WINDOWS
void getWinCurCoord() {GetConsoleScreenBufferInfo(hOut, &csbi); ccoord = csbi.dwCursorPosition;}
COORD & getWinCoord(int dx = 0, int dy = 0) {getWinCurCoord(); ccoord.X += dx; ccoord.Y += dy; return ccoord;}
#endif
void begin();
void run();
void fillLabels();
void status();
void checkColumn(uint col) {while (columns().size() < col) columns().push_back(Column(def_align));}
int bitsValue(const void * src, int offset, int count);
int bitsValue(const void * src, int offset, int count) const;
const char * toBin(const void * d, int s);
inline void printLine(const PIString & str, int dx = 0, PIFlags<PIConsole::Format> format = PIConsole::Normal);
inline int printValue(const PIString & str, PIFlags<PIConsole::Format> format = PIConsole::Normal);
@@ -191,6 +212,16 @@ private:
static void key_event(char key, void * t);
struct Variable {
Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = Normal; remote = false; ptr = 0; id = 1;}
bool isEmpty() const {return (remote ? false : ptr == 0);}
const void * data() {return (remote ? rdata.data() : ptr);}
void writeData(PIByteArray & ba) {
if (remote) ba << rdata;
else {
if (type == 0) ba << (*(PIString * )ptr);
else ba << PIByteArray::RawData(ptr, size);
}
}
PIString name;
PIFlags<PIConsole::Format> format;
int nx;
@@ -199,31 +230,24 @@ private:
int offset;
int bitFrom;
int bitCount;
union {
const PIString * s;
const bool * b;
const short * sh;
const int * i;
const long * l;
const llong * ll;
const float * f;
const double * d;
const char * c;
const uchar * uc;
const ushort * ush;
const uint * ui;
const ulong * ul;
const ullong * ull;
const void * ptr;
};
void operator =(const Variable & src) {name = src.name; format = src.format; type = src.type; offset = src.offset;
bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr; nx = src.nx; ny = src.ny;}
int size;
int id;
bool remote;
const void * ptr;
PIByteArray rdata;
void operator =(const Variable & src) {remote = src.remote; name = src.name; format = src.format; type = src.type; offset = src.offset; size = src.size;
bitFrom = src.bitFrom; bitCount = src.bitCount; ptr = src.ptr; nx = src.nx; ny = src.ny; rdata = src.rdata;}
};
struct VariableContent {
int id;
PIByteArray rdata;
};
struct Column {
Column(Alignment align = PIConsole::Right) {variables.reserve(16); alignment = align;}
PIVector<Variable> variables;
Alignment alignment;
Column(Alignment align = PIConsole::Right) { alignment = align;}
uint size() const {return variables.size();}
Variable & operator [](int index) {return variables[index];}
const Variable & operator [](int index) const {return variables[index];}
@@ -232,15 +256,27 @@ private:
};
struct Tab {
Tab(PIString n = "", char k = 0) {columns.reserve(16); name = n; key = k;}
PIVector<Column> columns;
PIString name;
PIString status;
char key;
Tab() {}
Tab(PIString n, char k) {name = n; key = k;}
~Tab() {;}
};
enum ConnectedState {Disconnected, FetchingData, Committing, Connected};
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v);
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v);
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v);
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v);
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v);
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v);
friend PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v);
friend PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v);
PIVector<Column> & columns() {return tabs[cur_tab].columns;}
Column & column(int index) {return tabs[cur_tab].columns[index - 1];}
inline int couts(const PIString & v);
@@ -258,6 +294,14 @@ private:
inline int couts(const ullong v);
inline int couts(const float v);
inline int couts(const double v);
struct RemoteClient;
void serverSendInfo();
void serverSendData();
RemoteClient & remoteClient(const PIString & fname);
EVENT_HANDLER2(void, peerReceived, const PIString &, from, const PIByteArray &, data);
EVENT_HANDLER2(void, peerTimer, void * , data, int, delim);
#ifdef WINDOWS
void * hOut;
@@ -277,8 +321,48 @@ private:
KBFunc ret_func;
int width, height, pwidth, pheight, ret, col_wid, num_format;
uint max_y;
int vid;
uint cur_tab, col_cnt;
PIPeer * peer;
PITimer peer_timer;
PIString server_name;
bool server_mode;
ConnectedState state;
/*struct RemoteData {
RemoteData() {msg_count = msg_rec = msg_send = 0;}
void clear() {msg_count = msg_rec = msg_send = 0; data.clear();}
bool isEmpty() const {return msg_count == 0;}
bool isReadyRec() const {return msg_count == msg_rec;}
bool isReadySend() const {return msg_count == msg_send;}
void setData(const PIByteArray & ba) {data = ba; msg_rec = msg_send = 0; msg_count = (data.size_s() - 1) / 4096 + 1;}
PIByteArray data;
int msg_count;
int msg_rec;
int msg_send;
};*/
struct RemoteClient {
RemoteClient(const PIString & n = "") {name = n; state = Disconnected;}
PIString name;
ConnectedState state;
};
PIVector<RemoteClient> remote_clients;
};
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::VariableContent & v) {ba << v.id << v.rdata; return ba;}
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::VariableContent & v) {ba >> v.id; ba >> v.rdata; return ba;}
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Variable & v) {ba << v.name << v.id << (int)v.format << v.type << v.size << v.bitFrom << v.bitCount; return ba;}
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Variable & v) {ba >> v.name >> v.id >> (int & )v.format >> v.type >> v.size >> v.bitFrom >> v.bitCount; return ba;}
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Column & v) {ba << (int)v.alignment << v.variables; return ba;}
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Column & v) {ba >> (int & )v.alignment >> v.variables; return ba;}
inline PIByteArray & operator <<(PIByteArray & ba, const PIConsole::Tab & v) {ba << v.name << v.status << (uchar)v.key << v.columns; return ba;}
inline PIByteArray & operator >>(PIByteArray & ba, PIConsole::Tab & v) {ba >> v.name >> v.status >> (uchar&)v.key >> v.columns; return ba;}
#endif // PICONSOLE_H

View File

@@ -549,7 +549,7 @@ public:
bool contains(const Type & v) const {for (uint i = 0; i < _stlc::size(); ++i) if (v == at(i)) return true; return false;}
#else
_CVector & enlarge(uint size_) {int ns = size_s() + size_; if (ns <= 0) _stlc::clear(); else _stlc::resize(ns); return *this;}
_CVector & enlarge(int size_) {int ns = size_s() + size_; if (ns <= 0) _stlc::clear(); else _stlc::resize(ns); return *this;}
_CVector & sort(CompareFunc compare = compare_func) {qsort(&at(0), _stlc::size(), sizeof(Type), (int(*)(const void * , const void * ))compare); return *this;}
_CVector & fill(const Type & t) {_stlc::assign(_stlc::size(), t); return *this;}
_CVector & pop_front() {_stlc::erase(_stlc::begin()); return *this;}

99
pidiagnostics.cpp Normal file
View File

@@ -0,0 +1,99 @@
/*
PIP - Platform Independent Primitives
Speed and quality in/out diagnostics
Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pidiagnostics.h"
PIDiagnostics::PIDiagnostics(bool start_): PITimer() {
PITimer::reset();
reset();
if (start_) start();
}
void PIDiagnostics::reset() {
lock();
qual = PIDiagnostics::Unknown;
speedIn = speedOut = PIString::readableSize(0) + "/s";
ifreq = immediate_freq = integral_freq = 0.f;
packets[0] = packets[1] = 0;
cur_pckt = rec_once = 0;
wrong_count = receive_count = send_count = 0;
packets_in_sec = packets_out_sec = bytes_in_sec = bytes_out_sec = 0;
unlock();
}
void PIDiagnostics::received(int size, bool correct) {
lock();
packets[correct ? 1 : 0]++;
rec_once = 1;
if (correct) {
float el = elapsed_s();
if (el > 0.f) immediate_freq = ifreq = 1.f / el;
else immediate_freq = ifreq = 0.f;
PITimer::reset();
receive_count++;
packets_in_sec++;
bytes_in_sec += size;
} else {
immediate_freq = ifreq = 0.f;
wrong_count++;
}
unlock();
}
void PIDiagnostics::sended(int size) {
lock();
send_count++;
packets_out_sec++;
bytes_out_sec += size;
unlock();
}
void PIDiagnostics::tick(void * data, int delimiter) {
lock();
PIDiagnostics::Quality diag;
float fdel = 1. / (interval() / 1000.);
immediate_freq = ifreq;
ifreq = 0.f;
speedIn = PIString::readableSize(bytes_in_sec * fdel) + "/s";
speedOut = PIString::readableSize(bytes_out_sec * fdel) + "/s";
bytes_in_sec = bytes_out_sec = packets_in_sec = packets_out_sec = 0;
int arc = packets[0] + packets[1];
float good_percents = 0.f;
if (arc > 0) good_percents = (float)packets[1] / arc * 100.f;
integral_freq = packets[1] * fdel;
if (rec_once == 0) {
diag = PIDiagnostics::Unknown;
} else {
if (good_percents == 0.f) diag = PIDiagnostics::Failure;
else if (good_percents <= 20.f) diag = PIDiagnostics::Bad;
else if (good_percents > 20.f && good_percents <= 80.f) diag = PIDiagnostics::Average;
else diag = PIDiagnostics::Good;
if (diag != qual) {
qualityChanged(diag, qual);
qual = diag;
}
}
packets[0] = packets[1] = 0;
unlock();
}

85
pidiagnostics.h Normal file
View File

@@ -0,0 +1,85 @@
/*
PIP - Platform Independent Primitives
Speed and quality in/out diagnostics
Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com, Bychkov Andrey wapmobil@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIDIAGNOSTICS_H
#define PIDIAGNOSTICS_H
#include "pitimer.h"
class PIP_EXPORT PIDiagnostics: private PITimer
{
PIOBJECT(PIDiagnostics)
public:
PIDiagnostics(bool start_ = true);
virtual ~PIDiagnostics() {;}
enum Quality {Unknown = 1, Failure = 2, Bad = 3, Average = 4, Good = 5};
EVENT_HANDLER0(void, start) {start(1000.);}
EVENT_HANDLER1(void, start, double, msecs) {if (msecs > 0.) PITimer::start(msecs);}
EVENT_HANDLER0(void, reset);
EVENT_HANDLER1(void, received, int, size) {received(size, true);}
EVENT_HANDLER2(void, received, int, size, bool, correct);
EVENT_HANDLER1(void, sended, int, size);
float immediateFrequency() const {return immediate_freq;}
float integralFrequency() const {return integral_freq;}
ullong receiveCountPerSec() const {return packets_in_sec;}
ullong sendCountPerSec() const {return packets_out_sec;}
ullong receiveBytesPerSec() const {return bytes_in_sec;}
ullong sendBytesPerSec() const {return bytes_out_sec;}
ullong receiveCount() const {return receive_count;}
ullong wrongCount() const {return wrong_count;}
ullong sendCount() const {return send_count;}
PIDiagnostics::Quality quality() const {return qual;}
PIString receiveSpeed() const {return speedIn;}
PIString sendSpeed() const {return speedOut;}
const float * immediateFrequency_ptr() const {return &immediate_freq;}
const float * integralFrequency_ptr() const {return &integral_freq;}
const ullong * receiveCountPerSec_ptr() const {return &packets_in_sec;}
const ullong * sendCountPerSec_ptr() const {return &packets_out_sec;}
const ullong * receiveBytesPerSec_ptr() const {return &bytes_in_sec;}
const ullong * sendBytesPerSec_ptr() const {return &bytes_out_sec;}
const ullong * receiveCount_ptr() const {return &receive_count;}
const ullong * wrongCount_ptr() const {return &wrong_count;}
const ullong * sendCount_ptr() const {return &send_count;}
const int * quality_ptr() const {return (int * )&qual;}
const PIString * receiveSpeed_ptr() const {return &speedIn;}
const PIString * sendSpeed_ptr() const {return &speedOut;}
EVENT2(qualityChanged, PIDiagnostics::Quality, new_quality, PIDiagnostics::Quality, old_quality)
private:
void tick(void * data, int delimiter);
void changeDisconnectTimeout();
PIDiagnostics::Quality qual;
PIString speedIn, speedOut;
float ifreq, immediate_freq, integral_freq;
int packets[2];
char cur_pckt, rec_once;
ullong wrong_count, receive_count, send_count;
ullong packets_in_sec, packets_out_sec, bytes_in_sec, bytes_out_sec;
};
#endif // PIDIAGNOSTICS_H

View File

@@ -83,7 +83,7 @@ bool PIEthernet::init() {
closeSocket(sock);
int st = 0, pr = 0;;
#ifdef WINDOWS
int flags = 0;
int flags = WSA_FLAG_OVERLAPPED;
#else
int so = 1;
#endif
@@ -96,18 +96,21 @@ bool PIEthernet::init() {
}
#ifdef WINDOWS
if (type_ == UDP) flags = WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF;
if (params[ReuseAddress]) flags |= WSA_FLAG_OVERLAPPED;
sock = WSASocket(AF_INET, st, pr, NULL, 0, flags);
#else
sock = socket(AF_INET, st, pr);
#endif
if (sock == -1) {
piCout << "[PIEthernet] Cant`t create socket, " << ethErrorString();
piCoutObj << "[PIEthernet] Can`t create socket, " << ethErrorString();
return false;
}
#ifndef WINDOWS
if (params[PIEthernet::ReuseAddress]) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &so, sizeof(so));
if (params[PIEthernet::Broadcast]) setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &so, sizeof(so));
#else
BOOL bv = TRUE;
if (params[PIEthernet::ReuseAddress]) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char * )&bv, sizeof(bv));
setsockopt(sock, SOL_SOCKET, SO_DONTLINGER, (const char * )&bv, sizeof(bv));
#endif
//cout << "inited " << sock << ": bc = " << params << endl;
//fcntl(sock, F_SETFL, 0/*O_NONBLOCK*/);
@@ -128,7 +131,7 @@ bool PIEthernet::openDevice() {
parseAddress(path_, &ip_, &port_);
if (type_ != UDP)
return true;
//cout << " bind to " << sock << ": " << (params[PIEthernet::Broadcast] ? "0.0.0.0" : path_) << ": " << port_ << " ..." <<endl;
//piCout << "bind to" << (params[PIEthernet::Broadcast] ? "bc" : ip_) << ":" << port_ << " ...";
memset(&addr_, 0, sizeof(addr_));
addr_.sin_family = AF_INET;
addr_.sin_port = htons(port_);
@@ -143,7 +146,7 @@ bool PIEthernet::openDevice() {
tries++;
}
if (tries == 10) {
piCout << "[PIEthernet] Cant`t bind to " << ip_ << ":" << port_ << ", " << ethErrorString();
piCoutObj << "[PIEthernet] Can`t bind to " << ip_ << ":" << port_ << ", " << ethErrorString();
return false;
}
opened_ = true;
@@ -156,7 +159,6 @@ bool PIEthernet::openDevice() {
bool PIEthernet::closeDevice() {
//cout << "close\n";
if (sock != -1) shutdown(sock, SHUT_RDWR);
closeSocket(sock);
piForeach (PIEthernet * i, clients_)
delete i;
@@ -172,7 +174,7 @@ bool PIEthernet::joinMulticastGroup(const PIString & group) {
if (sock == -1) init();
if (sock == -1) return false;
if (type_ != UDP) {
piCout << "[PIEthernet] Only UDP sockets can join multicast groups";
piCoutObj << "[PIEthernet] Only UDP sockets can join multicast groups";
return false;
}
if (!opened_) {
@@ -185,27 +187,36 @@ bool PIEthernet::joinMulticastGroup(const PIString & group) {
parseAddress(path_, &ip_, &port_);
memset(&addr_, 0, sizeof(addr_));
addr_.sin_family = AF_INET;
addr_.sin_port = htons(port_);
addr_.sin_addr.s_addr = inet_addr(group.data());
//int so = 1;
//setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char * )&so, sizeof(so));
SOCKET ret = WSAJoinLeaf(sock, (sockaddr *)&addr_, sizeof(addr_), NULL, NULL, NULL, NULL, JL_BOTH);
if (ret == INVALID_SOCKET) {
piCout << "[PIEthernet] Cant`t join multicast group " << group << ", " << ethErrorString();
piCoutObj << "[PIEthernet] Can`t join multicast group " << group << ", " << ethErrorString();
return false;
}
leafs.insert(group, ret);
#else
# ifndef QNX
if (!params[Broadcast])
piCout << "[PIEthernet] Warning: \"Broadcast\" parameter not set, \"joinMulticastGroup(\"" << group << "\")\" may be useless!";
piCoutObj << "[PIEthernet] Warning: \"Broadcast\" parameter not set, \"joinMulticastGroup(\"" << group << "\")\" may be useless!";
parseAddress(path_, &ip_, &port_);
struct ip_mreqn mreq;
memset(&mreq, 0, sizeof(mreq));
/*if (params[PIEthernet::Broadcast]) mreq.imr_address.s_addr = INADDR_ANY;
else*/ mreq.imr_address.s_addr = inet_addr(ip_.data());
mreq.imr_multiaddr.s_addr = inet_addr(group.data());
mreq.imr_ifindex = 0;
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
piCout << "[PIEthernet] Cant`t join multicast group " << group << ", " << ethErrorString();
if (params[PIEthernet::Broadcast]) mreq.imr_address.s_addr = INADDR_ANY;
else mreq.imr_address.s_addr = inet_addr(ip_.data());
PIEthernet::InterfaceList il = interfaces();
const PIEthernet::Interface * ci = il.getByAddress(ip_);
if (ci != 0) mreq.imr_ifindex = ci->index;
//piCout << "join group" << group << "ip" << ip_ << "with index" << mreq.imr_ifindex;
mreq.imr_multiaddr.s_addr = inet_addr(group.data());
int so = 1;
//setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &so, sizeof(so));
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &so, sizeof(so));
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq));
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != 0) {
piCoutObj << "[PIEthernet] Can`t join multicast group " << group << ", " << ethErrorString();
return false;
}
# endif
@@ -218,7 +229,7 @@ bool PIEthernet::leaveMulticastGroup(const PIString & group) {
if (sock == -1) init();
if (sock == -1) return false;
if (type_ != UDP) {
piCout << "[PIEthernet] Only UDP sockets can leave multicast groups";
piCoutObj << "[PIEthernet] Only UDP sockets can leave multicast groups";
return false;
}
#ifdef WINDOWS
@@ -237,7 +248,7 @@ bool PIEthernet::leaveMulticastGroup(const PIString & group) {
mreq.imr_multiaddr.s_addr = inet_addr(group.data());
mreq.imr_ifindex = 0;
if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) {
piCout << "[PIEthernet] Cant`t leave multicast group " << group << ", " << ethErrorString();
piCoutObj << "[PIEthernet] Can`t leave multicast group " << group << ", " << ethErrorString();
return false;
}
#endif
@@ -256,10 +267,10 @@ bool PIEthernet::connect() {
#ifdef QNX
addr_.sin_len = sizeof(addr_);
#endif
//piCout << "[PIEthernet] connect to " << ip << ":" << port_;
//piCoutObj << "[PIEthernet] connect to " << ip << ":" << port_;
connected_ = (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) == 0);
if (!connected_)
piCout << "[PIEthernet] Cant`t connect to " << ip_ << ":" << port_ << ", " << ethErrorString();
piCoutObj << "[PIEthernet] Can`t connect to " << ip_ << ":" << port_ << ", " << ethErrorString();
opened_ = connected_;
if (connected_) connected();
return connected_;
@@ -283,14 +294,14 @@ bool PIEthernet::listen() {
tries++;
}
if (tries == 10) {
piCout << "[PIEthernet] Cant`t bind to " << ip_ << ":" << port_ << ", " << ethErrorString();
piCoutObj << "[PIEthernet] Can`t bind to " << ip_ << ":" << port_ << ", " << ethErrorString();
return false;
}
if (::listen(sock, 64) == -1) {
piCout << "[PIEthernet] Can`t listen on "<< ip_ << ":" << port_ << ", " << ethErrorString();
piCoutObj << "[PIEthernet] Can`t listen on "<< ip_ << ":" << port_ << ", " << ethErrorString();
return false;
}
//piCout << "[PIEthernet] listen on " << ip_ << ":" << port_;
//piCoutObj << "[PIEthernet] listen on " << ip_ << ":" << port_;
server_thread_.start(server_func);
return true;
}
@@ -303,13 +314,14 @@ int PIEthernet::read(void * read_to, int max_size) {
int rs = 0, s = 0;
sockaddr_in client_addr;
socklen_t slen = sizeof(client_addr);
//piCout << "[PIEthernet] read from " << ip_ << ":" << port_ << endl;
//piCoutObj << "[PIEthernet] read from " << ip_ << ":" << port_ << endl;
switch (type_) {
case TCP_SingleTCP:
::listen(sock, 64);
s = accept(sock, (sockaddr * )&client_addr, &slen);
if (s == -1) {
piCout << "[PIEthernet] Cant`t accept new connection, " << ethErrorString();
//piCoutObj << "[PIEthernet] Can`t accept new connection, " << ethErrorString();
msleep(1);
return -1;
}
rs = recv(s, (char * )read_to, max_size, 0);
@@ -323,11 +335,11 @@ int PIEthernet::read(void * read_to, int max_size) {
#else
rs = recv(sock, read_to, max_size, 0);
#endif
piCout << "eth" << path_ << "read return" << rs << errno;
if (rs <= 0) {
//piCout << "eth" << path_ << "read return" << rs << errno;
if (rs <= 0 && type_ == TCP_Client) {
connected_ = false;
disconnected(rs < 0);
piCout << "eth" << path_ << "disconnected";
//piCoutObj << "eth" << path_ << "disconnected";
}
if (rs > 0) received(read_to, rs);
return rs;
@@ -342,10 +354,10 @@ int PIEthernet::read(void * read_to, int max_size) {
int PIEthernet::write(const void * data, int max_size) {
if (sock == -1) init();
if (sock == -1 || !isWriteable()) {
//piCout << "[PIEthernet] Can`t send to uninitialized socket";
//piCoutObj << "[PIEthernet] Can`t send to uninitialized socket";
return -1;
}
//piCout << "[PIEthernet] sending to " << ip_s << ":" << port_s << " " << max_size << " bytes";
//piCoutObj << "[PIEthernet] sending to " << ip_s << ":" << port_s << " " << max_size << " bytes";
int ret = 0;
switch (type_) {
case TCP_SingleTCP:
@@ -356,21 +368,22 @@ int PIEthernet::write(const void * data, int max_size) {
#ifdef QNX
addr_.sin_len = sizeof(addr_);
#endif
//piCout << "connect SingleTCP" << ip_s << ":" << port_s << "...";
//piCoutObj << "connect SingleTCP" << ip_s << ":" << port_s << "...";
if (::connect(sock, (sockaddr * )&addr_, sizeof(addr_)) != 0) {
piCout << "[PIEthernet] Cant`t connect to " << ip_s << ":" << port_s << ", " << ethErrorString();
//piCoutObj << "[PIEthernet] Can`t connect to " << ip_s << ":" << port_s << ", " << ethErrorString();
msleep(1);
return -1;
}
//piCout << "ok, write SingleTCP" << int(data) << max_size << "bytes ...";
//piCoutObj << "ok, write SingleTCP" << int(data) << max_size << "bytes ...";
ret = ::send(sock, (const char *)data, max_size, 0);
//piCout << "ok, ret" << ret;
//piCoutObj << "ok, ret" << ret;
closeSocket(sock);
init();
return ret;
case UDP:
saddr_.sin_port = htons(port_s);
if (params[PIEthernet::Broadcast]) saddr_.sin_addr.s_addr = INADDR_BROADCAST;
else saddr_.sin_addr.s_addr = inet_addr(ip_s.data());
/*if (params[PIEthernet::Broadcast]) saddr_.sin_addr.s_addr = INADDR_BROADCAST;
else*/ saddr_.sin_addr.s_addr = inet_addr(ip_s.data());
saddr_.sin_family = AF_INET;
#ifdef WINDOWS
return sendto(sock, (const char * )data, max_size, 0, (sockaddr * )&saddr_, sizeof(saddr_));
@@ -391,7 +404,7 @@ void PIEthernet::server_func(void * eth) {
socklen_t slen = sizeof(client_addr);
int s = accept(ce->sock, (sockaddr * )&client_addr, &slen);
if (s == -1) {
piCout << "[PIEthernet] Cant`t accept new connection, " << ethErrorString();
if (ce->debug_) piCout << "[PIEthernet] Can`t accept new connection, " << ethErrorString();
return;
}
PIString ip(inet_ntoa(client_addr.sin_addr));
@@ -406,19 +419,60 @@ void PIEthernet::server_func(void * eth) {
}
PIStringList PIEthernet::interfaces() {
PIEthernet::InterfaceList PIEthernet::interfaces() {
#ifdef WINDOWS
piCout << "[PIEthernet] Not implemented on Windows, use \"PIEthernet::allAddresses\" instead";
return PIStringList();
#else
# ifdef QNX
PIStringList il, sl;
/*struct if_nameindex * ni = if_nameindex();
for (int i = 0; ; ++i) {
if (ni[i].if_name == 0 || ni[i].if_index == 0) break;
sl << PIString(ni[i].if_name);
PIEthernet::InterfaceList il;
Interface ci;
PIP_ADAPTER_INFO pAdapterInfo, pAdapter = 0;
int ret = 0;
ulong ulOutBufLen = sizeof(IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO * ) HeapAlloc(GetProcessHeap(), 0, (sizeof (IP_ADAPTER_INFO)));
if (pAdapterInfo == 0) {
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo";
return il;
}
if_freenameindex(ni);*/
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
pAdapterInfo = (IP_ADAPTER_INFO *) HeapAlloc(GetProcessHeap(), 0, (ulOutBufLen));
if (pAdapterInfo == 0) {
piCout << "[PIEthernet] Error allocating memory needed to call GetAdaptersinfo";
return il;
}
}
if ((ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
pAdapter = pAdapterInfo;
while (pAdapter) {
ci.name = PIString(pAdapter->AdapterName);
ci.index = pAdapter->Index;
ci.address = PIString(pAdapter->IpAddressList.IpAddress.String);
if (ci.address == "0.0.0.0") {
pAdapter = pAdapter->Next;
continue;
}
ci.mac = macFromBytes(PIByteArray(pAdapter->Address, pAdapter->AddressLength));
ci.netmask = PIString(pAdapter->IpAddressList.IpMask.String);
ci.flags = PIEthernet::ifActive | PIEthernet::ifRunning;
//if (ret->ifa_flags & IFF_BROADCAST) ci.flags |= PIEthernet::ifBroadcast;
//if (ret->ifa_flags & IFF_MULTICAST) ci.flags |= PIEthernet::ifMulticast;
if (pAdapter->Type == MIB_IF_TYPE_PPP) ci.flags |= PIEthernet::ifPTP;
if (pAdapter->Type == MIB_IF_TYPE_LOOPBACK) ci.flags |= PIEthernet::ifLoopback;
ci.broadcast.clear();
ci.ptp.clear();
/*if (ci.flags[PIEthernet::ifBroadcast])
ci.broadcast = getSockAddr(ret->ifa_broadaddr);
if (ci.flags[PIEthernet::ifPTP])
ci.ptp = getSockAddr(ret->ifa_dstaddr);*/
il << ci;
pAdapter = pAdapter->Next;
}
} else
piCout << "[PIEthernet] GetAdaptersInfo failed with error: " << ret;
if (pAdapterInfo)
HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
return il;
#else
/*# ifdef QNX
PIStringList il, sl;
PIProcess proc;
proc.setGrabOutput(true);
proc.exec(ifconfigPath.c_str(), "-l");
@@ -436,38 +490,70 @@ PIStringList PIEthernet::interfaces() {
for (int j = 0; j < al; ++j)
sl << i.trimmed() + ":" + PIString::fromNumber(j);
}
//cout << out;
//cout << sl << endl;
return sl;
# else
PIStringList sl;
/*struct if_nameindex * ni = if_nameindex();
for (int i = 0; ; ++i) {
if (ni[i].if_name == 0 || ni[i].if_index == 0) break;
sl << PIString(ni[i].if_name);
}
if_freenameindex(ni);*/
PIProcess proc;
proc.setGrabOutput(true);
proc.exec(ifconfigPath.c_str(), "-s");
if (!proc.waitForFinish(1000)) return sl;
PIString out(proc.readOutput());
//cout << out << endl;
out.cutLeft(out.find('\n') + 1);
while (!out.isEmpty()) {
sl << out.left(out.find(' '));
out.cutLeft(out.find('\n') + 1);
}
//cout << sl << endl;
return sl;
# endif
# endif*/
PIEthernet::InterfaceList il;
Interface ci;
struct ifaddrs * ret;
int s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (getifaddrs(&ret) == 0) {
while (ret != 0) {
if (ret->ifa_addr->sa_family != AF_INET) {
ret = ret->ifa_next;
continue;
}
ci.name = PIString(ret->ifa_name);
ci.address = getSockAddr(ret->ifa_addr);
ci.netmask = getSockAddr(ret->ifa_netmask);
ci.mac.clear();
if (s != -1) {
struct ifreq ir;
strcpy(ir.ifr_name, ret->ifa_name);
if (ioctl(s, SIOCGIFHWADDR, &ir) == 0)
ci.mac = macFromBytes(PIByteArray(ir.ifr_hwaddr.sa_data, 6));
}
ci.flags = 0;
if (ret->ifa_flags & IFF_UP) ci.flags |= PIEthernet::ifActive;
if (ret->ifa_flags & IFF_RUNNING) ci.flags |= PIEthernet::ifRunning;
if (ret->ifa_flags & IFF_BROADCAST) ci.flags |= PIEthernet::ifBroadcast;
if (ret->ifa_flags & IFF_MULTICAST) ci.flags |= PIEthernet::ifMulticast;
if (ret->ifa_flags & IFF_LOOPBACK) ci.flags |= PIEthernet::ifLoopback;
if (ret->ifa_flags & IFF_POINTOPOINT) ci.flags |= PIEthernet::ifPTP;
ci.broadcast.clear();
ci.ptp.clear();
if (ci.flags[PIEthernet::ifBroadcast])
ci.broadcast = getSockAddr(ret->ifa_broadaddr);
if (ci.flags[PIEthernet::ifPTP])
ci.ptp = getSockAddr(ret->ifa_dstaddr);
ci.index = if_nametoindex(ret->ifa_name);
il << ci;
ret = ret->ifa_next;
}
freeifaddrs(ret);
} else
piCout << "[PIEthernet] Can`t get interfaces:" << errorString();
if (s != -1) ::close(s);
return il;
#endif
}
PIString PIEthernet::interfaceAddress(const PIString & interface_) {
#ifdef WINDOWS
piCout << "[PIEthernet] Not implemented on Windows, use \"PIEthernet::allAddresses\" instead";
piCout << "[PIEthernet] Not implemented on Windows, use \"PIEthernet::allAddresses\" or \"PIEthernet::interfaces\" instead";
return PIString();
#else
struct ifreq ifr;
@@ -484,7 +570,7 @@ PIString PIEthernet::interfaceAddress(const PIString & interface_) {
PIStringList PIEthernet::allAddresses() {
#ifdef WINDOWS
/*#ifdef WINDOWS
PIStringList al;
PIString ca;
PIP_ADAPTER_INFO pAdapterInfo, pAdapter = 0;
@@ -506,10 +592,6 @@ PIStringList PIEthernet::allAddresses() {
if ((ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
pAdapter = pAdapterInfo;
while (pAdapter) {
/*if (pAdapter->Type != MIB_IF_TYPE_ETHERNET && pAdapter->Type != MIB_IF_TYPE_LOOPBACK) {
pAdapter = pAdapter->Next;
continue;
}*/
ca = PIString(pAdapter->IpAddressList.IpAddress.String);
if (ca != "0.0.0.0") al << ca;
pAdapter = pAdapter->Next;
@@ -519,10 +601,11 @@ PIStringList PIEthernet::allAddresses() {
if (pAdapterInfo)
HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
return al;
#else
PIStringList il = interfaces(), al;
piForeachC (PIString & i, il)
al << interfaceAddress(i);
#else*/
PIEthernet::InterfaceList il = interfaces();
PIStringList al;
piForeachC (PIEthernet::Interface & i, il)
al << i.address;
return al.removeStrings("0.0.0.0");
#endif
//#endif
}

View File

@@ -46,8 +46,10 @@ public:
void setSendAddress(const PIString & ip_port) {parseAddress(ip_port, &ip_s, &port_s);}
void setSendIP(const PIString & ip) {ip_s = ip;}
void setSendPort(int port) {port_s = port;}
PIString readAddress() {return path_;}
PIString readIP() {parseAddress(path_, &ip_, &port_); return ip_;}
int readPort() {parseAddress(path_, &ip_, &port_); return port_;}
PIString sendAddress() {return ip_s + ":" + PIString::fromNumber(port_s);}
PIString sendIP() {return ip_s;}
int sendPort() {return port_s;}
@@ -83,14 +85,57 @@ public:
int read(void * read_to, int max_size);
int write(const void * data, int max_size);
int write(const PIByteArray & data) {return write(data.data(), data.size_s());}
static PIStringList interfaces();
static PIString interfaceAddress(const PIString & interface_);
static PIStringList allAddresses();
EVENT1(newConnection, PIEthernet * , client)
EVENT0(connected)
EVENT1(disconnected, bool, withError)
enum InterfaceFlag {
ifActive = 0x1,
ifRunning = 0x2,
ifBroadcast = 0x4,
ifMulticast = 0x8,
ifLoopback = 0x10,
ifPTP = 0x20
};
typedef PIFlags<InterfaceFlag> InterfaceFlags;
struct Interface {
int index;
PIString name;
PIString mac;
PIString address;
PIString netmask;
PIString broadcast;
PIString ptp;
InterfaceFlags flags;
bool isActive() const {return flags[PIEthernet::ifActive];}
bool isRunning() const {return flags[PIEthernet::ifRunning];}
bool isBroadcast() const {return flags[PIEthernet::ifBroadcast];}
bool isMulticast() const {return flags[PIEthernet::ifMulticast];}
bool isLoopback() const {return flags[PIEthernet::ifLoopback];}
bool isPTP() const {return flags[PIEthernet::ifPTP];}
};
class InterfaceList: public PIVector<PIEthernet::Interface> {
public:
InterfaceList(): PIVector<PIEthernet::Interface>() {}
const Interface * getByIndex(int index) const {for (int i = 0; i < size_s(); ++i) if ((*this)[i].index == index) return &((*this)[i]); return 0;}
const Interface * getByName(const PIString & name) const {for (int i = 0; i < size_s(); ++i) if ((*this)[i].name == name) return &((*this)[i]); return 0;}
const Interface * getByAddress(const PIString & address) const {for (int i = 0; i < size_s(); ++i) if ((*this)[i].address == address) return &((*this)[i]); return 0;}
const Interface * getLoopback() const {for (int i = 0; i < size_s(); ++i) if ((*this)[i].isLoopback()) return &((*this)[i]); return 0;}
};
static InterfaceList interfaces();
static PIString interfaceAddress(const PIString & interface_);
static PIStringList allAddresses();
static void parseAddress(const PIString & ipp, PIString * ip, int * port);
static PIString macFromBytes(const PIByteArray & mac) {PIString r; for (int i = 0; i < mac.size_s(); ++i) {r += PIString::fromNumber(mac[i], 16).expandLeftTo(2, '0'); if (i < mac.size_s() - 1) r += ":";} return r;}
static PIByteArray macToBytes(const PIString & mac) {PIByteArray r; PIStringList sl = mac.split(":"); piForeachC (PIString & i, sl) r << uchar(i.toInt(16)); return r;}
static PIString applyMask(const PIString & ip, const PIString & mask) {struct in_addr ia; ia.s_addr = inet_addr(ip.data()) & inet_addr(mask.data()); return PIString(inet_ntoa(ia));}
static PIString getBroadcast(const PIString & ip, const PIString & mask) {struct in_addr ia; ia.s_addr = inet_addr(ip.data()) | ~inet_addr(mask.data()); return PIString(inet_ntoa(ia));}
protected:
PIEthernet(int sock, PIString ip_port);
@@ -101,11 +146,12 @@ protected:
bool openDevice();
bool closeDevice();
#ifdef WINDOWS
void closeSocket(int & sd) {if (sd != -1) closesocket(sd); sd = -1;}
void closeSocket(int & sd) {if (sd != -1) {shutdown(sd, SD_BOTH); closesocket(sd);} sd = -1;}
#else
void closeSocket(int & sd) {if (sd != -1) ::close(sd); sd = -1;}
void closeSocket(int & sd) {if (sd != -1) {shutdown(sock, SHUT_RDWR); ::close(sd);} sd = -1;}
static PIString getSockAddr(sockaddr * s) {return s == 0 ? PIString() : PIString(inet_ntoa(((sockaddr_in*)s)->sin_addr));}
#endif
void parseAddress(const PIString & ipp, PIString * ip, int * port);
int sock, sock_s, port_, port_s, port_c, wrote;
bool connected_;
@@ -125,10 +171,10 @@ private:
static std::string ethErrorString() {
#ifdef WINDOWS
char * msg;
int err = WSAGetLastError();
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&msg, 0, NULL);
return "code " + itos(err) + " - " + string(msg);
char * msg;
int err = WSAGetLastError();
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&msg, 0, NULL);
return "code " + itos(err) + " - " + string(msg);
#else
return errorString();
#endif

View File

@@ -50,6 +50,12 @@ PIEvaluatorContent::PIEvaluatorContent() {
addFunction("sign", 1);
addFunction("rad", 1);
addFunction("deg", 1);
addFunction("j0", 1);
addFunction("j1", 1);
addFunction("jn", 2);
addFunction("y0", 1);
addFunction("y1", 1);
addFunction("yn", 2);
clearCustomVariables();
//addVariable("n", 0.);
//addVariable("x1", 123);
@@ -126,6 +132,12 @@ PIEvaluatorTypes::BaseFunctions PIEvaluatorContent::getBaseFunction(const PIStri
if (name == "sign") return PIEvaluatorTypes::bfSign;
if (name == "rad") return PIEvaluatorTypes::bfRad;
if (name == "deg") return PIEvaluatorTypes::bfDeg;
if (name == "j0") return PIEvaluatorTypes::bfJ0;
if (name == "j1") return PIEvaluatorTypes::bfJ1;
if (name == "jn") return PIEvaluatorTypes::bfJN;
if (name == "y0") return PIEvaluatorTypes::bfY0;
if (name == "y1") return PIEvaluatorTypes::bfY1;
if (name == "yn") return PIEvaluatorTypes::bfYN;
return PIEvaluatorTypes::bfUnknown;
}
@@ -957,6 +969,24 @@ inline void PIEvaluator::execFunction(const PIEvaluatorTypes::Instruction & ci)
case PIEvaluatorTypes::bfDeg:
tmpvars[oi].value = value(ci.operators[0]) * complexd(rad2deg, 0.);
break;
case PIEvaluatorTypes::bfJ0:
tmpvars[oi].value = j0(value(ci.operators[0]).real());
break;
case PIEvaluatorTypes::bfJ1:
tmpvars[oi].value = j1(value(ci.operators[0]).real());
break;
case PIEvaluatorTypes::bfJN:
tmpvars[oi].value = jn(round(value(ci.operators[1]).real()), value(ci.operators[0]).real());
break;
case PIEvaluatorTypes::bfY0:
tmpvars[oi].value = y0(value(ci.operators[0]).real());
break;
case PIEvaluatorTypes::bfY1:
tmpvars[oi].value = y1(value(ci.operators[0]).real());
break;
case PIEvaluatorTypes::bfYN:
tmpvars[oi].value = yn(round(value(ci.operators[1]).real()), value(ci.operators[0]).real());
break;
case PIEvaluatorTypes::bfRandom:
tmp = static_cast<ldouble>(rand()) / RAND_MAX;
stmp = value(ci.operators[1]) - value(ci.operators[0]);

View File

@@ -36,7 +36,8 @@ namespace PIEvaluatorTypes {
bfSqrt, bfSqr, bfPow, bfAbs,
bfLn, bfLg, bfLog, bfSign,
bfIm, bfRe, bfArg, bfLen, bfConj,
bfRad, bfDeg};
bfRad, bfDeg, bfJ0, bfJ1, bfJN,
bfY0, bfY1, bfYN};
struct Instruction {
Instruction() {;}

View File

@@ -104,7 +104,7 @@ void PIFile::resize(llong new_size, char fill_) {
delete[] buff;
return;
}
piCout << "[PIFile] Downsize is not support yet :-(";
piCoutObj << "[PIFile] Downsize is not support yet :-(";
}

View File

@@ -36,7 +36,7 @@ public:
//PIFile & operator =(const PIFile & f) {path_ = f.path_; type_ = f.type_; return *this;}
void flush() {if (!opened_) fflush(fd);}
void flush() {if (opened_) fflush(fd);}
EVENT_HANDLER(void, clear) {close(); fd = fopen(path_.data(), "w"); if (fd != 0) fclose(fd); fd = 0; opened_ = false; open();}
void seek(llong position) {if (!opened_) return; fseek(fd, position, SEEK_SET); clearerr(fd);}
void seekToBegin() {if (!opened_) return; fseek(fd, 0, SEEK_SET); clearerr(fd);}
@@ -79,34 +79,34 @@ public:
PIFile & operator =(const PIFile & f) {path_ = f.path_; mode_ = f.mode_; return *this;}
PIFile & operator <<(const char v) {if (!isWriteable()) return *this; write(&v, 1); return *this;}
PIFile & operator <<(const char v) {if (canWrite() && fd != 0) write(&v, 1); return *this;}
//PIFile & operator <<(const string & v) {write(v.c_str(), v.size()); return *this;}
PIFile & operator <<(const PIString & v) {if (!isWriteable()) return *this; write(v.data(), v.lengthAscii()); return *this;}
PIFile & operator <<(const PIByteArray & v) {if (!isWriteable()) return *this; write(v.data(), v.size()); return *this;}
PIFile & operator <<(short v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%hd", v); return *this;}
PIFile & operator <<(int v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%d", v); return *this;}
PIFile & operator <<(long v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%ld", v); return *this;}
PIFile & operator <<(llong v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%lld", v); return *this;}
PIFile & operator <<(uchar v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%u", int(v)); return *this;}
PIFile & operator <<(ushort v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%hu", v); return *this;}
PIFile & operator <<(uint v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%u", v); return *this;}
PIFile & operator <<(ulong v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%lu", v); return *this;}
PIFile & operator <<(ullong v) {if (!isWriteable()) return *this; ret = fprintf(fd, "%llu", v); return *this;}
PIFile & operator <<(float v) {if (!isWriteable()) return *this; ret = fprintf(fd, ("%" + prec_str + "f").c_str(), v); return *this;}
PIFile & operator <<(double v) {if (!isWriteable()) return *this; ret = fprintf(fd, ("%" + prec_str + "lf").c_str(), v); return *this;}
PIFile & operator <<(const PIString & v) {if (canWrite() && fd != 0) write(v.data(), v.lengthAscii()); return *this;}
PIFile & operator <<(const PIByteArray & v) {if (canWrite() && fd != 0) write(v.data(), v.size()); return *this;}
PIFile & operator <<(short v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%hd", v); return *this;}
PIFile & operator <<(int v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%d", v); return *this;}
PIFile & operator <<(long v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%ld", v); return *this;}
PIFile & operator <<(llong v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%lld", v); return *this;}
PIFile & operator <<(uchar v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%u", int(v)); return *this;}
PIFile & operator <<(ushort v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%hu", v); return *this;}
PIFile & operator <<(uint v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%u", v); return *this;}
PIFile & operator <<(ulong v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%lu", v); return *this;}
PIFile & operator <<(ullong v) {if (canWrite() && fd != 0) ret = fprintf(fd, "%llu", v); return *this;}
PIFile & operator <<(float v) {if (canWrite() && fd != 0) ret = fprintf(fd, ("%" + prec_str + "f").c_str(), v); return *this;}
PIFile & operator <<(double v) {if (canWrite() && fd != 0) ret = fprintf(fd, ("%" + prec_str + "lf").c_str(), v); return *this;}
PIFile & operator >>(char & v) {if (!isWriteable()) return *this; ret = fscanf(fd, "%hhn", &v); return *this;}
PIFile & operator >>(short & v) {if (!isWriteable()) return *this; ret = fscanf(fd, "%hn", &v); return *this;}
PIFile & operator >>(int & v) {if (!isWriteable()) return *this; ret = fscanf(fd, "%n", &v); return *this;}
PIFile & operator >>(long & v) {if (!isWriteable()) return *this; ret = fscanf(fd, "%ln", &v); return *this;}
PIFile & operator >>(llong & v) {if (!isWriteable()) return *this; ret = fscanf(fd, "%lln", &v); return *this;}
PIFile & operator >>(uchar & v) {if (!isWriteable()) return *this; ret = fscanf(fd, "%hhn", &v); return *this;}
PIFile & operator >>(ushort & v) {if (!isWriteable()) return *this; ret = fscanf(fd, "%hn", &v); return *this;}
PIFile & operator >>(uint & v) {if (!isWriteable()) return *this; ret = fscanf(fd, "%n", &v); return *this;}
PIFile & operator >>(ulong & v) {if (!isWriteable()) return *this; ret = fscanf(fd, "%ln", &v); return *this;}
PIFile & operator >>(ullong & v) {if (!isWriteable()) return *this; ret = fscanf(fd, "%lln", &v); return *this;}
PIFile & operator >>(float & v) {if (!isWriteable()) return *this; ret = fscanf(fd, "%f", &v); return *this;}
PIFile & operator >>(double & v) {if (!isWriteable()) return *this; ret = fscanf(fd, "%lf", &v); return *this;}
PIFile & operator >>(char & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%hhn", &v); return *this;}
PIFile & operator >>(short & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%hn", &v); return *this;}
PIFile & operator >>(int & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%n", &v); return *this;}
PIFile & operator >>(long & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%ln", &v); return *this;}
PIFile & operator >>(llong & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%lln", &v); return *this;}
PIFile & operator >>(uchar & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%hhn", &v); return *this;}
PIFile & operator >>(ushort & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%hn", &v); return *this;}
PIFile & operator >>(uint & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%n", &v); return *this;}
PIFile & operator >>(ulong & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%ln", &v); return *this;}
PIFile & operator >>(ullong & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%lln", &v); return *this;}
PIFile & operator >>(float & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%f", &v); return *this;}
PIFile & operator >>(double & v) {if (canRead() && fd != 0) ret = fscanf(fd, "%lf", &v); return *this;}
static PIFile openTemporary(PIIODevice::DeviceMode mode = PIIODevice::ReadWrite) {return PIFile(PIString(tmpnam(0)), mode);}
static bool isExists(const PIString & path);

View File

@@ -18,7 +18,7 @@
*/
#include "piincludes.h"
#include "pimutex.h"
#include "piconsole.h"
bool isPIInit = false;
bool piDebug = true;
@@ -53,18 +53,167 @@ PIMutex __PICout_mutex__;
*/
PICout::PICout(PIFlags<PICoutControl> controls): fo_(true), cc_(false), co_(controls) {
#ifdef WINDOWS
void * PICout::hOut = 0;
WORD PICout::dattr = 0;
DWORD PICout::smode = 0;
#endif
PICout::PICout(PIFlags<PICoutControl> controls): fo_(true), cc_(false), fc_(false), cnb_(10), co_(controls) {
#ifdef WINDOWS
if (hOut == 0) {
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO sbi;
GetConsoleScreenBufferInfo(hOut, &sbi);
dattr = sbi.wAttributes;
}
attr_ = dattr;
#endif
__PICout_mutex__.lock();
}
PICout::~PICout() {
if (fc_) applyFormat(PICoutManipulators::Default);
if (cc_) return;
newLine();
__PICout_mutex__.unlock();
}
PICout PICout::operator<<(const PICoutAction v) {
#ifdef WINDOWS
CONSOLE_SCREEN_BUFFER_INFO sbi;
COORD coord;
CONSOLE_CURSOR_INFO curinfo;
#endif
switch (v) {
case PICoutManipulators::Flush: std::cout << std::flush; break;
case PICoutManipulators::Backspace:
#ifdef WINDOWS
GetConsoleScreenBufferInfo(hOut, &sbi);
coord = sbi.dwCursorPosition;
coord.X = piMax<int>(0, int(coord.X) - 1);
SetConsoleCursorPosition(hOut, coord);
printf(" ");
SetConsoleCursorPosition(hOut, coord);
#else
printf("\e[1D \e[1D");
#endif
break;
case PICoutManipulators::ShowCursor:
#ifdef WINDOWS
GetConsoleCursorInfo(hOut, &curinfo);
curinfo.bVisible = true;
SetConsoleCursorInfo(hOut, &curinfo);
#else
printf("\e[?25h");
#endif
break;
case PICoutManipulators::HideCursor:
#ifdef WINDOWS
CONSOLE_CURSOR_INFO curinfo;
GetConsoleCursorInfo(hOut, &curinfo);
curinfo.bVisible = false;
SetConsoleCursorInfo(hOut, &curinfo);
#else
printf("\e[?25l");
#endif
break;
default: break;
};
return *this;
}
#define PINUMERICCOUT if (cnb_ == 10) std::cout << v; else std::cout << PIString::fromNumber(v, cnb_);
PICout PICout::operator <<(const uchar v) {space(); if (cnb_ == 10) std::cout << ushort(v); else std::cout << PIString::fromNumber(v, cnb_); return *this;}
PICout PICout::operator <<(const short int v) {space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const ushort v) {space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const int v) {space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const uint v) {space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const long v) {space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const ulong v) {space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const llong v) {space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const ullong v) {space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const float v) {space(); std::cout << v; return *this;}
PICout PICout::operator <<(const double v) {space(); std::cout << v; return *this;}
#undef PINUMERICCOUT
void PICout::applyFormat(PICoutFormat f) {
fc_ = true;
#ifdef WINDOWS
static int mask_fore = ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
static int mask_back = ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
switch (f) {
case Bin: case Oct: case Dec: case Hex: break;
case PICoutManipulators::Bold: attr_ |= FOREGROUND_INTENSITY; break;
case PICoutManipulators::Underline: attr_ |= COMMON_LVB_UNDERSCORE; break;
case PICoutManipulators::Black: attr_ = (attr_ & mask_fore); break;
case PICoutManipulators::Red: attr_ = (attr_ & mask_fore) | FOREGROUND_RED; break;
case PICoutManipulators::Green: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN; break;
case PICoutManipulators::Blue: attr_ = (attr_ & mask_fore) | FOREGROUND_BLUE; break;
case PICoutManipulators::Yellow: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN; break;
case PICoutManipulators::Magenta: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_BLUE; break;
case PICoutManipulators::Cyan: attr_ = (attr_ & mask_fore) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
case PICoutManipulators::White: attr_ = (attr_ & mask_fore) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
case PICoutManipulators::BackBlack: attr_ = (attr_ & mask_back); break;
case PICoutManipulators::BackRed: attr_ = (attr_ & mask_back) | BACKGROUND_RED; break;
case PICoutManipulators::BackGreen: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN; break;
case PICoutManipulators::BackBlue: attr_ = (attr_ & mask_back) | BACKGROUND_BLUE; break;
case PICoutManipulators::BackYellow: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN; break;
case PICoutManipulators::BackMagenta: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_BLUE; break;
case PICoutManipulators::BackCyan: attr_ = (attr_ & mask_back) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
case PICoutManipulators::BackWhite: attr_ = (attr_ & mask_back) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
case PICoutManipulators::Default: attr_ = dattr; break;
default: break;
}
SetConsoleTextAttribute(hOut, attr_);
#else
switch (f) {
case Bin: case Oct: case Dec: case Hex: break;
case PICoutManipulators::Bold: printf("\e[1m"); break;
case PICoutManipulators::Faint: printf("\e[2m"); break;
case PICoutManipulators::Italic: printf("\e[3m"); break;
case PICoutManipulators::Underline: printf("\e[4m"); break;
case PICoutManipulators::Blink: printf("\e[5m"); break;
case PICoutManipulators::Black: printf("\e[30m"); break;
case PICoutManipulators::Red: printf("\e[31m"); break;
case PICoutManipulators::Green: printf("\e[32m"); break;
case PICoutManipulators::Blue: printf("\e[34m"); break;
case PICoutManipulators::Yellow: printf("\e[33m"); break;
case PICoutManipulators::Magenta: printf("\e[35m"); break;
case PICoutManipulators::Cyan: printf("\e[36m"); break;
case PICoutManipulators::White: printf("\e[37m"); break;
case PICoutManipulators::BackBlack: printf("\e[40m"); break;
case PICoutManipulators::BackRed: printf("\e[41m"); break;
case PICoutManipulators::BackGreen: printf("\e[42m"); break;
case PICoutManipulators::BackBlue: printf("\e[44m"); break;
case PICoutManipulators::BackYellow: printf("\e[43m"); break;
case PICoutManipulators::BackMagenta: printf("\e[45m"); break;
case PICoutManipulators::BackCyan: printf("\e[46m"); break;
case PICoutManipulators::BackWhite: printf("\e[47m"); break;
case PICoutManipulators::Default: printf("\e[0m"); break;
default: break;
}
#endif
}
/*! \mainpage Title
* This is main page
*/

View File

@@ -27,7 +27,7 @@
#define PIINCLUDES_H
//! Version of PIP in hex - 0x##(Major)##(Minor)##(Revision)
#define PIP_VERSION 0x000304
#define PIP_VERSION 0x000306
//! Major value of PIP version
#define PIP_VERSION_MAJOR (PIP_VERSION & 0xFF0000) >> 16
@@ -78,16 +78,16 @@
#endif
#if WIN32 || WIN64 || _WIN32 || _WIN64 || __WIN32__ || __WIN64__
#if defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__WIN64__)
# define WINDOWS
#endif
#if __QNX__ || __QNXNTO__
#if defined(__QNX__) || defined(__QNXNTO__)
# define QNX
#endif
#if __FreeBSD__
#ifdef __FreeBSD__
# define FREE_BSD
#endif
#if __APPLE__ || __MACH__
#if defined(__APPLE__) || defined(__MACH__)
# define MAC_OS
#endif
#ifndef WINDOWS
@@ -99,7 +99,7 @@
# endif
# endif
#endif
#if __GNUC__
#ifdef __GNUC__
# define CC_GCC
# define CC_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__)
# if CC_GCC_VERSION > 0x025F // > 2.95
@@ -107,8 +107,25 @@
# define HAS_LOCALE
# endif
# endif
#elif _MSC_VER
# pragma GCC diagnostic ignored "-Wformat"
# pragma GCC diagnostic ignored "-Wformat-extra-args"
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
#elif defined(_MSC_VER)
# define CC_VC
# pragma warning(disable: 4061)
# pragma warning(disable: 4100)
# pragma warning(disable: 4239)
# pragma warning(disable: 4242)
# pragma warning(disable: 4244)
# pragma warning(disable: 4251)
# pragma warning(disable: 4365)
# pragma warning(disable: 4512)
# pragma warning(disable: 4668)
# pragma warning(disable: 4710)
# pragma warning(disable: 4800)
# pragma warning(disable: 4820)
# pragma warning(disable: 4986)
# pragma warning(disable: 4996)
#else
# define CC_OTHER
#endif
@@ -168,7 +185,7 @@
#include <set>
#include <map>
#ifdef WINDOWS
typedef int socklen_t;
typedef int socklen_t;
# include <conio.h>
# include <io.h>
# include <winsock2.h>
@@ -189,6 +206,7 @@ typedef int socklen_t;
# include <fcntl.h>
# include <sys/ioctl.h>
# include <net/if.h>
# include <ifaddrs.h>
#endif
#ifdef MAC_OS
# include <mach/mach_traps.h>
@@ -196,8 +214,8 @@ typedef int socklen_t;
# include <mach/clock.h>
# include <crt_externs.h>
# define environ (*_NSGetEnviron())
typedef long time_t;
extern clock_serv_t __pi_mac_clock;
typedef long time_t;
extern clock_serv_t __pi_mac_clock;
#endif
#ifndef QNX
# ifndef WINDOWS
@@ -212,7 +230,7 @@ extern clock_serv_t __pi_mac_clock;
# define PIP_TIMER_RT
#endif
#ifdef FREE_BSD
extern char ** environ;
extern char ** environ;
#endif
#include "pimonitor.h"
@@ -405,7 +423,7 @@ template<typename T> inline T piClamp(const T & v, const T & min, const T & max)
extern bool isPIInit;
//! global variable enabling output to piCout
extern bool piDebug;
extern PIP_EXPORT bool piDebug;
extern string ifconfigPath;
@@ -656,6 +674,9 @@ private:
//! Macro used for conditional (piDebug) output to PICout
#define piCout if (piDebug) PICout()
//! Macro used for conditional (piDebug and PIObject::debug()) output to PICout for subclasses of PIObject
#define piCoutObj if (piDebug && debug_) PICout()
class PIMutex;
extern PIMutex __PICout_mutex__;
@@ -664,25 +685,58 @@ namespace PICoutManipulators {
//! \brief Enum contains special characters
enum PIP_EXPORT PICoutSpecialChar {
Null /*! Null-character, '\\0' */,
NewLine /*! New line character, '\\n' */,
Tab /*! Tab character, '\\t' */,
Esc /*! Escape character, '\\e' */,
Quote /*! Quote character, '"' */
Null /*! Null-character, '\\0' */,
NewLine /*! New line character, '\\n' */,
Tab /*! Tab character, '\\t' */,
Esc /*! Escape character, '\\e' */,
Quote /*! Quote character, '"' */
};
//! \brief Enum contains immediate action
enum PIP_EXPORT PICoutAction {
Flush /*! Flush the output */
Flush /*! Flush the output */,
Backspace /*! Remove last symbol */,
ShowCursor /*! Show cursor */,
HideCursor /*! Hide cursor */
};
//! \brief Enum contains control of PICout
enum PIP_EXPORT PICoutControl {
AddNone /*! No controls */ = 0x0,
AddSpaces /*! Spaces will be appear after each output */ = 0x1,
AddNewLine /*! New line will be appear after all output */ = 0x2,
AddQuotes /*! Each string will be quoted */ = 0x4,
AddAll /*! All controls */ = 0xFFFFFFFF
AddNone /*! No controls */ = 0x0,
AddSpaces /*! Spaces will be appear after each output */ = 0x1,
AddNewLine /*! New line will be appear after all output */ = 0x2,
AddQuotes /*! Each string will be quoted */ = 0x4,
AddAll /*! All controls */ = 0xFFFFFFFF
};
//! \brief Enum contains output format
enum PIP_EXPORT PICoutFormat {
Bin /*! Binary representation of integers */ = 0x01,
Oct /*! Octal representation of integers */ = 0x02,
Dec /*! Decimal representation of integers */ = 0x04,
Hex /*! Hexadecimal representation of integers */ = 0x08,
Bold /*! Bold */ = 0x10,
Faint /*! */ = 0x20,
Italic /*! */ = 0x40,
Underline /*! Underline */ = 0x80,
Blink /*! Blink */ = 0x100,
Black /*! Black font */ = 0x400,
Red /*! Red font */ = 0x800,
Green /*! Green font */ = 0x1000,
Blue /*! Blue font */ = 0x2000,
Yellow /*! Yellow font */ = 0x4000,
Magenta /*! Magenta font */ = 0x8000,
Cyan /*! Cyan font */ = 0x10000,
White /*! White font */ = 0x20000,
BackBlack /*! Black background */ = 0x40000,
BackRed /*! Red background */ = 0x80000,
BackGreen /*! Green background */ = 0x100000,
BackBlue /*! Blue background */ = 0x200000,
BackYellow /*! Yellow background */ = 0x400000,
BackMagenta /*! Magenta background */ = 0x800000,
BackCyan /*! Cyan background */ = 0x1000000,
BackWhite /*! White background */ = 0x2000000,
Default /*! Default format */ = 0x4000000,
};
};
@@ -695,7 +749,7 @@ public:
//! Default constructor with default features
PICout(PIFlags<PICoutControl> controls = AddSpaces | AddNewLine);
PICout(const PICout & other): fo_(other.fo_), cc_(true), co_(other.co_) {;}
PICout(const PICout & other): fo_(other.fo_), cc_(true), fc_(false), cnb_(other.cnb_), attr_(other.attr_), co_(other.co_) {;}
~PICout();
//! Output operator for strings with <tt>"const char * "</tt> type
@@ -711,89 +765,141 @@ public:
PICout operator <<(const char v) {space(); std::cout << v; return *this;}
//! Output operator for <tt>"unsigned char"</tt> values
PICout operator <<(const uchar v) {space(); std::cout << ushort(v); return *this;}
PICout operator <<(const uchar v);
//! Output operator for <tt>"short"</tt> values
PICout operator <<(const short v) {space(); std::cout << v; return *this;}
PICout operator <<(const short v);
//! Output operator for <tt>"unsigned short"</tt> values
PICout operator <<(const ushort v) {space(); std::cout << v; return *this;}
PICout operator <<(const ushort v);
//! Output operator for <tt>"int"</tt> values
PICout operator <<(const int v) {space(); std::cout << v; return *this;}
PICout operator <<(const int v);
//! Output operator for <tt>"unsigned int"</tt> values
PICout operator <<(const uint v) {space(); std::cout << v; return *this;}
PICout operator <<(const uint v);
//! Output operator for <tt>"long"</tt> values
PICout operator <<(const long v) {space(); std::cout << v; return *this;}
PICout operator <<(const long v);
//! Output operator for <tt>"unsigned long"</tt> values
PICout operator <<(const ulong v) {space(); std::cout << v; return *this;}
PICout operator <<(const ulong v);
//! Output operator for <tt>"long long"</tt> values
PICout operator <<(const llong v) {space(); std::cout << v; return *this;}
PICout operator <<(const llong v);
//! Output operator for <tt>"unsigned long long"</tt> values
PICout operator <<(const ullong v) {space(); std::cout << v; return *this;}
PICout operator <<(const ullong v);
//! Output operator for <tt>"float"</tt> values
PICout operator <<(const float v) {space(); std::cout << v; return *this;}
PICout operator <<(const float v);
//! Output operator for <tt>"double"</tt> values
PICout operator <<(const double v) {space(); std::cout << v; return *this;}
PICout operator <<(const double v);
//! Output operator for \a PICoutSpecialChar values
PICout operator <<(const PICoutSpecialChar v) {
switch (v) {
case Null: std::cout << char(0);
case NewLine: std::cout << '\n';
case Tab: std::cout << '\t';
case Esc: std::cout << '\e';
case Quote: std::cout << '"';
case Null: std::cout << char(0); break;
case NewLine: std::cout << '\n'; fo_ = true; break;
case Tab: std::cout << '\t'; break;
case Esc:
#ifdef CC_VC
std::cout << char(27);
#else
std::cout << '\e';
#endif
break;
case Quote: std::cout << '"'; break;
};
return *this;
}
//! Output operator for \a PIFlags<PICoutFormat> values
PICout operator <<(const PIFlags<PICoutFormat> v) {
if (v[Bin]) cnb_ = 2;
if (v[Oct]) cnb_ = 8;
if (v[Dec]) cnb_ = 10;
if (v[Hex]) cnb_ = 16;
if (v[Bold]) applyFormat(Bold);
if (v[Faint]) applyFormat(Faint);
if (v[Italic]) applyFormat(Italic);
if (v[Underline]) applyFormat(Underline);
if (v[Blink]) applyFormat(Blink);
if (v[Black]) applyFormat(Black);
if (v[Red]) applyFormat(Red);
if (v[Green]) applyFormat(Green);
if (v[Blue]) applyFormat(Blue);
if (v[Yellow]) applyFormat(Yellow);
if (v[Magenta]) applyFormat(Magenta);
if (v[Cyan]) applyFormat(Cyan);
if (v[White]) applyFormat(White);
if (v[BackBlack]) applyFormat(BackBlack);
if (v[BackRed]) applyFormat(BackRed);
if (v[BackGreen]) applyFormat(BackGreen);
if (v[BackBlue]) applyFormat(BackBlue);
if (v[BackYellow]) applyFormat(BackYellow);
if (v[BackMagenta]) applyFormat(BackMagenta);
if (v[BackCyan]) applyFormat(BackCyan);
if (v[BackWhite]) applyFormat(BackWhite);
if (v[Default]) applyFormat(Default);
return *this;
}
//! Output operator for \a PICoutFormat values
PICout operator <<(const PICoutFormat v) {
switch (v) {
case Bin: cnb_ = 2; break;
case Oct: cnb_ = 8; break;
case Dec: cnb_ = 10; break;
case Hex: cnb_ = 16; break;
default: applyFormat(v);
};
return *this;
}
//! Do some action
PICout operator <<(const PICoutAction v) {
switch (v) {
case Flush: std::cout << std::flush;
};
return *this;
}
PICout operator <<(const PICoutAction v);
//! Set control flag "c" is "on" state
void setControl(PICoutControl c, bool on = true) {co_.setFlag(c, on);}
PICout & setControl(PICoutControl c, bool on = true) {co_.setFlag(c, on); return *this;}
//! Set control flags "c" and if "save" exec \a saveControl()
void setControl(PICoutControls c, bool save = false) {if (save) saveControl(); co_ = c;}
//! Set control flags "c" and if "save" exec \a saveControl()
PICout & setControl(PICoutControls c, bool save = false) {if (save) saveControl(); co_ = c; return *this;}
//! Save control flags to internal stack \sa \a restoreControl()
void saveControl() {cos_.push(co_);}
PICout & saveControl() {cos_.push(co_); return *this;}
//! Restore control flags from internal stack \sa \a saveControl()
void restoreControl() {if (!cos_.empty()) {co_ = cos_.top(); cos_.pop();}}
PICout & restoreControl() {if (!cos_.empty()) {co_ = cos_.top(); cos_.pop();} return *this;}
/*! \brief Conditional put space character to output
* \details If it is not a first output and control \a AddSpaces is set
* space character is put \sa \a quote(), \a newLine() */
inline void space() {if (!fo_ && co_[AddSpaces]) std::cout << ' '; fo_ = false;}
inline PICout & space() {if (!fo_ && co_[AddSpaces]) std::cout << ' '; fo_ = false; return *this;}
/*! \brief Conditional put quote character to output
* \details If control \a AddQuotes is set
* quote character is put \sa \a space(), \a newLine() */
inline void quote() {if (co_[AddQuotes]) std::cout << '"'; fo_ = false;}
inline PICout & quote() {if (co_[AddQuotes]) std::cout << '"'; fo_ = false; return *this;}
/*! \brief Conditional put new line character to output
* \details If control \a AddNewLine is set
* new line character is put \sa \a space(), \a quote() */
inline void newLine() {if (co_[AddNewLine]) std::cout << std::endl; fo_ = false;}
inline PICout & newLine() {if (co_[AddNewLine]) std::cout << std::endl; fo_ = false; return *this;}
private:
bool fo_, cc_;
void applyFormat(PICoutFormat f);
bool fo_, cc_, fc_;
int cnb_, attr_;
PICoutControls co_;
std::stack<PICoutControls> cos_;
#ifdef WINDOWS
static void * hOut;
static WORD dattr;
static DWORD smode;
#endif
};
#endif // PIINCLUDES_H

View File

@@ -24,7 +24,7 @@
* \brief Base class for input/output classes
*
* \section PIIODevice_sec0 Synopsis
* This class provide open/close logic, threaded read and virtual input/output
* This class provide open/close logic, threaded read/write and virtual input/output
* functions \a read() and \a write(). You should implement pure virtual
* function \a openDevice() in your subclass.
*
@@ -41,13 +41,20 @@
* bool func_name(void * Threaded_read_data, uchar * readed_data, int readed_size)\n
* Threaded read starts with function \a startThreadedRead().
*
* \section PIIODevice_sec3 Internal buffer
* \section PIIODevice_sec3 Threaded write
* PIIODevice aggregate another PIThread to perform a threaded write by function
* \a writeThreaded(). This function add task to internal queue and return
* queue entry ID. You should start write thread by function \a startThreadedWrite.
* On successful write event \a threadedWriteEvent is raised with two arguments -
* task ID and written bytes count.
*
* \section PIIODevice_sec4 Internal buffer
* PIIODevice have internal buffer for threaded read, and \a threadedRead() function
* receive pointer to this buffer in first argument. You can adjust size of this buffer
* by function \a setThreadedReadBufferSize() \n
* Default size of this buffer is 4096 bytes
*
* \section PIIODevice_sec4 Reopen
* \section PIIODevice_sec5 Reopen
* When threaded read is begin its call \a open() if device is closed. While threaded
* read running PIIODevice check if device opened every read and if not call \a open()
* every reopen timeout if reopen enabled. Reopen timeout is set by \a setReopenTimeout(),
@@ -58,11 +65,10 @@
*/
//! Constructs a empty PIIODevice
PIIODevice::PIIODevice(): PIThread() {
mode_ = ReadOnly;
opened_ = init_ = thread_started_ = false;
reopen_enabled_ = true;
reopen_enabled_ = raise_threaded_read_ = true;
reopen_timeout_ = 1000;
ret_func_ = 0;
ret_data_ = 0;
@@ -82,7 +88,7 @@ PIIODevice::PIIODevice(const PIString & path, PIIODevice::DeviceMode type, bool
path_ = path;
mode_ = type;
opened_ = init_ = thread_started_ = false;
reopen_enabled_ = true;
reopen_enabled_ = raise_threaded_read_ = true;
reopen_timeout_ = 1000;
ret_func_ = 0;
ret_data_ = 0;
@@ -150,7 +156,7 @@ void PIIODevice::begin() {
void PIIODevice::run() {
if (!isReadable()) {
//cout << "not readable\n";
stop();
PIThread::stop();
return;
}
if (!thread_started_) {
@@ -165,7 +171,7 @@ void PIIODevice::run() {
return;
}
threadedRead(buffer_tr.data(), readed_);
threadedReadEvent(buffer_tr.data(), readed_);
if (raise_threaded_read_) threadedReadEvent(buffer_tr.data(), readed_);
}

View File

@@ -28,23 +28,13 @@
// function executed from threaded read, pass ThreadedReadData, readedData, sizeOfData
typedef bool (*ReadRetFunc)(void * , uchar * , int );
// events:
// void opened()
// void closed()
//
// handlers:
// bool open()
// bool open(const PIString & path)
// bool open(const DeviceMode & type)
// bool open(const PIString & path, const DeviceMode & type)
// bool close()
// bool initialize()
// void flush()
class PIP_EXPORT PIIODevice: public PIThread
{
PIOBJECT(PIIODevice)
public:
//! Constructs a empty PIIODevice
PIIODevice();
//! \brief Open modes for PIIODevice
@@ -55,7 +45,7 @@ public:
};
PIIODevice(const PIString & path, DeviceMode type = ReadWrite, bool initNow = true);
virtual ~PIIODevice() {stop(); write_thread.stop(); if (opened_) {closeDevice(); if (!opened_) closed();}}
virtual ~PIIODevice() {stop(); if (opened_) {closeDevice(); if (!opened_) closed();}}
//! Current open mode of device
DeviceMode mode() const {return mode_;}
@@ -63,67 +53,119 @@ public:
//! Current path of device
PIString path() const {return path_;}
//! return \b true if mode is ReadOnly or ReadWrite
//! Set path of device
void setPath(const PIString & path) {path_ = path;}
//! Return \b true if mode is ReadOnly or ReadWrite
bool isReadable() const {return (mode_ & ReadOnly);}
//! return \b true if mode is WriteOnly or ReadWrite
//! Return \b true if mode is WriteOnly or ReadWrite
bool isWriteable() const {return (mode_ & WriteOnly);}
bool isInitialized() const {return init_;}
//! return \b true if device is successfully opened
//! Return \b true if device is successfully opened
bool isOpened() const {return opened_;}
//! return \b true if device is closed
//! Return \b true if device is closed
bool isClosed() const {return !opened_;}
//! return \b true if device can read \b now
//! Return \b true if device can read \b now
bool canRead() const {return opened_ && (mode_ & ReadOnly);}
//! return \b true if device can write \b now
//! Return \b true if device can write \b now
bool canWrite() const {return opened_ && (mode_ & WriteOnly);}
// Enable timer to periodically open device until it will be opened
//! Set execution of \a open enabled while threaded read on closed device
void setReopenEnabled(bool yes = true) {reopen_enabled_ = yes;}
//! Set timeout in milliseconds between \a open tryings if reopen is enabled
void setReopenTimeout(int msecs = 1000) {reopen_timeout_ = msecs;}
//! Return reopen enable
bool isReopenEnabled() const {return reopen_enabled_;}
//! Return reopen timeout
int reopenTimeout() {return reopen_timeout_;}
// set return function executed when successful read in thread
/** \brief Set "threaded read slot"
* \details Set external static function of threaded read that will be executed
* at every successful threaded read. Function should have format
* "bool func(void * data, uchar * readed, int size)" */
void setThreadedReadSlot(ReadRetFunc func) {ret_func_ = func;}
//! Set custom data that will be passed to "threaded read slot"
void setThreadedReadData(void * d) {ret_data_ = d;}
/** \brief Set size of threaded read buffer
* \details Default size is 4096 bytes. If your device can read at single read
* more than 4096 bytes you should use this function to adjust buffer size */
void setThreadedReadBufferSize(int new_size) {buffer_tr.resize(new_size);}
//! Return size of threaded read buffer
int threadedReadBufferSize() const {return buffer_tr.size_s();}
//! Return content of threaded read buffer
const uchar * threadedReadBuffer() const {return buffer_tr.data();}
bool isThreadedRead() const {return isRunning();}
void startThreadedRead() {if (!isRunning()) start();}
void startThreadedRead(ReadRetFunc func) {ret_func_ = func; if (!isRunning()) start();}
//! Return \b true if threaded read is started
bool isThreadedRead() const {return isRunning();}
//! Start threaded read
void startThreadedRead() {if (!isRunning()) PIThread::start();}
//! Start threaded read and assign "threaded read slot" to "func"
void startThreadedRead(ReadRetFunc func) {ret_func_ = func; if (!isRunning()) PIThread::start();}
//! Stop threaded read
void stopThreadedRead() {PIThread::stop();}
//! Return \b true if threaded write is started
bool isThreadedWrite() const {return write_thread.isRunning();}
//! Start threaded write
void startThreadedWrite() {if (!write_thread.isRunning()) write_thread.startOnce();}
//! Stop threaded write
void stopThreadedWrite() {write_thread.stop();}
//! Clear threaded write task queue
void clearThreadedWriteQueue() {write_thread.lock(); write_queue.clear(); write_thread.unlock();}
//! Start both threaded read and threaded write
void start() {startThreadedRead(); startThreadedWrite();}
//! Stop both threaded read and threaded write and if "wait" block until both threads are stop
void stop(bool wait = false) {stopThreadedRead(); stopThreadedWrite(); if (wait) while (write_thread.isRunning() || isRunning()) msleep(1);}
// Read from device to "read_to" maximum "max_size" bytes, return readed bytes count
virtual int read(void * read_to, int max_size) {piCout << "[PIIODevice] \"read\" not implemented!"; return -2;}
// Write to device "data" maximum "max_size" bytes, return written bytes count
virtual int write(const void * data, int max_size) {piCout << "[PIIODevice] \"write\" not implemented!"; return -2;}
//! Reimplement this function to read from your device
virtual int read(void * read_to, int max_size) {piCoutObj << "[PIIODevice] \"read\" not implemented!"; return -2;}
// Read from device maximum "max_size" bytes and return them as PIByteArray
//! Reimplement this function to write to your device
virtual int write(const void * data, int max_size) {piCoutObj << "[PIIODevice] \"write\" not implemented!"; return -2;}
//! Read from device maximum "max_size" bytes and return them as PIByteArray
PIByteArray read(int max_size) {buffer_in.resize(max_size); int ret = read(buffer_in.data(), max_size); if (ret < 0) return PIByteArray(); return buffer_in.resized(ret);}
//! Write to device "data"
int write(const PIByteArray & data) {return write(data.data(), data.size_s());}
//! Add task to threaded write queue and return task ID
ullong writeThreaded(const void * data, int max_size) {return writeThreaded(PIByteArray(data, uint(max_size)));}
//! Add task to threaded write queue and return task ID
ullong writeThreaded(const PIByteArray & data);
EVENT_HANDLER(bool, open) {if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;}
EVENT_HANDLER1(bool, open, const PIString &, _path) {path_ = _path; if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;}
EVENT_HANDLER1(bool, open, const DeviceMode &, _type) {mode_ = _type; if (!init_) init(); opened_ = openDevice(); if (opened_) opened(); return opened_;}
@@ -153,6 +195,12 @@ public:
//! \fn bool open(const PIString & path, const DeviceMode & mode)
//! \brief Open device with path "path" and mode "mode"
//! \fn bool close()
//! \brief Close device
//! \fn bool initialize()
//! \brief Initialize device
//! \}
//! \vhandlers
//! \{
@@ -174,19 +222,22 @@ public:
//! \brief Raise if read thread succesfull read some data
//! \fn void threadedWriteEvent(ullong id, int written_size)
//! \brief Raise if write thread succesfull write some data of queue item with id "id"
//! \brief Raise if write thread succesfull write some data of task with ID "id"
//! \}
protected:
// Function executed before first openDevice() or from constructor
//! Function executed before first \a openDevice() or from constructor
virtual bool init() {return true;}
// Functions to open and close device, return value will set to "opened_" variable
//! Reimplement to open device, return value will be set to "opened_" variable
virtual bool openDevice() = 0; // use path_, type_, opened_, init_ variables
//! Reimplement to close device, inverse return value will be set to "opened_" variable
virtual bool closeDevice() {return true;} // use path_, type_, opened_, init_ variables
// Function executed when thread read some data, default implementation execute external slot "ret_func_"
//! Function executed when thread read some data, default implementation execute external slot "ret_func_"
virtual bool threadedRead(uchar * readed, int size) {if (ret_func_ != 0) return ret_func_(ret_data_, readed, size); return true;}
void terminate();
@@ -194,7 +245,7 @@ protected:
PIString path_;
DeviceMode mode_;
ReadRetFunc ret_func_;
bool init_, opened_, thread_started_, reopen_enabled_;
bool init_, opened_, thread_started_, reopen_enabled_, raise_threaded_read_;
int reopen_timeout_;
void * ret_data_;

View File

@@ -64,13 +64,15 @@ void PIKbdListener::run() {
KEY_EVENT_RECORD ker = ir.Event.KeyEvent;
if (ker.bKeyDown) {
bool ctrl = ((ker.dwControlKeyState & LEFT_CTRL_PRESSED) || (ker.dwControlKeyState & RIGHT_CTRL_PRESSED));
bool shift = (ker.dwControlKeyState & SHIFT_PRESSED);
if (ker.dwControlKeyState & CAPSLOCK_ON) shift = !shift;
//cout << "key " << int(ker.wVirtualKeyCode) << endl;
switch (ker.wVirtualKeyCode) {
case 37: ret = 1; lc = (ctrl ? CtrlLeftArrow : LeftArrow); break;
case 38: ret = 1; lc = (ctrl ? CtrlUpArrow : UpArrow); break;
case 39: ret = 1; lc = (ctrl ? CtrlRightArrow : RightArrow); break;
case 40: ret = 1; lc = (ctrl ? CtrlDownArrow : DownArrow); break;
default: ret = 1; lc = ker.uChar.AsciiChar; break;
default: ret = 1; lc = (shift ? char(toupper(ker.uChar.AsciiChar)) : ker.uChar.AsciiChar); break;
}
if (lc == 0) return;
} else return;

View File

@@ -20,6 +20,443 @@
#include "pimath.h"
#ifndef PIP_MATH_J0
double j0(const double & v) {
double x = v;
double xsq;
double nn;
double pzero;
double qzero;
double p1;
double q1;
double result;
if (x < 0) x = -x;
if (x > 8.) {
double xsq_;
double p2;
double q2;
double p3;
double q3;
xsq_ = 64. / (x * x);
p2 = 0.0;
p2 = 2485.271928957404011288128951 + xsq_ * p2;
p2 = 153982.6532623911470917825993 + xsq_ * p2;
p2 = 2016135.283049983642487182349 + xsq_ * p2;
p2 = 8413041.456550439208464315611 + xsq_ * p2;
p2 = 12332384.76817638145232406055 + xsq_ * p2;
p2 = 5393485.083869438325262122897 + xsq_ * p2;
q2 = 1.0;
q2 = 2615.700736920839685159081813 + xsq_ * q2;
q2 = 156001.7276940030940592769933 + xsq_ * q2;
q2 = 2025066.801570134013891035236 + xsq_ * q2;
q2 = 8426449.050629797331554404810 + xsq_ * q2;
q2 = 12338310.22786324960844856182 + xsq_ * q2;
q2 = 5393485.083869438325560444960 + xsq_ * q2;
p3 = -0.0;
p3 = -4.887199395841261531199129300 +xsq_ * p3;
p3 = -226.2630641933704113967255053 +xsq_ * p3;
p3 = -2365.956170779108192723612816 +xsq_ * p3;
p3 = -8239.066313485606568803548860 +xsq_ * p3;
p3 = -10381.41698748464093880530341 +xsq_ * p3;
p3 = -3984.617357595222463506790588 +xsq_ * p3;
q3 = 1.0;
q3 = 408.7714673983499223402830260 + xsq_ * q3;
q3 = 15704.89191515395519392882766 + xsq_ * q3;
q3 = 156021.3206679291652539287109 + xsq_ * q3;
q3 = 533291.3634216897168722255057 + xsq_ * q3;
q3 = 666745.4239319826986004038103 + xsq_ * q3;
q3 = 255015.5108860942382983170882 + xsq_ * q3;
pzero = p2 / q2;
qzero = 8. * p3 / q3 / x;
nn = x- M_PI / 4.;
result = sqrt(2. / M_PI / x) * (pzero * cos(nn) - qzero * sin(nn));
return result;
}
xsq = x * x;
p1 = 26857.86856980014981415848441;
p1 = -40504123.71833132706360663322 + xsq * p1;
p1 = 25071582855.36881945555156435 + xsq * p1;
p1 = -8085222034853.793871199468171 + xsq * p1;
p1 = 1434354939140344.111664316553 + xsq * p1;
p1 = -136762035308817138.6865416609 + xsq * p1;
p1 = 6382059341072356562.289432465 + xsq * p1;
p1 = -117915762910761053603.8440800 + xsq * p1;
p1 = 493378725179413356181.6813446 + xsq * p1;
q1 = 1.;
q1 = 1363.063652328970604442810507 + xsq * q1;
q1 = 1114636.098462985378182402543 + xsq * q1;
q1 = 669998767.2982239671814028660 + xsq * q1;
q1 = 312304311494.1213172572469442 + xsq * q1;
q1 = 112775673967979.8507056031594 + xsq * q1;
q1 = 30246356167094626.98627330784 + xsq * q1;
q1 = 5428918384092285160.200195092 + xsq * q1;
q1 = 493378725179413356211.3278438 + xsq * q1;
return p1 / q1;
}
#endif
#ifndef PIP_MATH_J1
double j1(const double & v) {
double x = v;
double s;
double xsq;
double nn;
double pzero;
double qzero;
double p1;
double q1;
double result;
s = sign(x);
if (x < 0)
x = -x;
if (x > 8.) {
double xsq_;
double p2;
double q2;
double p3;
double q3;
xsq_ = 64.0 / (x * x);
p2 = -1611.616644324610116477412898;
p2 = -109824.0554345934672737413139 + xsq_ * p2;
p2 = -1523529.351181137383255105722 + xsq_ * p2;
p2 = -6603373.248364939109255245434 + xsq_ * p2;
p2 = -9942246.505077641195658377899 + xsq_ * p2;
p2 = -4435757.816794127857114720794 + xsq_ * p2;
q2 = 1.0;
q2 = -1455.009440190496182453565068 + xsq_ * q2;
q2 = -107263.8599110382011903063867 + xsq_ * q2;
q2 = -1511809.506634160881644546358 + xsq_ * q2;
q2 = -6585339.479723087072826915069 + xsq_ * q2;
q2 = -9934124.389934585658967556309 + xsq_ * q2;
q2 = -4435757.816794127856828016962 + xsq_ * q2;
p3 = 35.26513384663603218592175580;
p3 = 1706.375429020768002061283546 + xsq_ * p3;
p3 = 18494.26287322386679652009819 + xsq_ * p3;
p3 = 66178.83658127083517939992166 + xsq_ * p3;
p3 = 85145.16067533570196555001171 + xsq_ * p3;
p3 = 33220.91340985722351859704442 + xsq_ * p3;
q3 = 1.0;
q3 = 863.8367769604990967475517183 + xsq_ * q3;
q3 = 37890.22974577220264142952256 + xsq_ * q3;
q3 = 400294.4358226697511708610813 + xsq_ * q3;
q3 = 1419460.669603720892855755253 + xsq_ * q3;
q3 = 1819458.042243997298924553839 + xsq_ * q3;
q3 = 708712.8194102874357377502472 + xsq_ * q3;
pzero = p2 / q2;
qzero = 8 * p3 / q3 / x;
nn = x - 3 * M_PI / 4;
result = sqrt(2 / M_PI / x) * (pzero * cos(nn) - qzero * sin(nn));
if (s < 0)
result = -result;
return result;
}
xsq = sqr(x);
p1 = 2701.122710892323414856790990;
p1 = -4695753.530642995859767162166 + xsq * p1;
p1 = 3413234182.301700539091292655 + xsq * p1;
p1 = -1322983480332.126453125473247 + xsq * p1;
p1 = 290879526383477.5409737601689 + xsq * p1;
p1 = -35888175699101060.50743641413 + xsq * p1;
p1 = 2316433580634002297.931815435 + xsq * p1;
p1 = -66721065689249162980.20941484 + xsq * p1;
p1 = 581199354001606143928.050809 + xsq * p1;
q1 = 1.0;
q1 = 1606.931573481487801970916749 + xsq * q1;
q1 = 1501793.594998585505921097578 + xsq * q1;
q1 = 1013863514.358673989967045588 + xsq * q1;
q1 = 524371026216.7649715406728642 + xsq * q1;
q1 = 208166122130760.7351240184229 + xsq * q1;
q1 = 60920613989175217.46105196863 + xsq * q1;
q1 = 11857707121903209998.37113348 + xsq * q1;
q1 = 1162398708003212287858.529400 + xsq * q1;
result = s * x * p1 / q1;
return result;
}
#endif
#ifndef PIP_MATH_JN
double jn(const int & n, const double & v) {
double x = v;
double pkm2;
double pkm1;
double pk;
double xk;
double r;
double ans;
int k;
int sg;
double result;
if (n < 0) {
n = -n;
if (n % 2 == 0)
sg = 1;
else
sg = -1;
} else
sg = 1;
if (x < 0) {
if (n % 2 != 0)
sg = -sg;
x = -x;
}
if (n == 0) {
result = sg * j0(x);
return result;
}
if (n == 1) {
result = sg * j1(x);
return result;
}
if (n == 2) {
if (x == 0)
result = 0;
else
result = sg * (2.0 * j1(x) / x - j0(x));
return result;
}
if (x < 1E-16) {
result = 0;
return result;
}
k = 53;
pk = 2 * (n + k);
ans = pk;
xk = x * x;
do {
pk = pk - 2.0;
ans = pk - xk / ans;
k = k - 1;
} while (k != 0);
ans = x / ans;
pk = 1.0;
pkm1 = 1.0 / ans;
k = n - 1;
r = 2 * k;
do {
pkm2 = (pkm1 * r - pk * x) / x;
pk = pkm1;
pkm1 = pkm2;
r = r - 2.0;
k = k - 1;
} while (k != 0);
if (fabs(pk) > fabs(pkm1))
ans = j1(x) / pk;
else
ans = j0(x) / pkm1;
result = sg * ans;
return result;
}
#endif
#ifndef PIP_MATH_Y0
double y0(const double & v) {
double x = v;
double nn;
double xsq;
double pzero;
double qzero;
double p4;
double q4;
double result;
if (x > 8.) {
double xsq_;
double p2;
double q2;
double p3;
double q3;
xsq_ = 64.0 / (x * x);
p2 = 0.0;
p2 = 2485.271928957404011288128951 + xsq_ * p2;
p2 = 153982.6532623911470917825993 + xsq_ * p2;
p2 = 2016135.283049983642487182349 + xsq_ * p2;
p2 = 8413041.456550439208464315611 + xsq_ * p2;
p2 = 12332384.76817638145232406055 + xsq_ * p2;
p2 = 5393485.083869438325262122897 + xsq_ * p2;
q2 = 1.0;
q2 = 2615.700736920839685159081813 + xsq_ * q2;
q2 = 156001.7276940030940592769933 + xsq_ * q2;
q2 = 2025066.801570134013891035236 + xsq_ * q2;
q2 = 8426449.050629797331554404810 + xsq_ * q2;
q2 = 12338310.22786324960844856182 + xsq_ * q2;
q2 = 5393485.083869438325560444960 + xsq_ * q2;
p3 = -0.0;
p3 = -4.887199395841261531199129300 + xsq_ * p3;
p3 = -226.2630641933704113967255053 + xsq_ * p3;
p3 = -2365.956170779108192723612816 + xsq_ * p3;
p3 = -8239.066313485606568803548860 + xsq_ * p3;
p3 = -10381.41698748464093880530341 + xsq_ * p3;
p3 = -3984.617357595222463506790588 + xsq_ * p3;
q3 = 1.0;
q3 = 408.7714673983499223402830260 + xsq_ * q3;
q3 = 15704.89191515395519392882766 + xsq_ * q3;
q3 = 156021.3206679291652539287109 + xsq_ * q3;
q3 = 533291.3634216897168722255057 + xsq_ * q3;
q3 = 666745.4239319826986004038103 + xsq_ * q3;
q3 = 255015.5108860942382983170882 + xsq_ * q3;
pzero = p2 / q2;
qzero = 8 * p3 / q3 / x;
nn = x - M_PI / 4;
result = sqrt(2 / M_PI / x) * (pzero * sin(nn) + qzero * cos(nn));
return result;
}
xsq = sqr(x);
p4 = -41370.35497933148554125235152;
p4 = 59152134.65686889654273830069 + xsq * p4;
p4 = -34363712229.79040378171030138 + xsq * p4;
p4 = 10255208596863.94284509167421 + xsq * p4;
p4 = -1648605817185729.473122082537 + xsq * p4;
p4 = 137562431639934407.8571335453 + xsq * p4;
p4 = -5247065581112764941.297350814 + xsq * p4;
p4 = 65874732757195549259.99402049 + xsq * p4;
p4 = -27502866786291095837.01933175 + xsq * p4;
q4 = 1.0;
q4 = 1282.452772478993804176329391 + xsq * q4;
q4 = 1001702.641288906265666651753 + xsq * q4;
q4 = 579512264.0700729537480087915 + xsq * q4;
q4 = 261306575504.1081249568482092 + xsq * q4;
q4 = 91620380340751.85262489147968 + xsq * q4;
q4 = 23928830434997818.57439356652 + xsq * q4;
q4 = 4192417043410839973.904769661 + xsq * q4;
q4 = 372645883898616588198.9980 + xsq * q4;
result = p4 / q4 + 2 / M_PI * j0(x) * log(x);
return result;
}
#endif
#ifndef PIP_MATH_Y1
double y1(const double & v) {
double x = v;
double nn;
double xsq;
double pzero;
double qzero;
double p4;
double q4;
double result;
if (x > 8.) {
double xsq_;
double p2;
double q2;
double p3;
double q3;
xsq_ = 64.0 / (x * x);
p2 = -1611.616644324610116477412898;
p2 = -109824.0554345934672737413139 + xsq_ * p2;
p2 = -1523529.351181137383255105722 + xsq_ * p2;
p2 = -6603373.248364939109255245434 + xsq_ * p2;
p2 = -9942246.505077641195658377899 + xsq_ * p2;
p2 = -4435757.816794127857114720794 + xsq_ * p2;
q2 = 1.0;
q2 = -1455.009440190496182453565068 + xsq_ * q2;
q2 = -107263.8599110382011903063867 + xsq_ * q2;
q2 = -1511809.506634160881644546358 + xsq_ * q2;
q2 = -6585339.479723087072826915069 + xsq_ * q2;
q2 = -9934124.389934585658967556309 + xsq_ * q2;
q2 = -4435757.816794127856828016962 + xsq_ * q2;
p3 = 35.26513384663603218592175580;
p3 = 1706.375429020768002061283546 + xsq_ * p3;
p3 = 18494.26287322386679652009819 + xsq_ * p3;
p3 = 66178.83658127083517939992166 + xsq_ * p3;
p3 = 85145.16067533570196555001171 + xsq_ * p3;
p3 = 33220.91340985722351859704442 + xsq_ * p3;
q3 = 1.0;
q3 = 863.8367769604990967475517183 + xsq_ * q3;
q3 = 37890.22974577220264142952256 + xsq_ * q3;
q3 = 400294.4358226697511708610813 + xsq_ * q3;
q3 = 1419460.669603720892855755253 + xsq_ * q3;
q3 = 1819458.042243997298924553839 + xsq_ * q3;
q3 = 708712.8194102874357377502472 + xsq_ * q3;
pzero = p2 / q2;
qzero = 8 * p3 / q3 / x;
nn = x - 3 * M_PI / 4;
result = sqrt(2 / M_PI / x) * (pzero * sin(nn) + qzero * cos(nn));
return result;
}
xsq = sqr(x);
p4 = -2108847.540133123652824139923;
p4 = 3639488548.124002058278999428 + xsq * p4;
p4 = -2580681702194.450950541426399 + xsq * p4;
p4 = 956993023992168.3481121552788 + xsq * p4;
p4 = -196588746272214065.8820322248 + xsq * p4;
p4 = 21931073399177975921.11427556 + xsq * p4;
p4 = -1212297555414509577913.561535 + xsq * p4;
p4 = 26554738314348543268942.48968 + xsq * p4;
p4 = -99637534243069222259967.44354 + xsq * p4;
q4 = 1.0;
q4 = 1612.361029677000859332072312 + xsq * q4;
q4 = 1563282.754899580604737366452 + xsq * q4;
q4 = 1128686837.169442121732366891 + xsq * q4;
q4 = 646534088126.5275571961681500 + xsq * q4;
q4 = 297663212564727.6729292742282 + xsq * q4;
q4 = 108225825940881955.2553850180 + xsq * q4;
q4 = 29549879358971486742.90758119 + xsq * q4;
q4 = 5435310377188854170800.653097 + xsq * q4;
q4 = 508206736694124324531442.4152 + xsq * q4;
result = x * p4 / q4 + 2 / M_PI * (j1(x) * log(x) - 1 / x);
return result;
}
#endif
#ifndef PIP_MATH_YN
double yn(const int & n, const double & v) {
int i;
double x = v;
double a;
double b;
double tmp;
double s;
double result;
s = 1;
if (n < 0) {
n = -n;
if (n % 2 != 0)
s = -1;
}
if (n == 0) {
result = y0(x);
return result;
}
if (n == 1) {
result = s * y1(x);
return result;
}
a = y0(x);
b = y1(x);
for (i = 1; i <= n - 1; i++) {
tmp = b;
b = 2 * i / x * b - a;
a = tmp;
}
result = s * b;
return result;
}
#endif
double randomn(double dv, double sv) {
static bool agen = false;
double s = 2., v0 = 0., v1 = 0.;
if (agen) {
agen = false;
v1 = v1 * sqrt(-2 * log(s) / s);
return v1 * sv + dv;
}
while (s > 1. || s == 0.) {
v0 = randomd();
v1 = randomd();
s = v0*v0 + v1*v1;
}
v0 = v0 * sqrt(-2 * log(s) / s);
return v0 * sv + dv;
}
const char Solver::methods_desc[] = "b{Methods:}\
\n -1 - Global settings\
\n 01 - Eyler 1\
@@ -70,7 +507,7 @@ void Solver::fromTF(const TransferFunction & TF) {
if (TF.vector_An.size() >= TF.vector_Bm.size())
size = TF.vector_An.size()-1;
else {
cout << "Solver error: {A} should be greater than {B}" << endl;
piCout << "Solver error: {A} should be greater than {B}";
return;
}
if (size == 0) return;
@@ -327,7 +764,7 @@ void PIFFT::fftc1d(const PIVector<complexd> &a, uint n) {
void PIFFT::fftc1r(const PIVector<double> & a, uint n) {
uint i;
if( n%2==0 ) {
if( n%2==0) {
PIVector<double> buf;
uint n2 = n/2;
//buf.resize(n);
@@ -455,14 +892,14 @@ void PIFFT::ftbase_ftbasegenerateplanrec(
int ftbase_fftcodeletplan = 2;
int ftbase_fftrealcooleytukeyplan = 5;
int ftbase_fftemptyplan = 6;
if( *plansize+ftbase_ftbaseplanentrysize>(*planarraysize) ) {
if( *plansize+ftbase_ftbaseplanentrysize>(*planarraysize)) {
curplan.plan.resize(8*(*planarraysize));
*planarraysize = 8*(*planarraysize);
}
entryoffset = *plansize;
esize = ftbase_ftbaseplanentrysize;
*plansize = *plansize+esize;
if( n==1 ) {
if( n==1) {
curplan.plan[entryoffset+0] = esize;
curplan.plan[entryoffset+1] = -1;
curplan.plan[entryoffset+2] = -1;
@@ -474,12 +911,12 @@ void PIFFT::ftbase_ftbasegenerateplanrec(
return;
}
ftbasefactorize(n, &n1, &n2);
if( n1!=1 ) {
if( n1!=1) {
*tmpmemsize = piMax<int>(*tmpmemsize, 2*n1*n2);
curplan.plan[entryoffset+0] = esize;
curplan.plan[entryoffset+1] = n1;
curplan.plan[entryoffset+2] = n2;
if( tasktype==ftbase_ftbasecffttask )
if( tasktype==ftbase_ftbasecffttask)
curplan.plan[entryoffset+3] = ftbase_fftcooleytukeyplan;
else
curplan.plan[entryoffset+3] = ftbase_fftrealcooleytukeyplan;
@@ -501,9 +938,9 @@ void PIFFT::ftbase_ftbasegenerateplanrec(
curplan.plan[entryoffset+5] = -1;
curplan.plan[entryoffset+6] = -1;
curplan.plan[entryoffset+7] = *precomputedsize;
if( n==3 )
if( n==3)
*precomputedsize = *precomputedsize+2;
if( n==5 )
if( n==5)
*precomputedsize = *precomputedsize+5;
return;
} else {
@@ -547,22 +984,22 @@ void PIFFT::ftbase_ftbaseprecomputeplanrec(ftplan* plan,
int ftbase_fhtcooleytukeyplan = 3;
int ftbase_fhtcodeletplan = 4;
int ftbase_fftrealcooleytukeyplan = 5;
if( (curplan.plan[entryoffset+3]==ftbase_fftcooleytukeyplan||curplan.plan[entryoffset+3]==ftbase_fftrealcooleytukeyplan)||curplan.plan[entryoffset+3]==ftbase_fhtcooleytukeyplan ) {
if( (curplan.plan[entryoffset+3]==ftbase_fftcooleytukeyplan||curplan.plan[entryoffset+3]==ftbase_fftrealcooleytukeyplan)||curplan.plan[entryoffset+3]==ftbase_fhtcooleytukeyplan) {
ftbase_ftbaseprecomputeplanrec(plan, curplan.plan[entryoffset+5], stackptr);
ftbase_ftbaseprecomputeplanrec(plan, curplan.plan[entryoffset+6], stackptr);
return;
}
if( curplan.plan[entryoffset+3]==ftbase_fftcodeletplan||curplan.plan[entryoffset+3]==ftbase_fhtcodeletplan ) {
if( curplan.plan[entryoffset+3]==ftbase_fftcodeletplan||curplan.plan[entryoffset+3]==ftbase_fhtcodeletplan) {
n1 = curplan.plan[entryoffset+1];
n2 = curplan.plan[entryoffset+2];
n = n1*n2;
if( n==3 ) {
if( n==3) {
offs = curplan.plan[entryoffset+7];
curplan.precomputed[offs+0] = cos(2*M_PI/3)-1;
curplan.precomputed[offs+1] = sin(2*M_PI/3);
return;
}
if( n==5 ) {
if( n==5) {
offs = curplan.plan[entryoffset+7];
v = 2*M_PI/5;
curplan.precomputed[offs+0] = (cos(v)+cos(2*v))/2-1;
@@ -573,7 +1010,7 @@ void PIFFT::ftbase_ftbaseprecomputeplanrec(ftplan* plan,
return;
}
}
if( curplan.plan[entryoffset+3]==ftbase_fftbluesteinplan ) {
if( curplan.plan[entryoffset+3]==ftbase_fftbluesteinplan) {
ftbase_ftbaseprecomputeplanrec(plan, curplan.plan[entryoffset+5], stackptr);
n = curplan.plan[entryoffset+1];
m = curplan.plan[entryoffset+4];
@@ -587,7 +1024,7 @@ void PIFFT::ftbase_ftbaseprecomputeplanrec(ftplan* plan,
curplan.precomputed[offs+2*i+1] = by;
curplan.precomputed[offs+2*m+2*i+0] = bx;
curplan.precomputed[offs+2*m+2*i+1] = by;
if( i>0 ) {
if( i>0) {
curplan.precomputed[offs+2*(m-i)+0] = bx;
curplan.precomputed[offs+2*(m-i)+1] = by;
}
@@ -601,29 +1038,29 @@ void PIFFT::ftbase_ftbaseprecomputeplanrec(ftplan* plan,
void PIFFT::ftbasefactorize(int n, int* n1, int* n2) {
*n1 = *n2 = 0;
int ftbase_ftbasecodeletrecommended = 5;
if( (*n1)*(*n2)!=n ) {
if( (*n1)*(*n2)!=n) {
for(int j=ftbase_ftbasecodeletrecommended; j>=2; j--) {
if( n%j==0 ) {
if( n%j==0) {
*n1 = j;
*n2 = n/j;
break;
}
}
}
if( (*n1)*(*n2)!=n ) {
if( (*n1)*(*n2)!=n) {
for(int j=ftbase_ftbasecodeletrecommended+1; j<=n-1; j++) {
if( n%j==0 ) {
if( n%j==0) {
*n1 = j;
*n2 = n/j;
break;
}
}
}
if( (*n1)*(*n2)!=n ) {
if( (*n1)*(*n2)!=n) {
*n1 = 1;
*n2 = n;
}
if( (*n2)==1 && (*n1)!=1 ) {
if( (*n2)==1 && (*n1)!=1) {
*n2 = *n1;
*n1 = 1;
}
@@ -637,15 +1074,15 @@ Is number smooth?
Copyright 01.05.2009 by Bochkanov Sergey
*************************************************************************/
void PIFFT::ftbase_ftbasefindsmoothrec(int n, int seed, int leastfactor, int* best) {
if( seed>=n ) {
if( seed>=n) {
*best = piMin<int>(*best, seed);
return;
}
if( leastfactor<=2 )
if( leastfactor<=2)
ftbase_ftbasefindsmoothrec(n, seed*2, 2, best);
if( leastfactor<=3 )
if( leastfactor<=3)
ftbase_ftbasefindsmoothrec(n, seed*3, 3, best);
if( leastfactor<=5 )
if( leastfactor<=5)
ftbase_ftbasefindsmoothrec(n, seed*5, 5, best);
}
@@ -670,9 +1107,9 @@ void PIFFT::ftbase_internalreallintranspose(PIVector<double>* a, int m, int n, i
void PIFFT::ftbase_fftirltrec(PIVector<double>* a, int astart, int astride, PIVector<double>* b, int bstart, int bstride, int m, int n) {
int idx1, idx2;
int m1, n1;
if( m==0||n==0 )
if( m==0||n==0)
return;
if( piMax<int>(m, n)<=8 ) {
if( piMax<int>(m, n)<=8) {
for(int i=0; i<=m-1; i++) {
idx1 = bstart+i;
idx2 = astart+i*astride;
@@ -684,15 +1121,15 @@ void PIFFT::ftbase_fftirltrec(PIVector<double>* a, int astart, int astride, PIVe
}
return;
}
if( n>m ) {
if( n>m) {
n1 = n/2;
if( n-n1>=8&&n1%8!=0 )
if( n-n1>=8&&n1%8!=0)
n1 = n1+(8-n1%8);
ftbase_fftirltrec(a, astart, astride, b, bstart, bstride, m, n1);
ftbase_fftirltrec(a, astart+n1, astride, b, bstart+n1*bstride, bstride, m, n-n1);
} else {
m1 = m/2;
if( m-m1>=8&&m1%8!=0 )
if( m-m1>=8&&m1%8!=0)
m1 = m1+(8-m1%8);
ftbase_fftirltrec(a, astart, astride, b, bstart, bstride, m1, n);
ftbase_fftirltrec(a, astart+m1*astride, astride, b, bstart+m1, bstride, m-m1, n);
@@ -709,9 +1146,9 @@ void PIFFT::ftbase_internalcomplexlintranspose(PIVector<double>* a, int m, int n
void PIFFT::ftbase_ffticltrec(PIVector<double>* a, int astart, int astride, PIVector<double>* b, int bstart, int bstride, int m, int n) {
int idx1, idx2, m2, m1, n1;
if( m==0||n==0 )
if( m==0||n==0)
return;
if( piMax<int>(m, n)<=8 ) {
if( piMax<int>(m, n)<=8) {
m2 = 2*bstride;
for(int i=0; i<=m-1; i++) {
idx1 = bstart+2*i;
@@ -725,15 +1162,15 @@ void PIFFT::ftbase_ffticltrec(PIVector<double>* a, int astart, int astride, PIVe
}
return;
}
if( n>m ) {
if( n>m) {
n1 = n/2;
if( n-n1>=8&&n1%8!=0 )
if( n-n1>=8&&n1%8!=0)
n1 = n1+(8-n1%8);
ftbase_ffticltrec(a, astart, astride, b, bstart, bstride, m, n1);
ftbase_ffticltrec(a, astart+2*n1, astride, b, bstart+2*n1*bstride, bstride, m, n-n1);
} else {
m1 = m/2;
if( m-m1>=8&&m1%8!=0 )
if( m-m1>=8&&m1%8!=0)
m1 = m1+(8-m1%8);
ftbase_ffticltrec(a, astart, astride, b, bstart, bstride, m1, n);
ftbase_ffticltrec(a, astart+2*m1*astride, astride, b, bstart+2*m1, bstride, m-m1, n);
@@ -775,9 +1212,9 @@ void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan,
int ftbase_fftemptyplan = 6;
PIVector<double> & tmpb(curplan.tmpbuf);
if( curplan.plan[entryoffset+3]==ftbase_fftemptyplan )
if( curplan.plan[entryoffset+3]==ftbase_fftemptyplan)
return;
if( curplan.plan[entryoffset+3]==ftbase_fftcooleytukeyplan ) {
if( curplan.plan[entryoffset+3]==ftbase_fftcooleytukeyplan) {
n1 = curplan.plan[entryoffset+1];
n2 = curplan.plan[entryoffset+2];
ftbase_internalcomplexlintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
@@ -790,7 +1227,7 @@ void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan,
ftbase_internalcomplexlintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
return;
}
if( curplan.plan[entryoffset+3]==ftbase_fftrealcooleytukeyplan ) {
if( curplan.plan[entryoffset+3]==ftbase_fftrealcooleytukeyplan) {
n1 = curplan.plan[entryoffset+1];
n2 = curplan.plan[entryoffset+2];
ftbase_internalcomplexlintranspose(a, n2, n1, aoffset, &(curplan.tmpbuf));
@@ -817,7 +1254,7 @@ void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan,
}
for (int i=0; i<2*n2*2; i++) (*a)[offs+i] = tmpb[i];
}
if( n1%2!=0 )
if( n1%2!=0)
ftbaseexecuteplanrec(a, aoffset+(n1-1)*n2*2, plan, curplan.plan[entryoffset+6], stackptr);
ftbase_ffttwcalc(a, aoffset, n2, n1);
ftbase_internalcomplexlintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
@@ -826,7 +1263,7 @@ void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan,
ftbase_internalcomplexlintranspose(a, n2, n1, aoffset, &(curplan.tmpbuf));
return;
}
if( curplan.plan[entryoffset+3]==ftbase_fhtcooleytukeyplan ) {
if( curplan.plan[entryoffset+3]==ftbase_fhtcooleytukeyplan) {
n1 = curplan.plan[entryoffset+1];
n2 = curplan.plan[entryoffset+2];
n = n1*n2;
@@ -846,7 +1283,7 @@ void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan,
ftbase_ffttwcalc(&(curplan.tmpbuf), 0, n1, n2);
for(int j=0; j<=n1-1; j++)
(*a)[aoffset+j] = tmpb[2*j+0]+tmpb[2*j+1];
if( n2%2==0 ) {
if( n2%2==0) {
offs = 2*(n2/2)*n1;
offsa = aoffset+n2/2*n1;
for(int j=0; j<=n1-1; j++)
@@ -868,11 +1305,11 @@ void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan,
ftbase_internalreallintranspose(a, n1, n2, aoffset, &(curplan.tmpbuf));
return;
}
if( curplan.plan[entryoffset+3]==ftbase_fftcodeletplan ) {
if( curplan.plan[entryoffset+3]==ftbase_fftcodeletplan) {
n1 = curplan.plan[entryoffset+1];
n2 = curplan.plan[entryoffset+2];
n = n1*n2;
if( n==2 ) {
if( n==2) {
a0x = (*a)[aoffset+0];
a0y = (*a)[aoffset+1];
a1x = (*a)[aoffset+2];
@@ -887,7 +1324,7 @@ void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan,
(*a)[aoffset+3] = v3;
return;
}
if( n==3 ) {
if( n==3) {
offs = curplan.plan[entryoffset+7];
c1 = curplan.precomputed[offs+0];
c2 = curplan.precomputed[offs+1];
@@ -919,7 +1356,7 @@ void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan,
(*a)[aoffset+5] = a2y;
return;
}
if( n==4 ) {
if( n==4) {
a0x = (*a)[aoffset+0];
a0y = (*a)[aoffset+1];
a1x = (*a)[aoffset+2];
@@ -946,7 +1383,7 @@ void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan,
(*a)[aoffset+7] = m2y-m3y;
return;
}
if( n==5 ) {
if( n==5) {
offs = curplan.plan[entryoffset+7];
c1 = curplan.precomputed[offs+0];
c2 = curplan.precomputed[offs+1];
@@ -996,18 +1433,18 @@ void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan,
return;
}
}
if( curplan.plan[entryoffset+3]==ftbase_fhtcodeletplan ) {
if( curplan.plan[entryoffset+3]==ftbase_fhtcodeletplan) {
n1 = curplan.plan[entryoffset+1];
n2 = curplan.plan[entryoffset+2];
n = n1*n2;
if( n==2 ) {
if( n==2) {
a0x = (*a)[aoffset+0];
a1x = (*a)[aoffset+1];
(*a)[aoffset+0] = a0x+a1x;
(*a)[aoffset+1] = a0x-a1x;
return;
}
if( n==3 ) {
if( n==3) {
offs = curplan.plan[entryoffset+7];
c1 = curplan.precomputed[offs+0];
c2 = curplan.precomputed[offs+1];
@@ -1024,7 +1461,7 @@ void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan,
(*a)[aoffset+2] = s1x+m2y;
return;
}
if( n==4 ) {
if( n==4) {
a0x = (*a)[aoffset+0];
a1x = (*a)[aoffset+1];
a2x = (*a)[aoffset+2];
@@ -1039,7 +1476,7 @@ void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan,
(*a)[aoffset+3] = m2x+m3y;
return;
}
if( n==5 ) {
if( n==5) {
offs = curplan.plan[entryoffset+7];
c1 = curplan.precomputed[offs+0];
c2 = curplan.precomputed[offs+1];
@@ -1067,7 +1504,7 @@ void PIFFT::ftbaseexecuteplanrec(PIVector<double>* a, int aoffset, ftplan* plan,
return;
}
}
if( curplan.plan[entryoffset+3]==ftbase_fftbluesteinplan ) {
if( curplan.plan[entryoffset+3]==ftbase_fftbluesteinplan) {
n = curplan.plan[entryoffset+1];
m = curplan.plan[entryoffset+4];
offs = curplan.plan[entryoffset+7];
@@ -1148,8 +1585,8 @@ void PIFFT::ftbase_ffttwcalc(PIVector<double> * a, int aoffset, int n1, int n2)
tmpy = x*twy+y*twxm1;
(*a)[offs+0] = x+tmpx;
(*a)[offs+1] = y+tmpy;
if( j<n1-1 ) {
if( j%ftbase_ftbaseupdatetw==0 ) {
if( j<n1-1) {
if( j%ftbase_ftbaseupdatetw==0) {
v = -2*M_PI*i*(j+1)/n;
twxm1 = -2*sqr(sin(0.5*v));
twy = sin(v);
@@ -1162,8 +1599,8 @@ void PIFFT::ftbase_ffttwcalc(PIVector<double> * a, int aoffset, int n1, int n2)
}
}
if( i<n2-1 ) {
if( j%ftbase_ftbaseupdatetw==0 ) {
if( i<n2-1) {
if( j%ftbase_ftbaseupdatetw==0) {
v = -2*M_PI*(i+1)/n;
twrowxm1 = -2*sqr(sin(0.5*v));
twrowy = sin(v);
@@ -1176,52 +1613,3 @@ void PIFFT::ftbase_ffttwcalc(PIVector<double> * a, int aoffset, int n1, int n2)
}
}
}
PIStatistic::PIStatistic() {
mean = 0.;
variance = 0.;
skewness = 0.;
kurtosis = 0.;
}
bool PIStatistic::calculate(const PIVector<double> & val) {
double v = 0., v1 = 0., v2 = 0., stddev = 0.;
int i, n = val.size();
if (n < 2)
return false;
/*
* Mean
*/
for (i = 0; i < n; i++)
mean += val[i];
mean /= n;
/*
* Variance (using corrected two-pass algorithm)
*/
for (i = 0; i < n; i++)
v1 += sqr(val[i] - mean);
for (i = 0; i < n; i++)
v2 += val[i] - mean;
v2 = sqr(v2) / n;
variance = (v1 - v2) / (n - 1);
if(variance < 0)
variance = 0.;
stddev = sqrt(variance);
/*
* Skewness and kurtosis
*/
if (stddev != 0) {
for (i = 0; i < n; i++) {
v = (val[i] - mean) / stddev;
v2 = sqr(v);
skewness = skewness + v2 * v;
kurtosis = kurtosis + sqr(v2);
}
skewness /= n;
kurtosis = kurtosis / n - 3.;
}
return true;
}

195
pimath.h
View File

@@ -35,6 +35,18 @@
#ifndef M_LN10
# define M_LN10 2.30258509299404568402
#endif
#ifndef M_SQRT2
# define M_SQRT2 1.41421356237309514547
#endif
#ifndef M_SQRT3
# define M_SQRT3 1.73205080756887719318
#endif
#ifndef M_1_SQRT2
# define M_1_SQRT2 0.70710678118654746172
#endif
#ifndef M_1_SQRT3
# define M_1_SQRT3 0.57735026918962584208
#endif
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
@@ -53,6 +65,12 @@
#ifndef M_PI_180
# define M_PI_180 1.74532925199432957692e-2
#endif
#ifndef M_E
# define M_E 2.7182818284590452353602874713527
#endif
#ifndef M_LIGHT_SPEED
# define M_LIGHT_SPEED 2.99792458e+8
#endif
using std::complex;
@@ -70,7 +88,12 @@ const complexd complexd_1(1.);
const double deg2rad = M_PI_180;
const double rad2deg = M_180_PI;
inline int sign(const float & x) {return (x < 0.) ? -1 : (x > 0. ? 1 : 0);}
inline int sign(const double & x) {return (x < 0.) ? -1 : (x > 0. ? 1 : 0);}
inline complexd sign(const complexd & x) {return complexd(sign(x.real()), sign(x.imag()));}
inline int pow2(const int p) {return 1 << p;}
inline double sqr(const int v) {return v * v;}
inline double sqr(const float & v) {return v * v;}
inline double sqr(const double & v) {return v * v;}
inline double sinc(const double & v) {if (v == 0.) return 1.; double t = M_PI * v; return sin(t) / t;}
inline complexd round(const complexd & c) {return complexd(piRound<double>(c.real()), piRound<double>(c.imag()));}
@@ -79,23 +102,42 @@ inline complexd ceil(const complexd & c) {return complexd(ceil(c.real()), ceil(c
inline complexd atanc(const complexd & c) {return -complexd(-0.5, 1.) * log((complexd_1 + complexd_i * c) / (complexd_1 - complexd_i * c));}
inline complexd asinc(const complexd & c) {return -complexd_i * log(complexd_i * c + sqrt(complexd_1 - c * c));}
inline complexd acosc(const complexd & c) {return -complexd_i * log(c + complexd_i * sqrt(complexd_1 - c * c));}
#if CC_GCC_VERSION <= 0x025F
#ifdef CC_GCC
# if CC_GCC_VERSION <= 0x025F
inline complexd tan(const complexd & c) {return sin(c) / cos(c);}
inline complexd tanh(const complexd & c) {return sinh(c) / cosh(c);}
inline complexd log2(const complexd & c) {return log(c) / M_LN2;}
inline complexd log10(const complexd & c) {return log(c) / M_LN10;}
inline double j0(const double & v) {return v;}
inline double j1(const double & v) {v;}
inline double jn(const int & n, const double & v) {return v;}
inline double y0(const double & v) {return v;}
inline double y1(const double & v) {return v;}
inline double yn(const int & n, const double & v) {return v;}
# endif
#endif
#ifndef PIP_MATH_J0
__attribute__ ((unused)) static double j0(const double & v);
#endif
#ifndef PIP_MATH_J1
__attribute__ ((unused)) static double j1(const double & v);
#endif
#ifndef PIP_MATH_JN
__attribute__ ((unused)) static double jn(const int & n, const double & v);
#endif
#ifndef PIP_MATH_Y0
__attribute__ ((unused)) static double y0(const double & v);
#endif
#ifndef PIP_MATH_Y1
__attribute__ ((unused)) static double y1(const double & v);
#endif
#ifndef PIP_MATH_YN
__attribute__ ((unused)) static double yn(const int & n, const double & v);
#endif
inline double toDb(double val) {return 10. * log10(val);}
inline double fromDb(double val) {return pow(10., val / 10.);}
inline double toRad(double deg) {return deg * M_PI_180;}
inline double toDeg(double rad) {return rad * M_180_PI;}
// [-1 ; 1]
inline double randomd() {return (double)random() / RAND_MAX * 2. - 1.;}
// [-1 ; 1] normal
double randomn(double dv = 0., double sv = 1.);
inline PIVector<double> abs(const PIVector<complexd> & v) {
PIVector<double> result;
result.resize(v.size());
@@ -152,7 +194,7 @@ public:
Type at(uint index) const {return c[index];}
Type & operator [](uint index) {return c[index];}
Type operator [](uint index) const {return c[index];}
void operator =(const _CVector & v) {c = v.c;}
_CVector & operator =(const _CVector & v) {c = v.c; return *this;}
bool operator ==(const _CVector & v) const {PIMV_FOR(i, 0) if (c[i] != v[i]) return false; return true;}
bool operator !=(const _CVector & v) const {return !(*this == c);}
void operator +=(const _CVector & v) {PIMV_FOR(i, 0) c[i] += v[i];}
@@ -166,6 +208,7 @@ public:
_CVector operator -(const _CVector & v) const {_CVector tv = _CVector(*this); PIMV_FOR(i, 0) tv[i] -= v[i]; return tv;}
_CVector operator *(const Type & v) const {_CVector tv = _CVector(*this); PIMV_FOR(i, 0) tv[i] *= v; return tv;}
_CVector operator /(const Type & v) const {_CVector tv = _CVector(*this); PIMV_FOR(i, 0) tv[i] /= v; return tv;}
_CVector operator /(const _CVector & v) const {_CVector tv = _CVector(*this); PIMV_FOR(i, 0) tv[i] /= v[i]; return tv;}
_CVector operator *(const _CVector & v) const {if (Size > 3) return _CVector(); _CVector tv; tv.fill(Type(1)); tv[0] = c[1]*v[2] - v[1]*c[2]; tv[1] = v[0]*c[2] - c[0]*v[2]; tv[2] = c[0]*v[1] - v[0]*c[1]; return tv;}
Type operator ^(const _CVector & v) const {Type tv(0); PIMV_FOR(i, 0) tv += c[i] * v[i]; return tv;}
@@ -187,7 +230,13 @@ private:
template<uint Size, typename Type>
inline std::ostream & operator <<(std::ostream & s, const PIMathVectorT<Size, Type> & v) {s << '{'; PIMV_FOR(i, 0) {s << v[i]; if (i < Size - 1) s << ", ";} s << '}'; return s;}
template<uint Size, typename Type>
inline PICout operator <<(PICout s, const PIMathVectorT<Size, Type> & v) {s << '{'; PIMV_FOR(i, 0) {s << v[i]; if (i < Size - 1) s << ", ";} s << '}'; return s;}
template<uint Size, typename Type>
inline bool operator ||(const PIMathVectorT<Size, Type> & f, const PIMathVectorT<Size, Type> & s) {return (f * s).isNull();}
template<uint Size, typename Type>
inline PIMathVectorT<Size, Type> sqrt(const PIMathVectorT<Size, Type> & v) {PIMathVectorT<Size, Type> ret; PIMV_FOR(i, 0) {ret[i] = sqrt(v[i]);} return ret;}
template<uint Size, typename Type>
inline PIMathVectorT<Size, Type> sqr(const PIMathVectorT<Size, Type> & v) {PIMathVectorT<Size, Type> ret; PIMV_FOR(i, 0) {ret[i] = sqr(v[i]);} return ret;}
//template<uint Size0, typename Type0 = double, uint Size1 = Size0, typename Type1 = Type0> /// vector {Size0, Type0} to vector {Size1, Type1}
//inline operator PIMathVectorT<Size1, Type1>(const PIMathVectorT<Size0, Type0> & v) {PIMathVectorT<Size1, Type1> tv; uint sz = piMin<uint>(Size0, Size1); for (uint i = 0; i < sz; ++i) tv[i] = v[i]; return tv;}
@@ -220,6 +269,10 @@ public:
PIMathMatrixT(const PIVector<Type> & val) {resize(Cols, Rows); int i = 0; PIMM_FOR_I_WB(c, r) m[c][r] = val[i++];}
static _CMatrix identity() {_CMatrix tm = _CMatrix(); PIMM_FOR_WB(c, r) tm.m[c][r] = (c == r ? Type(1) : Type(0)); return tm;}
static _CMatrix rotation(double angle) {return _CMatrix();}
static _CMatrix rotationX(double angle) {return _CMatrix();}
static _CMatrix rotationY(double angle) {return _CMatrix();}
static _CMatrix rotationZ(double angle) {return _CMatrix();}
uint cols() const {return Cols;}
uint rows() const {return Rows;}
@@ -360,8 +413,16 @@ private:
};
template<> inline PIMathMatrixT<2u, 2u> PIMathMatrixT<2u, 2u>::rotation(double angle) {double c = cos(angle), s = sin(angle); PIMathMatrixT<2u, 2u> tm; tm[0][0] = tm[1][1] = c; tm[0][1] = -s; tm[1][0] = s; return tm;}
template<> inline PIMathMatrixT<3u, 3u> PIMathMatrixT<3u, 3u>::rotationX(double angle) {double c = cos(angle), s = sin(angle); PIMathMatrixT<3u, 3u> tm; tm[0][0] = 1.; tm[1][1] = tm[2][2] = c; tm[2][1] = -s; tm[1][2] = s; return tm;}
template<> inline PIMathMatrixT<3u, 3u> PIMathMatrixT<3u, 3u>::rotationY(double angle) {double c = cos(angle), s = sin(angle); PIMathMatrixT<3u, 3u> tm; tm[1][1] = 1.; tm[0][0] = tm[2][2] = c; tm[2][0] = s; tm[0][2] = -s; return tm;}
template<> inline PIMathMatrixT<3u, 3u> PIMathMatrixT<3u, 3u>::rotationZ(double angle) {double c = cos(angle), s = sin(angle); PIMathMatrixT<3u, 3u> tm; tm[2][2] = 1.; tm[0][0] = tm[1][1] = c; tm[1][0] = -s; tm[0][1] = s; return tm;}
template<uint Cols, uint Rows, typename Type>
inline std::ostream & operator <<(std::ostream & s, const PIMathMatrixT<Cols, Rows, Type> & m) {s << '{'; PIMM_FOR_I(c, r) s << m[c][r]; if (c < Cols - 1 || r < Rows - 1) s << ", ";} if (r < Rows - 1) s << endl << ' ';} s << '}'; return s;}
template<uint Cols, uint Rows, typename Type>
inline PICout operator <<(PICout s, const PIMathMatrixT<Cols, Rows, Type> & m) {s << '{'; PIMM_FOR_I(c, r) s << m[c][r]; if (c < Cols - 1 || r < Rows - 1) s << ", ";} if (r < Rows - 1) s << NewLine << ' ';} s << '}'; return s;}
/// Multiply matrices {CR x Rows0} on {Cols1 x CR}, result is {Cols1 x Rows0}
template<uint CR, uint Rows0, uint Cols1, typename Type>
@@ -487,6 +548,8 @@ private:
template<typename Type>
inline std::ostream & operator <<(std::ostream & s, const PIMathVector<Type> & v) {s << '{'; for (uint i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << '}'; return s;}
template<typename Type>
inline PICout operator <<(PICout s, const PIMathVector<Type> & v) {s << '{'; for (uint i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << '}'; return s;}
typedef PIMathVector<int> PIMathVectori;
typedef PIMathVector<double> PIMathVectord;
@@ -658,6 +721,8 @@ private:
template<typename Type>
inline std::ostream & operator <<(std::ostream & s, const PIMathMatrix<Type> & m) {s << '{'; for (uint r = 0; r < m.rows(); ++r) { for (uint c = 0; c < m.cols(); ++c) { s << m[c][r]; if (c < m.cols() - 1 || r < m.rows() - 1) s << ", ";} if (r < m.rows() - 1) s << endl << ' ';} s << '}'; return s;}
template<typename Type>
inline PICout operator <<(PICout s, const PIMathMatrix<Type> & m) {s << '{'; for (uint r = 0; r < m.rows(); ++r) { for (uint c = 0; c < m.cols(); ++c) { s << m[c][r]; if (c < m.cols() - 1 || r < m.rows() - 1) s << ", ";} if (r < m.rows() - 1) s << NewLine << ' ';} s << '}'; return s;}
/// Multiply matrices {CR x Rows0} on {Cols1 x CR}, result is {Cols1 x Rows0}
template<typename Type>
@@ -829,14 +894,116 @@ private:
};
template <typename T>
class PIP_EXPORT PIStatistic {
public:
PIStatistic();
bool calculate(const PIVector<double> &val);
double mean;
double variance;
double skewness;
double kurtosis;
PIStatistic() {
mean = T();
variance = T();
skewness = T();
kurtosis = T();
}
bool calculate(const PIVector<T> &val) {
T v = T(), v1 = T(), v2 = T(), stddev = T();
int i, n = val.size();
mean = T();
variance = T();
skewness = T();
kurtosis = T();
if (n < 2)
return false;
/*
* Mean
*/
for (i = 0; i < n; i++)
mean += val[i];
mean /= n;
/*
* Variance (using corrected two-pass algorithm)
*/
for (i = 0; i < n; i++) {
v1 += sqr(val[i] - mean);
}
for (i = 0; i < n; i++)
v2 += val[i] - mean;
v2 = sqr(v2) / n;
variance = (v1 - v2) / (n - 1);
if (variance < T())
variance = T();
stddev = sqrt(variance);
/*
* Skewness and kurtosis
*/
if (stddev != T()) {
for (i = 0; i < n; i++) {
v = (val[i] - mean) / stddev;
v2 = sqr(v);
skewness = skewness + v2 * v;
kurtosis = kurtosis + sqr(v2);
}
skewness /= n;
kurtosis = kurtosis / n - 3.;
}
return true;
}
T mean;
T variance;
T skewness;
T kurtosis;
};
typedef PIStatistic<int> PIStatistici;
typedef PIStatistic<float> PIStatisticf;
typedef PIStatistic<double> PIStatisticd;
template <typename T>
bool OLS_Linear(const PIVector<PIPair<T, T> > & input, T * out_a, T * out_b) {
if (input.size_s() < 2)
return false;
int n = input.size_s();
T a_t0 = T(), a_t1 = T(), a_t2 = T(), a_t3 = T(), a_t4 = T(), a = T(), b = T();
for (int i = 0; i < n; ++i) {
const PIPair<T, T> & cv(input[i]);
a_t0 += cv.first * cv.second;
a_t1 += cv.first;
a_t2 += cv.second;
a_t3 += cv.first * cv.first;
}
a_t4 = n * a_t3 - a_t1 * a_t1;
if (a_t4 != T())
a = (n * a_t0 - a_t1 * a_t2) / a_t4;
b = (a_t2 - a * a_t1) / n;
if (out_a != 0) *out_a = a;
if (out_b != 0) *out_b = b;
return true;
}
template <typename T>
bool WLS_Linear(const PIVector<PIPair<T, T> > & input, const PIVector<T> & weights, T * out_a, T * out_b) {
if (input.size_s() < 2)
return false;
if (input.size_s() != weights.size_s())
return false;
int n = input.size_s();
T a_t0 = T(), a_t1 = T(), a_t2 = T(), a_t3 = T(), a_t4 = T(), a_n = T(), a = T(), b = T();
for (int i = 0; i < n; ++i) {
T cp = weights[i];
const PIPair<T, T> & cv(input[i]);
a_t0 += cv.first * cv.second * cp;
a_t1 += cv.first * cp;
a_t2 += cv.second * cp;
a_t3 += cv.first * cv.first * cp;
a_n += cp;
}
a_t4 = a_n * a_t3 - a_t1 * a_t1;
if (a_t4 != T())
a = (a_n * a_t0 - a_t1 * a_t2) / a_t4;
b = (a_t2 - a * a_t1) / a_n;
if (out_a != 0) *out_a = a;
if (out_b != 0) *out_b = b;
return true;
}
#endif // PIMATH_H

View File

@@ -64,12 +64,12 @@ public:
PIRepeater(const PIString & config, const PIString & name) {
PIConfig conf(config, PIIODevice::ReadOnly);
if (!conf.isOpened()) {
piCout << "[PIRepeater \"" << name << "\"] Can`t open \"" << config << "\"!";
piCoutObj << "[PIRepeater \"" << name << "\"] Can`t open \"" << config << "\"!";
return;
}
PIConfig::Entry & b(conf.getValue(name));
if (b.childCount() != 2) {
piCout << "[PIRepeater \"" << name << "\"] \"" << config << "\" should consist 2 nodes!";
piCoutObj << "[PIRepeater \"" << name << "\"] \"" << config << "\" should consist 2 nodes!";
return;
}
addProtocol(config, b.child(0)->fullName());

View File

@@ -21,6 +21,41 @@
PIVector<PIObject * > PIObject::objects;
void PIObject::piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h) {
PIObject * o = findByName(src);
if (o == 0) {
piCout << "[PIObject] Can`t find object with name \"" << src << "\"!";
return;
}
o->connections << Connection(ev_h, 0, sig, dest);
}
void PIObject::piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * ev_h) {
PIObject * o = findByName(dest);
if (o == 0) {
piCout << "[PIObject] Can`t find object with name \"" << dest << "\"!";
return;
}
src->connections << Connection(ev_h, 0, sig, o);
}
void PIObject::piConnect(const PIString & src, const PIString & sig, const PIString & dest, void * ev_h) {
PIObject * s = findByName(src);
if (s == 0) {
piCout << "[PIObject] Can`t find object with name \"" << src << "\"!";
return;
}
PIObject * d = findByName(dest);
if (d == 0) {
piCout << "[PIObject] Can`t find object with name \"" << dest << "\"!";
return;
}
s->connections << Connection(ev_h, 0, sig, d);
}
/*
PIStringList PIObject::events() {
PIStringList l;

View File

@@ -253,11 +253,22 @@ class PIP_EXPORT PIObject
{
friend class PIObjectManager;
public:
PIObject(const PIString & name = PIString()) {piMonitor.objects++; setName(name); objects << this;}
//! Contructs PIObject with name "name"
PIObject(const PIString & name = PIString()) {piMonitor.objects++; setName(name); objects << this; debug_ = true;}
~PIObject() {piMonitor.objects--; objects.removeAll(this);}
//! Returns object name
const PIString & name() const {return name_;}
//! Set object name
void setName(const PIString & name) {name_ = name;}
//! Return if debug of this object is active
bool debug() const {return debug_;}
//! Set object debug active
void setDebug(bool debug) {debug_ = debug;}
/*
PIStringList events();
PIStringList eventHandlers();
@@ -307,6 +318,11 @@ public:
// / Direct connect
static void piConnect(PIObject * src, const PIString & sig, void * dest, void * ev_h) {src->connections << Connection(ev_h, 0, sig, dest);}
static void piConnect(PIObject * src, const PIString & sig, void * dest, void * ev_h, void * e_h) {src->connections << Connection(ev_h, e_h, sig, dest);}
static void piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h);
static void piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * ev_h);
static void piConnect(const PIString & src, const PIString & sig, const PIString & dest, void * ev_h);
static void piDisconnect(PIObject * src, const PIString & sig, void * dest, void * ev_h) {
for (int i = 0; i < src->connections.size_s(); ++i) {
Connection & cc(src->connections[i]);
@@ -325,6 +341,8 @@ public:
}
}
}
//! Disconnect object "src" from all connections with event name "sig"
static void piDisconnect(PIObject * src, const PIString & sig) {
for (int i = 0; i < src->connections.size_s(); ++i) {
Connection & cc(src->connections[i]);
@@ -334,6 +352,8 @@ public:
}
}
}
//! Disconnect object "src" from all connections, i.e. all connections where object "src" is emitter
static void piDisconnect(PIObject * src) {src->connections.clear();}
//static void piConnect(PIObject & src, const PIString & sig, PIObject * dest, void * ev_h) {src.connections << Connection(ev_h, sig, dest);}
//static void piConnect(PIObject * src, const PIString & sig, PIObject & dest, void * ev_h) {src->connections << Connection(ev_h, sig, &dest);}
@@ -464,6 +484,7 @@ public:
protected:
PIString name_;
bool debug_;
private:
struct Connection {

333
pip.cbp Normal file
View File

@@ -0,0 +1,333 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="pip" />
<Option makefile_is_custom="1" />
<Option compiler="gcc" />
<Option virtualFolders="CMake Files\;CMake Files\arm_core\;CMake Files\arm_gui\;CMake Files\peri4_widgets\;CMake Files\pip\;CMake Files\pip\system_test\;CMake Files\RLSysteModel\;" />
<Build>
<Target title="all">
<Option working_dir="C:/Qt/synchro-a/src/pip" />
<Option type="4" />
<MakeCommands>
<Build command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 all" />
<CompileFile command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 &quot;$file&quot;" />
<Clean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 clean" />
<DistClean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 clean" />
</MakeCommands>
</Target>
<Target title="pip">
<Option output="C:/Qt/synchro-a/src/pip/libpip.dll" prefix_auto="0" extension_auto="0" />
<Option working_dir="C:/Qt/synchro-a/src/pip" />
<Option object_output="./" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-DPIP_USB" />
<Add option="-DPIP_USB" />
<Add directory="C:/Qt/synchro-a/src" />
<Add directory="C:/Qt/synchro-a/src/peri4_widgets" />
<Add directory="C:/Qt/synchro-a/src/pip" />
<Add directory="C:/Qt/synchro-a/src/pip/." />
</Compiler>
<MakeCommands>
<Build command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 pip" />
<CompileFile command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 &quot;$file&quot;" />
<Clean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 clean" />
<DistClean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 clean" />
</MakeCommands>
</Target>
<Target title="pip/fast">
<Option output="C:/Qt/synchro-a/src/pip/libpip.dll" prefix_auto="0" extension_auto="0" />
<Option working_dir="C:/Qt/synchro-a/src/pip" />
<Option object_output="./" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-DPIP_USB" />
<Add option="-DPIP_USB" />
<Add directory="C:/Qt/synchro-a/src" />
<Add directory="C:/Qt/synchro-a/src/peri4_widgets" />
<Add directory="C:/Qt/synchro-a/src/pip" />
<Add directory="C:/Qt/synchro-a/src/pip/." />
</Compiler>
<MakeCommands>
<Build command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 pip/fast" />
<CompileFile command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 &quot;$file&quot;" />
<Clean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 clean" />
<DistClean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 clean" />
</MakeCommands>
</Target>
<Target title="pip_test">
<Option output="C:/Qt/synchro-a/src/pip/pip_test.exe" prefix_auto="0" extension_auto="0" />
<Option working_dir="C:/Qt/synchro-a/src/pip" />
<Option object_output="./" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-DPIP_USB" />
<Add option="-DPIP_USB" />
<Add directory="C:/Qt/synchro-a/src" />
<Add directory="C:/Qt/synchro-a/src/peri4_widgets" />
<Add directory="C:/Qt/synchro-a/src/pip" />
<Add directory="C:/Qt/synchro-a/src/pip/." />
</Compiler>
<MakeCommands>
<Build command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 pip_test" />
<CompileFile command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 &quot;$file&quot;" />
<Clean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 clean" />
<DistClean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 clean" />
</MakeCommands>
</Target>
<Target title="pip_test/fast">
<Option output="C:/Qt/synchro-a/src/pip/pip_test.exe" prefix_auto="0" extension_auto="0" />
<Option working_dir="C:/Qt/synchro-a/src/pip" />
<Option object_output="./" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-DPIP_USB" />
<Add option="-DPIP_USB" />
<Add directory="C:/Qt/synchro-a/src" />
<Add directory="C:/Qt/synchro-a/src/peri4_widgets" />
<Add directory="C:/Qt/synchro-a/src/pip" />
<Add directory="C:/Qt/synchro-a/src/pip/." />
</Compiler>
<MakeCommands>
<Build command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 pip_test/fast" />
<CompileFile command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 &quot;$file&quot;" />
<Clean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 clean" />
<DistClean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/Makefile&quot; VERBOSE=1 clean" />
</MakeCommands>
</Target>
<Target title="pip_sys_test">
<Option output="C:/Qt/synchro-a/src/pip/system_test/pip_sys_test.exe" prefix_auto="0" extension_auto="0" />
<Option working_dir="C:/Qt/synchro-a/src/pip/system_test" />
<Option object_output="./" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-DPIP_USB" />
<Add option="-DPIP_USB" />
<Add directory="C:/Qt/synchro-a/src" />
<Add directory="C:/Qt/synchro-a/src/peri4_widgets" />
<Add directory="C:/Qt/synchro-a/src/pip" />
<Add directory="C:/Qt/synchro-a/src/pip/." />
<Add directory="C:/Qt/synchro-a/src/pip/system_test" />
<Add directory="C:/Qt/synchro-a/src/pip/system_test/." />
<Add directory="C:/Qt/synchro-a/src/pip/system_test/.." />
</Compiler>
<MakeCommands>
<Build command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/system_test/Makefile&quot; VERBOSE=1 pip_sys_test" />
<CompileFile command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/system_test/Makefile&quot; VERBOSE=1 &quot;$file&quot;" />
<Clean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/system_test/Makefile&quot; VERBOSE=1 clean" />
<DistClean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/system_test/Makefile&quot; VERBOSE=1 clean" />
</MakeCommands>
</Target>
<Target title="pip_sys_test/fast">
<Option output="C:/Qt/synchro-a/src/pip/system_test/pip_sys_test.exe" prefix_auto="0" extension_auto="0" />
<Option working_dir="C:/Qt/synchro-a/src/pip/system_test" />
<Option object_output="./" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-DPIP_USB" />
<Add option="-DPIP_USB" />
<Add directory="C:/Qt/synchro-a/src" />
<Add directory="C:/Qt/synchro-a/src/peri4_widgets" />
<Add directory="C:/Qt/synchro-a/src/pip" />
<Add directory="C:/Qt/synchro-a/src/pip/." />
<Add directory="C:/Qt/synchro-a/src/pip/system_test" />
<Add directory="C:/Qt/synchro-a/src/pip/system_test/." />
<Add directory="C:/Qt/synchro-a/src/pip/system_test/.." />
</Compiler>
<MakeCommands>
<Build command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/system_test/Makefile&quot; VERBOSE=1 pip_sys_test/fast" />
<CompileFile command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/system_test/Makefile&quot; VERBOSE=1 &quot;$file&quot;" />
<Clean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/system_test/Makefile&quot; VERBOSE=1 clean" />
<DistClean command="C:/MinGW/bin/mingw32-make.exe -f &quot;C:/Qt/synchro-a/src/pip/system_test/Makefile&quot; VERBOSE=1 clean" />
</MakeCommands>
</Target>
</Build>
<Unit filename="C:/Qt/synchro-a/src/pip/main.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pibytearray.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/picli.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/picodec.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piconfig.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piconsole.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pidiagnostics.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pidir.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piethernet.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pievaluator.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pifile.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piincludes.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piiodevice.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pikbdlistener.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pimath.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pimonitor.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piobject.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pipacketextractor.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pipeer.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piprocess.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piprotocol.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piserial.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pisignals.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pistring.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pisystemmonitor.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pisystemtests.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pithread.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pitimer.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piusb.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pivariable.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/system_test/main.cpp">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pibytearray.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/picli.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/picodec.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piconfig.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piconsole.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pidiagnostics.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pidir.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piethernet.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pievaluator.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pifile.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piincludes.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piiodevice.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pikbdlistener.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pimath.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pimonitor.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piobject.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pip_resource_win.o">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pipacketextractor.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pipeer.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piprocess.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piprotocol.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piserial.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pisignals.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pistring.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pisystemmonitor.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pisystemtests.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pithread.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pitimer.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/piusb.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/pivariable.h">
</Unit>
<Unit filename="C:/Qt/synchro-a/src/CMakeLists.txt">
<Option virtualFolder="CMake Files\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/arm_core/CMakeLists.txt">
<Option virtualFolder="CMake Files\arm_core\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/arm_core/CMakeLists.txt">
<Option virtualFolder="CMake Files\arm_core\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/arm_gui/CMakeLists.txt">
<Option virtualFolder="CMake Files\arm_gui\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/arm_gui/CMakeLists.txt">
<Option virtualFolder="CMake Files\arm_gui\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/peri4_widgets/CMakeLists.txt">
<Option virtualFolder="CMake Files\peri4_widgets\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/peri4_widgets/peri4_widgets.qrc">
<Option virtualFolder="CMake Files\peri4_widgets\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/peri4_widgets/CMakeLists.txt">
<Option virtualFolder="CMake Files\peri4_widgets\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/peri4_widgets/peri4_widgets.qrc">
<Option virtualFolder="CMake Files\peri4_widgets\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/CMakeLists.txt">
<Option virtualFolder="CMake Files\pip\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/CMakeLists.txt">
<Option virtualFolder="CMake Files\pip\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/system_test/CMakeLists.txt">
<Option virtualFolder="CMake Files\pip\system_test\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/pip/system_test/CMakeLists.txt">
<Option virtualFolder="CMake Files\pip\system_test\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/RLSysteModel/CMakeLists.txt">
<Option virtualFolder="CMake Files\RLSysteModel\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/RLSysteModel/icons.qrc">
<Option virtualFolder="CMake Files\RLSysteModel\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/RLSysteModel/pcollection.qrc">
<Option virtualFolder="CMake Files\RLSysteModel\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/RLSysteModel/CMakeLists.txt">
<Option virtualFolder="CMake Files\RLSysteModel\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/RLSysteModel/icons.qrc">
<Option virtualFolder="CMake Files\RLSysteModel\" />
</Unit>
<Unit filename="C:/Qt/synchro-a/src/RLSysteModel/pcollection.qrc">
<Option virtualFolder="CMake Files\RLSysteModel\" />
</Unit>
</Project>
</CodeBlocks_project_file>

View File

@@ -9,7 +9,7 @@ INCLUDEPATH += .
QT -= core gui
CONFIG -= qt
CONFIG += dll
VERSION = 0.3.4
VERSION = 0.3.6
# Input
HEADERS += \

215
pip.pro.user Normal file
View File

@@ -0,0 +1,215 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by Qt Creator 2.4.1, 2013-04-09T20:11:21. -->
<qtcreator>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QString" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QString" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"/>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Target.DesktopTarget</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Mingw:C:/MinGW/bin//g++.exe.x86-windows-msys-pe-32bit.C:/Qt/qtcreator-2.4.1/pythongdb/gdb-i686-pc-mingw32.exe</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibraryAuto">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Qt 4.8.0 (4.8.0) Релиз</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="QString" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory">E:/pprojects/pip</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId">6</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">false</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Установка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Без установки</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Project.UseGlobal">true</value>
<value type="bool" key="Analyzer.Project.UseGlobal">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">pip</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4RunConfiguration.BaseEnvironmentBase">2</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">pip.pro</value>
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal">false</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.Qt4RunConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
<value type="QString">{e0680b61-7ce7-4775-a872-e83c6b7b3dfe}</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">10</value>
</data>
</qtcreator>

35
pip_export.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef PIP_EXPORT_H
#define PIP_EXPORT_H
#ifdef PIP_STATIC_DEFINE
# define PIP_EXPORT
# define PIP_NO_EXPORT
#else
# ifndef PIP_EXPORT
# ifdef pip_EXPORTS
/* We are building this library */
# define PIP_EXPORT __attribute__((visibility("default")))
# else
/* We are using this library */
# define PIP_EXPORT __attribute__((visibility("default")))
# endif
# endif
# ifndef PIP_NO_EXPORT
# define PIP_NO_EXPORT __attribute__((visibility("hidden")))
# endif
#endif
#ifndef PIP_DEPRECATED
# define PIP_DEPRECATED __attribute__ ((__deprecated__))
# define PIP_DEPRECATED_EXPORT PIP_EXPORT __attribute__ ((__deprecated__))
# define PIP_DEPRECATED_NO_EXPORT PIP_NO_EXPORT __attribute__ ((__deprecated__))
#endif
#define DEFINE_NO_DEPRECATED 0
#if DEFINE_NO_DEPRECATED
# define PIP_NO_DEPRECATED
#endif
#endif

38
pip_resource.rc Normal file
View File

@@ -0,0 +1,38 @@
# if defined(UNDER_CE)
# include <winbase.h>
# else
# include <winver.h>
# endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,3,6,0
PRODUCTVERSION 0,3,6,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "\0"
VALUE "FileVersion", "0.3.6.0\0"
VALUE "LegalCopyright", "\0"
VALUE "OriginalFilename", "pip0.dll\0"
VALUE "ProductName", "pip\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
/* End of Version info */

34
pip_resource_win.rc Normal file
View File

@@ -0,0 +1,34 @@
# if defined(UNDER_CE)
# include <winbase.h>
# else
# include <winver.h>
# endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,3,6,0
PRODUCTVERSION 0,3,6,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "Peri4\0"
VALUE "FileDescription", "Platform-Independent Primitives\0"
VALUE "FileVersion", "0.3.6.0\0"
VALUE "LegalCopyright", "\0"
VALUE "OriginalFilename", "libpip.dll\0"
VALUE "ProductName", "PIP\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
/* End of Version info */

38
pip_test_resource.rc Normal file
View File

@@ -0,0 +1,38 @@
# if defined(UNDER_CE)
# include <winbase.h>
# else
# include <winver.h>
# endif
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,3,2,0
PRODUCTVERSION 0,3,2,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "\0"
VALUE "FileVersion", "0.3.2.0\0"
VALUE "LegalCopyright", "\0"
VALUE "OriginalFilename", "pip_test.exe\0"
VALUE "ProductName", "pip_test\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
/* End of Version info */

View File

@@ -19,45 +19,36 @@
#include "pipeer.h"
#define _PIPEER_PORT_SYNC_START 13313
#define _PIPEER_PORT_SYNC_END 13353
#define _PIPEER_IP_MULTICAST "239.13.3.12"
#define _PIPEER_MSG_SIZE 8192
PIPeer::PIPeer(const PIString & name): PIEthernet() {
PIPeer::PIPeer(const PIString & name): PIObject() {
rec_mc = rec_bc = false;
setName(name);
setParameter(PIEthernet::Broadcast);
setReadPort(13312);
setSendPort(13312);
self_info.name = name_;
self_info.dist = 0;
//joinMulticastGroup("239.240.241.242");
srand(uint(PITimer::elapsed_system_m()));
//id_ = name() + "_" + PIString::fromNumber(rand());
CONNECT2(void, void * , int, &timer, timeout, this, timerEvent);
PIEthernet * ce;
PIStringList sl = PIEthernet::allAddresses();
PIString ta;
self_info.name = name_;
self_info.dist = 0;
piForeachC (PIString & i, sl) {
ce = new PIEthernet(this, func_readed);
ce->setReadAddress(i, 13313);
eths << ce;
ce->startThreadedRead();
self_info.addresses << i;
//cout << i << ": " << ta << endl;
}
eth_send = new PIEthernet();
eth_send->initialize();
startThreadedRead();
//joinMulticastGroup("239.13.3.12");
//timer.addDelimiter(5);
sl.removeAll("127.0.0.1"); sl << "127.0.0.1";
initMulticasts(sl);
initEths(sl);
//piCout << "Peer" << name_;
timer.addDelimiter(5);
timer.start(1000);
sendSelfInfo();
}
PIPeer::~PIPeer() {
terminate();
piForeach (PIEthernet * i, mc_eths)
i->stopThreadedRead();
sendSelfRemove();
//leaveMulticastGroup("239.13.3.12");
delete eth_send;
destroyMulticasts();
piForeach (PIEthernet * i, eths)
delete i;
eths.clear();
@@ -66,7 +57,7 @@ PIPeer::~PIPeer() {
void PIPeer::timerEvent(void * data, int delim) {
switch (delim) {
case 1: // 5 s
case 5: // 5 s
syncPeers();
break;
}
@@ -74,46 +65,260 @@ void PIPeer::timerEvent(void * data, int delim) {
}
bool PIPeer::threadedRead(uchar * data, int size) {
void PIPeer::initEths(const PIStringList & al) {
PIEthernet * ce;
PIEthernet::InterfaceList il = PIEthernet::interfaces();
const PIEthernet::Interface * cint = 0;
piForeachC (PIString & a, al) {
ce = new PIEthernet();
ce->setParameters(0);
ce->setDebug(false);
for (int p = _PIPEER_PORT_SYNC_START; p < 65536; ++p) {
ce->setReadAddress(a, p);
if (ce->open()) {
eths << ce;
cint = il.getByAddress(a);
self_info.addresses << ce->path();
self_info.netmasks << (cint == 0 ? "255.255.255.0" : cint->netmask);
CONNECT2(bool, void * , int, ce, threadedReadEvent, this, dataRead);
ce->startThreadedRead();
//piCout << "dc binded to" << ce->path();
//piCout << "add eth" << ta;
break;
}
}
}
}
void PIPeer::initMulticasts(const PIStringList & al) {
destroyMulticasts();
PIEthernet * ce;
PIEthernet::InterfaceList il = PIEthernet::interfaces();
const PIEthernet::Interface * cint;
PIStringList nal = al;
PIString nm;
nal << "main" << "bc";
rec_mc = rec_bc = false;
piForeachC (PIString & a, nal) {
bool is_main = (a == "main");
bool is_bc = (a == "bc");
ce = new PIEthernet();
ce->setParameters((is_main || is_bc) ? PIEthernet::Broadcast : 0);
ce->setDebug(false);
//cint = il.getByAddress(a);
//nm = (cint == 0) ? "255.255.255.0" : cint->netmask;
ce->setSendIP(is_bc ? "255.255.255.255" : _PIPEER_IP_MULTICAST);
//piCout << "mc try" << a << nm << ce->sendIP();
for (int p = _PIPEER_PORT_SYNC_START; p < _PIPEER_PORT_SYNC_END; ++p) {
ce->setReadAddress(((is_main || is_bc) ? "255.255.255.255" : a) + ":" + PIString::fromNumber(p));
ce->close();
if (!ce->open()) continue;
if (is_main) if (!ce->joinMulticastGroup(_PIPEER_IP_MULTICAST)) continue;
//piCout << "mc binded to" << ce->path();
mc_eths << ce;
if (is_main || is_bc) {
if (is_main) rec_mc = true;
if (is_bc) rec_bc = true;
CONNECT2(bool, void * , int, ce, threadedReadEvent, this, multicastRead);
ce->startThreadedRead();
if (is_bc) ce->setParameter(PIEthernet::Broadcast, false);
}
break;
}
}
piForeachC (PIString & a, al) {
ce = new PIEthernet();
ce->setParameters(PIEthernet::Broadcast);
ce->setDebug(false);
cint = il.getByAddress(a);
nm = (cint == 0) ? "255.255.255.0" : cint->netmask;
ce->setSendIP(PIEthernet::getBroadcast(a, nm));
//piCout << "mc BC try" << a << nm << ce->sendIP();
for (int p = _PIPEER_PORT_SYNC_START; p < _PIPEER_PORT_SYNC_END; ++p) {
ce->setReadAddress(a + ":" + PIString::fromNumber(p));
ce->close();
if (!ce->open()) continue;
//piCout << "BC binded to" << ce->path();
mc_eths << ce;
break;
}
}
if (!rec_mc) piCoutObj << "[PIPeer \"" + name_ + "\"] Can`t find suitable network interface for multicast receive, check for exists at least one interface with multicasting enabled!";
if (!rec_bc) piCoutObj << "[PIPeer \"" + name_ + "\"] Can`t find suitable network interface for broadcast receive, check for exists at least one interface with broadcasting enabled!";
}
void PIPeer::destroyMulticasts() {
piForeach (PIEthernet * i, mc_eths) {
i->leaveMulticastGroup(_PIPEER_IP_MULTICAST);
delete i;
}
mc_eths.clear();
}
PIPeer::PeerInfo * PIPeer::quickestPeer(const PIString & to) {
if (!addresses_map.contains(to)) return 0;
//piCout << "*** search quickest peer" << to;
PIVector<PeerInfo * > tp = addresses_map[to];
PeerInfo * dp = 0;
int mping = 99999;
for (int i = 0; i < tp.size_s(); ++i) {
if (mping > tp[i]->ping) {
mping = tp[i]->ping;
dp = tp[i];
}
}
//piCout << "*** search quickest peer: found" << dp->name;
return dp;
}
bool PIPeer::sendToNeighbour(PIPeer::PeerInfo * peer, const PIByteArray & ba) {
if (peer->_neth == 0) return false;
//piCout << "send to" << peer->name << peer->_naddress << ba.size_s() << "bytes";
diag_d.sended(ba.size_s());
return peer->_neth->send(peer->_naddress, ba.data(), ba.size_s());
}
bool PIPeer::send(const PIString & to, const void * data, int size) {
PeerInfo * dp = quickestPeer(to);
if (dp == 0) {
//piCoutObj << "[PIPeer \"" + name_ + "\"] Can`t find peer \"" << to << "\"!";
return false;
}
PIByteArray ba;
ba << int(4) << self_info.name << to << int(0) << size;
PIByteArray fmsg(data, size), cmsg;
int msg_count = (size - 1) / _PIPEER_MSG_SIZE + 1;
for (int i = 0; i < msg_count; ++i) {
int csize = (i == msg_count - 1) ? ((size - 1) % _PIPEER_MSG_SIZE + 1) : _PIPEER_MSG_SIZE;
cmsg.clear();
cmsg.append(ba);
cmsg << msg_count << i;
cmsg.append(fmsg.data(i * _PIPEER_MSG_SIZE), csize);
if (!sendToNeighbour(dp, cmsg)) return false;
}
return true;
}
bool PIPeer::dataRead(uchar * readed, int size) {
diag_d.received(size);
PIByteArray ba(readed, size), sba;
int type, cnt, rec_size;
PIString from, to;
ba >> type >> from >> to >> cnt >> rec_size;
//piCout << "[PIPeer \"" + name_ + "\"] Received packet" << type << from << to << cnt << rec_size;
if (type == 4) { // data packet
if (to == self_info.name) { // my packet
int msg_count, cmsg;
ba >> msg_count >> cmsg;
//piCout << "[PIPeer \"" + name_ + "\"] Received packet" << type << from << to << cnt << rec_size << msg_count << cmsg;
if (cmsg == 0 && msg_count == 1) {
dataReceived(from, ba);
dataReceivedEvent(from, ba);
return true;
}
PeerInfo * fp = const_cast<PeerInfo * >(getPeerByName(from));
if (fp == 0) return true;
PeerData & pd(fp->_data);
if (cmsg == 0) {
//piCout << "[PIPeer \"" + name_ + "\"] Packet clear" << rec_size;
pd.clear();
pd.msg_count = msg_count;
}
//piCout << "[PIPeer \"" + name_ + "\"] Packet add" << cmsg << ba.size_s();
pd.addData(ba);
if (pd.isFullReceived()) {
dataReceived(from, pd.data);
dataReceivedEvent(from, pd.data);
//piCout << "[PIPeer \"" + name_ + "\"] Packet received" << pd.data.size_s();
}
return true;
}
PeerInfo * dp = quickestPeer(to);
if (dp == 0) {
//piCoutObj << "[PIPeer \"" + name_ + "\"] Can`t find peer \"" << to << "\"!";
return true;
}
cnt++;
if (cnt > 100 || from == dp->name) return true;
sba << type << from << to << cnt << rec_size;
sba.append(ba);
//piCoutObj << "[PIPeer \"" + name_ + "\"] Translate data packet" << type << from << to << cnt << rec_size;
sendToNeighbour(dp, sba);
}
return true;
}
bool PIPeer::multicastRead(uchar * data, int size) {
PIMutexLocker locker(mc_mutex);
diag_s.received(size);
int header;
PeerInfo pi;
PIByteArray ba(data, size);
PIVector<PeerInfo> rpeers;
ba >> header >> pi.name;
//piCout << "read type" << header << "from" << pi.name;
if (pi.name == name_) return true;
//piCout << "analyz ...";
switch (header) {
case 1: // new peer accepted
//piCout << "new peer packet ...";
if (hasPeer(pi.name)) break;
ba >> pi.dist >> pi.addresses;
ba >> pi.dist >> pi.addresses >> pi.netmasks >> pi.neighbours;
pi.sync = 0;
if (pi.dist == 0) {
pi.addNeighbour(self_info.name);
self_info.addNeighbour(pi.name);
}
peers << pi;
cout << "[PIPeer \"" + name_ + "\"] new peer \"" << pi.name << "\"" << " dist " << pi.dist << endl;
//piCoutObj << "[PIPeer \"" + name_ + "\"] new peer \"" << pi.name << "\"" << " dist " << pi.dist;
pi.dist++;
sendSelfInfo();
sendPeerInfo(pi);
findNearestAddresses();
peerConnected(pi.name);
peerConnectedEvent(pi.name);
//piCout << "new peer packet ok";
break;
case 2: // remove peer accepted
//piCout << "remove peer packet ...";
if (removePeer(pi.name)) {
cout << "[PIPeer \"" + name_ + "\"] remove peer \"" << pi.name << "\"" << endl;
//piCoutObj << "[PIPeer \"" + name_ + "\"] remove peer \"" << pi.name << "\"";
if (pi.dist == 0) {
pi.removeNeighbour(self_info.name);
self_info.removeNeighbour(pi.name);
}
sendPeerRemove(pi.name);
findNearestAddresses();
peerDisconnected(pi.name);
peerDisconnectedEvent(pi.name);
}
//piCout << "remove peer packet ok";
break;
case 3: // sync peers
ba >> pi.addresses >> rpeers;
//piCout << "sync packet ...";
ba >> pi.addresses >> pi.netmasks >> pi.neighbours >> rpeers;
rpeers << pi;
//cout << "[PIPeer \"" + name_ + "\"] rec sync " << rpeers.size_s() << " peers" << endl;
//piCout << "[PIPeer \"" + name_ + "\"] rec sync " << rpeers.size_s() << " peers";
for (uint i = 0; i < rpeers.size(); ++i) {
PeerInfo & rpeer(rpeers[i]);
//cout << " to sync " << rpeer.name << endl;
//piCout << " to sync " << rpeer.name;
if (rpeer.name == name_) continue;
bool exist = false;
for (uint j = 0; j < peers.size(); ++j) {
PeerInfo & peer(peers[j]);
if (peer.name == rpeer.name) {
//cout << "synced " << peer.name << endl;
//piCout << "synced " << peer.name;
peer.addresses == rpeer.addresses;
peer.netmasks == rpeer.netmasks;
peer.addNeighbours(rpeer.neighbours);
rpeer.neighbours = peer.neighbours;
if (peer.name == pi.name) peer.sync = 0;
exist = true;
break;
@@ -123,6 +328,17 @@ bool PIPeer::threadedRead(uchar * data, int size) {
peers << rpeer;
peers.back().dist++;
findNearestAddresses();
peerConnected(rpeer.name);
peerConnectedEvent(rpeer.name);
}
//piCout << "***";;
//piCout << self_info.name << self_info.neighbours;
piForeach (PeerInfo & i, peers) {
if (i.dist == 0) {
self_info.addNeighbour(i.name);
i.addNeighbour(self_info.name);
}
//piCout << i.name << i.neighbours;
}
break;
}
@@ -130,57 +346,146 @@ bool PIPeer::threadedRead(uchar * data, int size) {
}
bool PIPeer::func_readed(void * peer, uchar * data, int size) {
PIPeer * p = (PIPeer * )peer;
cout << "[PIPeer \"" + p->name_ + "\"] received " << data << endl;
return true;
void PIPeer::sendMulticast(const PIByteArray & ba) {
piForeach (PIEthernet * e, mc_eths) {
for (int p = _PIPEER_PORT_SYNC_START; p < _PIPEER_PORT_SYNC_END; ++p) {
e->setSendPort(p);
//errorClear();
//piCout << "send to" << e->sendAddress() << e->send(ba);
//piCout << PIEthernet::ethErrorString();
e->send(ba);
diag_s.sended(ba.size_s());
}
}
}
void PIPeer::sendPeerInfo(const PeerInfo & info) {
PIByteArray ba;
ba << int(1) << info.name << info.dist << info.addresses;
write(ba);
ba << int(1) << info.name << info.dist << info.addresses << info.netmasks << info.neighbours;
sendMulticast(ba);
}
void PIPeer::sendPeerRemove(const PIString & peer) {
PIByteArray ba;
ba << int(2) << peer;
write(ba);
sendMulticast(ba);
}
void PIPeer::syncPeers() {
//cout << "[PIPeer \"" + name_ + "\"] sync " << peers.size_s() << " peers" << endl;
//piCout << "[PIPeer \"" + name_ + "\"] sync " << peers.size_s() << " peers";
PIString pn;
bool change = false;
for (uint i = 0; i < peers.size(); ++i) {
PeerInfo & cp(peers[i]);
if (cp.sync > 1 && cp.dist == 0) {
if (cp.sync > 3 && cp.dist == 0) {
pn = cp.name;
cout << "[PIPeer \"" + name_ + "\"] sync: remove " << pn << endl;
//piCoutObj << "[PIPeer \"" + name_ + "\"] sync: remove " << pn;
peers.remove(i);
sendPeerRemove(pn);
--i;
findNearestAddresses();
piForeach (PeerInfo & p, peers)
p.removeNeighbour(pn);
self_info.removeNeighbour(pn);
peerDisconnected(pn);
peerDisconnectedEvent(pn);
change = true;
continue;
}
cp.sync++;
}
if (change) findNearestAddresses();
PIByteArray ba;
ba << int(3) << self_info.name << self_info.addresses << peers;
write(ba);
ba << int(3) << self_info.name << self_info.addresses << self_info.netmasks << self_info.neighbours << peers;
sendMulticast(ba);
}
void PIPeer::findNearestAddresses() {
cout << "[PIPeer \"" + name_ + "\"] findNearestAddresses" << endl;
//piCout << "[PIPeer \"" + name_ + "\"] findNearestAddresses";
addresses_map.clear();
int max_dist = -1;
piForeach (PeerInfo & i, peers)
static PIMap<PIString, PeerInfo * > peers_;
peers_.clear();
self_info._nuses.resize(self_info.neighbours.size());
self_info._nuses.fill(0);
self_info._first = &self_info;
peers_[self_info.name] = &self_info;
piForeach (PeerInfo & i, peers) {
i._nuses.resize(i.neighbours.size());
i._nuses.fill(0);
i._first = 0;
peers_[i.name] = &i;
if (max_dist < i.dist)
max_dist = i.dist;
PIVector<PeerInfo * > cwave;
for (int d = 0; d <= max_dist; ++d) {
//if ()
if (i.dist > 0) continue;
i._naddress.clear();
i._neth = 0;
PIString mma, ma;
bool af = false;
for (int mi = 0; mi < self_info.addresses.size_s(); ++mi) {
PIString & m(self_info.addresses[mi]), & mmask(self_info.netmasks[mi]);
if (af) break;
ma = m;
//mma = m.left(m.findLast("."));
mma = PIEthernet::applyMask(m, mmask);
for (int ii = 0; ii < i.addresses.size_s(); ++ii) {
PIString & r(i.addresses[ii]), & rmask(i.netmasks[ii]);
if (mma == PIEthernet::applyMask(r, rmask)) {
i._naddress = r;
//piCout << "_naddress" << i.name << "=" << r;
af = true;
break;
}
}
}
if (!af) continue;
//piCout << " peer" << i.name << ma;
piForeach (PIEthernet * e, eths)
if (e->readAddress() == ma) {
i._neth = e;
break;
}
//piCout << i.name << i._naddress;
}
PIVector<PeerInfo * > cwave, nwave;
PeerInfo * npeer;
cwave << &self_info;
for (int d = 0; d <= max_dist; ++d) {
if (cwave.isEmpty()) break;
nwave.clear();
piForeach (PeerInfo * p, cwave) {
int ns = p->neighbours.size_s();
for (int n = 0; n < ns; ++n) {
if (p->_nuses[n] >= ns) continue;
p->_nuses[n]++;
npeer = peers_[p->neighbours[n]];
if (npeer == 0) continue;
if (d == 0) npeer->_first = npeer;
else {
if (d == 1) npeer->_first = p;
else npeer->_first = p->_first;
}
nwave << npeer;
}
}
cwave = nwave;
//piCout << "wave" << d;
for (int i = 0; i < cwave.size_s(); ++i) {
//piCout << " peer" << cwave[i]->name << Hex << (uint)(cwave[i]->_first);
if (cwave[i]->_first == 0) {cwave.remove(i); --i; continue;}
if (addresses_map.contains(cwave[i]->name)) {cwave.remove(i); --i; continue;}
}
for (int i = 0; i < cwave.size_s(); ++i) {
PIVector<PeerInfo * > & pl(addresses_map[cwave[i]->name]);
if (!pl.contains(cwave[i]->_first))
pl << cwave[i]->_first;
}
}
/*piCout << " ** addresses map **";
piForeachC (napair & i, addresses_map)
piCout << i.first << i.second;
piCout << " ** addresses map end **";*/
}

131
pipeer.h
View File

@@ -1,6 +1,6 @@
/*
PIP - Platform Independent Primitives
Peer - named I/O ethernet node
Peer - named I/O ethernet node, forming self-organized peering network
Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
@@ -21,35 +21,103 @@
#define PIPEER_H
#include "piethernet.h"
#include "pidiagnostics.h"
class PIP_EXPORT PIPeer: public PIEthernet
class PIP_EXPORT PIPeer: public PIObject
{
PIOBJECT(PIPeer)
struct PeerInfo;
friend PIByteArray & operator <<(PIByteArray & s, const PIPeer::PeerInfo & v);
friend PIByteArray & operator >>(PIByteArray & s, PIPeer::PeerInfo & v);
private:
struct PeerData {
PeerData() {msg_count = msg_rec = 0;}
void clear() {msg_count = msg_rec = 0; data.clear();}
bool isEmpty() const {return msg_count == 0;}
bool isFullReceived() const {return msg_count == msg_rec;}
void addData(const PIByteArray & ba) {data.append(ba); msg_rec++;}
void setData(const PIByteArray & ba) {data = ba; msg_rec = 0; msg_count = (data.size_s() - 1) / 4096 + 1;}
PIByteArray data;
int msg_count;
int msg_rec;
};
public:
PIPeer(const PIString & name);
~PIPeer();
virtual ~PIPeer();
//const PIString & id() const {return id_;}
class PeerInfo {
friend class PIPeer;
friend PIByteArray & operator <<(PIByteArray & s, const PIPeer::PeerInfo & v);
friend PIByteArray & operator >>(PIByteArray & s, PIPeer::PeerInfo & v);
public:
PeerInfo() {dist = sync = ping = 0; _neth = 0; _first = 0;}
PIString name;
PIStringList addresses;
int dist;
int ping;
bool isNeighbour() const {return dist == 0;}
protected:
void addNeighbour(const PIString & n) {if (!neighbours.contains(n)) neighbours << n;}
void addNeighbours(const PIStringList & l) {piForeachC (PIString & n, l) if (!neighbours.contains(n)) neighbours << n;}
void removeNeighbour(const PIString & n) {neighbours.removeAll(n);}
PIString nearest_address;
PIStringList netmasks;
PIStringList neighbours;
int sync;
PIString _naddress;
PIEthernet * _neth;
PIVector<uchar> _nuses;
PeerInfo * _first;
PeerData _data;
};
friend PIByteArray & operator <<(PIByteArray & s, const PIPeer::PeerInfo & v);
friend PIByteArray & operator >>(PIByteArray & s, PIPeer::PeerInfo & v);
bool send(const PIString & to, const PIByteArray & data) {return send(to, data.data(), data.size_s());}
bool send(const PIString & to, const PIString & data) {return send(to, data.data(), data.size_s());}
bool send(const PIString & to, const void * data, int size);
bool send(const PeerInfo & to, const PIByteArray & data) {return send(to.name, data.data(), data.size_s());}
bool send(const PeerInfo & to, const PIString & data) {return send(to.name, data.data(), data.size_s());}
bool send(const PeerInfo & to, const void * data, int size) {return send(to.name, data, size);}
bool send(const PeerInfo * to, const PIByteArray & data) {if (to == 0) return false; return send(to->name, data.data(), data.size_s());}
bool send(const PeerInfo * to, const PIString & data) {if (to == 0) return false; return send(to->name, data.data(), data.size_s());}
bool send(const PeerInfo * to, const void * data, int size) {if (to == 0) return false; return send(to->name, data, size);}
void sendToAll(const PIByteArray & data) {piForeachC (PeerInfo & i, peers) send(i.name, data.data(), data.size_s());}
void sendToAll(const PIString & data) {piForeachC (PeerInfo & i, peers) send(i.name, data.data(), data.size_s());}
void sendToAll(const void * data, int size) {piForeachC (PeerInfo & i, peers) send(i.name, data, size);}
bool isMulticastReceive() const {return rec_mc;}
bool isBroadcastReceive() const {return rec_bc;}
PIDiagnostics & diagnosticService() {return diag_s;}
PIDiagnostics & diagnosticData() {return diag_d;}
const PIVector<PeerInfo> & allPeers() const {return peers;}
bool isPeerExists(const PIString & name) const {return getPeerByName(name) != 0;}
const PeerInfo * getPeerByName(const PIString & name) const {piForeachC (PeerInfo & i, peers) if (i.name == name) return &i; return 0;}
void lock() {mc_mutex.lock();}
void unlock() {mc_mutex.unlock();}
EVENT2(dataReceivedEvent, const PIString &, from, const PIByteArray &, data);
EVENT1(peerConnectedEvent, const PIString &, name);
EVENT1(peerDisconnectedEvent, const PIString &, name);
protected:
bool threadedRead(uchar * readed, int size);
virtual void dataReceived(const PIString & from, const PIByteArray & data) {;}
virtual void peerConnected(const PIString & name) {;}
virtual void peerDisconnected(const PIString & name) {;}
EVENT_HANDLER2(bool, dataRead, uchar *, readed, int, size);
EVENT_HANDLER2(bool, multicastRead, uchar *, readed, int, size);
private:
EVENT_HANDLER2(void, timerEvent, void * , data, int, delim);
static bool func_readed(void * peer, uchar * data, int size);
struct PeerInfo {
PIString name;
PIString nearest_address;
PIStringList addresses;
int dist;
int sync;
int _wave;
};
bool hasPeer(const PIString & name) {piForeachC (PeerInfo & i, peers) if (i.name == name) return true; return false;}
bool removePeer(const PIString & name) {for (uint i = 0; i < peers.size(); ++i) if (peers[i].name == name) {peers.remove(i); return true;} return false;}
@@ -60,23 +128,36 @@ private:
void sendSelfRemove() {sendPeerRemove(name_);}
void syncPeers();
void findNearestAddresses();
void initEths(const PIStringList & al);
void initMulticasts(const PIStringList & al);
void destroyMulticasts();
void sendMulticast(const PIByteArray & ba);
PeerInfo * quickestPeer(const PIString & to);
bool sendToNeighbour(PeerInfo * peer, const PIByteArray & ba);
struct PeerPacket {
int header; // 1 - new peer, 2 - remove peer, 3 - sync peers
int header; // 1 - new peer, 2 - remove peer, 3 - sync peers, 4 - data
// Data packet: 4, from, to, ticks, data_size, data
};
PIList<PIEthernet * > eths;
PIEthernet * eth_send;
typedef std::pair<PIString, PIVector<PeerInfo * > > napair;
PIVector<PIEthernet * > eths;
PIVector<PIEthernet * > mc_eths;
PITimer timer;
PIMutex mc_mutex;
bool rec_mc, rec_bc;
PeerInfo self_info;
PIVector<PeerInfo> peers;
PIMap<PIString, PIVector<PeerInfo * > > addresses_map; // map {"to" = list of nearest peers}
PIDiagnostics diag_s, diag_d;
//PIString id_;
};
inline PIByteArray & operator <<(PIByteArray & s, const PIPeer::PeerInfo & v) {s << v.name << v.addresses << v.dist; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIPeer::PeerInfo & v) {s >> v.name >> v.addresses >> v.dist; return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIPeer::PeerInfo & v) {s << v.name << v.addresses << v.netmasks << v.dist << v.neighbours; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIPeer::PeerInfo & v) {s >> v.name >> v.addresses >> v.netmasks >> v.dist >> v.neighbours; return s;}
#endif // PIPEER_H

View File

@@ -141,12 +141,12 @@ void PIProcess::run() {
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
} else
piCout << "[PIProcess] \"CreateProcess\" error, " << errorString();
piCoutObj << "[PIProcess] \"CreateProcess\" error, " << errorString();
#else
//cout << "exec " << tf_in << ", " << tf_out << ", " << tf_err << endl;
if (execve(str.c_str(), a, e) < 0)
piCout << "[PIProcess] \"execve\" error, " << errorString();
piCoutObj << "[PIProcess] \"execve\" error, " << errorString();
} else {
msleep(1);
//cout << "wait" << endl;

View File

@@ -26,7 +26,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
PIObject::setName(name);
PIConfig conf(config, PIIODevice::ReadOnly);
if (!conf.isOpened()) {
piCout << "[PIProtocol \"" << name << "\"] Can`t open \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Can`t open \"" << config << "\"!";
devReceiverState = devSenderState = "Config error";
return;
}
@@ -41,7 +41,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
/// receiver section
if (rb.isEntryExists("ip") && rb.isEntryExists("device")) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous receiver type in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous receiver type in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
@@ -50,7 +50,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) dev = gdev;
if (gok && ok && (dev != gdev)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous receiver type in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous receiver type in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
@@ -59,7 +59,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) ps = gps;
if (gok && ok && (ps != gps)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive port in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous receive port in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
@@ -74,7 +74,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) flag = gflag;
if (gok && ok && (flag != gflag)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectEnabled\" flag in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectEnabled\" flag in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
@@ -85,18 +85,18 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) freq = gfreq;
if (gok && ok && (freq != gfreq)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectTimeout\" value in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectTimeout\" value in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
eth->setReopenTimeout(freq * 1000);
}
if (recDataPtr == 0)
piCout << "[PIProtocol \"" << name << "\"] Warning: null receive data pointer!";
piCoutObj << "[PIProtocol \"" << name << "\"] Warning: null receive data pointer!";
if (recDataSize == 0)
piCout << "[PIProtocol \"" << name << "\"] Warning: null receive data size!";
piCoutObj << "[PIProtocol \"" << name << "\"] Warning: null receive data size!";
} else {
piCout << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".receiver.port\" or \"" << name << ".port\" in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".receiver.port\" or \"" << name << ".port\" in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
@@ -106,7 +106,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) dev = gdev;
if (gok && ok && (dev != gdev)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous receiver type in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous receiver type in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
@@ -115,7 +115,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) ps = gps;
if (gok && ok && (ps != gps)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive \"speed\" in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous receive \"speed\" in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
@@ -124,7 +124,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) flag = gflag;
if (gok && ok && (flag != gflag)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive \"parity\" in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous receive \"parity\" in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
@@ -135,7 +135,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) flag = gflag;
if (gok && ok && (flag != gflag)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive \"twoStopBits\" parity in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous receive \"twoStopBits\" parity in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
@@ -154,7 +154,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) ps = gps;
if (gok && ok && (ps != gps)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous receive \"vtime\" in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous receive \"vtime\" in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
@@ -162,11 +162,11 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
}
has_dev = true;
if (recDataPtr == 0)
piCout << "[PIProtocol \"" << name << "\"] Warning: null receive data pointer!";
piCoutObj << "[PIProtocol \"" << name << "\"] Warning: null receive data pointer!";
if (recDataSize == 0)
piCout << "[PIProtocol \"" << name << "\"] Warning: null receive data size!";
piCoutObj << "[PIProtocol \"" << name << "\"] Warning: null receive data size!";
} else {
piCout << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".receiver.speed\" or \"" << name << ".speed\" in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".receiver.speed\" or \"" << name << ".speed\" in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
@@ -176,7 +176,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) history_write_rec = ghist;
if (gok && ok && (history_write_rec != ghist)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous receiver history in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous receiver history in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
@@ -187,7 +187,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
history_id_rec = rb.getValue("historyID", 0, &ok);
if (!ok) {
history_id_rec = protName.toByteArray().checksumCRC16();
piCout << "[PIProtocol \"" << name << "\"] Warning: no receiver history ID defined, write with ID = " << history_id_rec;
piCoutObj << "[PIProtocol \"" << name << "\"] Warning: no receiver history ID defined, write with ID = " << history_id_rec;
}
history_file_rec.open(history_path_rec, PIIODevice::WriteOnly);
}
@@ -196,21 +196,21 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
gfreq = b.getValue("frequency", -1.f, &gok);
if (gok && !ok) freq = gfreq;
if (gok && ok && (freq != gfreq)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous expected frequency in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous expected frequency in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
if (freq > 0.f && !has_dev)
piCout << "[PIProtocol \"" << name << "\"] Warning: no receiver device and not null expected frequency!";
piCoutObj << "[PIProtocol \"" << name << "\"] Warning: no receiver device and not null expected frequency!";
float tm = b.getValue("disconnectTimeout", 3.f);
if (tm <= 0.f)
piCout << "[PIProtocol \"" << name << "\"] Warning: diconnect timeout <= 0 s!";
piCoutObj << "[PIProtocol \"" << name << "\"] Warning: diconnect timeout <= 0 s!";
timeout_ = (tm < 0.f) ? 0.f : tm;
setExpectedFrequency(freq);
/// sender section
if (sb.isEntryExists("ip") && sb.isEntryExists("device")) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender type in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous sender type in \"" << config << "\"!";
devSenderState = "Config error";
return;
}
@@ -220,7 +220,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) dev = gdev;
if (gok && ok && (dev != gdev)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender type in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous sender type in \"" << config << "\"!";
devSenderState = "Config error";
return;
}
@@ -229,7 +229,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) ps = gps;
if (gok && ok && (ps != gps)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous send port in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous send port in \"" << config << "\"!";
devSenderState = "Config error";
return;
}
@@ -243,7 +243,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) flag = gflag;
if (gok && ok && (flag != gflag)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectEnabled\" flag in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectEnabled\" flag in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
@@ -254,18 +254,18 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) freq = gfreq;
if (gok && ok && (freq != gfreq)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectTimeout\" value in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous \"reconnectTimeout\" value in \"" << config << "\"!";
devReceiverState = "Config error";
return;
}
eth->setReopenTimeout(freq * 1000);
}
if (sendDataPtr_ == 0)
piCout << "[PIProtocol \"" << name << "\"] Warning: null send data pointer!";
piCoutObj << "[PIProtocol \"" << name << "\"] Warning: null send data pointer!";
if (sendDataSize_ == 0)
piCout << "[PIProtocol \"" << name << "\"] Warning: null send data size!";
piCoutObj << "[PIProtocol \"" << name << "\"] Warning: null send data size!";
} else {
piCout << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".sender.port\" or \"" << name << ".port\" in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".sender.port\" or \"" << name << ".port\" in \"" << config << "\"!";
devSenderState = "Config error";
return;
}
@@ -275,7 +275,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) dev = gdev;
if (gok && ok && (dev != gdev)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender type in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous sender type in \"" << config << "\"!";
devSenderState = "Config error";
return;
}
@@ -284,7 +284,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) ps = gps;
if (gok && ok && (ps != gps)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous send \"speed\" in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous send \"speed\" in \"" << config << "\"!";
devSenderState = "Config error";
return;
}
@@ -293,7 +293,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) flag = gflag;
if (gok && ok && (flag != gflag)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous send \"parity\" in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous send \"parity\" in \"" << config << "\"!";
devSenderState = "Config error";
return;
}
@@ -304,14 +304,14 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
if (ok || gok) {
if (gok && !ok) flag = gflag;
if (gok && ok && (flag != gflag)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous send \"twoStopBits\" parity in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous send \"twoStopBits\" parity in \"" << config << "\"!";
devSenderState = "Config error";
return;
}
pp.setFlag(PISerial::TwoStopBits, flag);
}
} else {
piCout << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".sender.speed\" or \"" << name << ".speed\" in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Can`t find \"" << name << ".sender.speed\" or \"" << name << ".speed\" in \"" << config << "\"!";
devSenderState = "Config error";
return;
}
@@ -322,16 +322,16 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
ser->setParameters(pp);
has_dev = true;
if (sendDataPtr_ == 0)
piCout << "[PIProtocol \"" << name << "\"] Warning: null send data pointer!";
piCoutObj << "[PIProtocol \"" << name << "\"] Warning: null send data pointer!";
if (sendDataSize_ == 0)
piCout << "[PIProtocol \"" << name << "\"] Warning: null send data size!";
piCoutObj << "[PIProtocol \"" << name << "\"] Warning: null send data size!";
}
history_write_send = sb.getValue("writeHistory", false, &ok);
ghist = b.getValue("writeHistory", false, &gok);
if (ok || gok) {
if (gok && !ok) history_write_send = ghist;
if (gok && ok && (history_write_send != ghist)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender history in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous sender history in \"" << config << "\"!";
devSenderState = "Config error";
return;
}
@@ -342,7 +342,7 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
history_id_send = sb.getValue("historyID", 0, &ok);
if (!ok) {
history_id_send = protName.toByteArray().checksumCRC16() + 1;
piCout << "[PIProtocol \"" << name << "\"] Warning: no sender history ID defined, write with ID = " << history_id_send;
piCoutObj << "[PIProtocol \"" << name << "\"] Warning: no sender history ID defined, write with ID = " << history_id_send;
}
history_file_send.open(history_path_send, PIIODevice::WriteOnly);
}
@@ -351,12 +351,12 @@ PIProtocol::PIProtocol(const PIString & config, const PIString & name, void * re
gfreq = b.getValue("frequency", -1.f, &gok);
if (gok && !ok) freq = gfreq;
if (gok && ok && (freq != gfreq)) {
piCout << "[PIProtocol \"" << name << "\"] Ambiguous sender frequency in \"" << config << "\"!";
piCoutObj << "[PIProtocol \"" << name << "\"] Ambiguous sender frequency in \"" << config << "\"!";
devSenderState = "Config error";
return;
}
if (freq > 0.f && !has_dev)
piCout << "[PIProtocol \"" << name << "\"] Warning: no sender device and not null send frequency!";
piCoutObj << "[PIProtocol \"" << name << "\"] Warning: no sender device and not null send frequency!";
setSenderFrequency(freq);
headerPtr = (uchar * )recHeaderPtr;

View File

@@ -29,8 +29,9 @@
class PIProtocol;
class PIP_EXPORT PIMultiProtocolBase
class PIP_EXPORT PIMultiProtocolBase: protected PIObject
{
PIOBJECT(PIMultiProtocolBase)
friend class PIProtocol;
public:
PIMultiProtocolBase() {;}

View File

@@ -67,14 +67,14 @@ bool PISerial::setPin(int number, bool on) {
case 3: return setST(on); break;
case 4: return setDTR(on); break;
case 5:
piCout << "[PISerial] Pin number 5 is ground";
piCoutObj << "[PISerial] Pin number 5 is ground";
return false;
case 6: return setDSR(on); break;
case 7: return setRTS(on); break;
case 8: return setCTS(on); break;
case 9: return setRNG(on); break;
default:
piCout << "[PISerial] Pin number " << number << " doesn`t exists!";
piCoutObj << "[PISerial] Pin number " << number << " doesn`t exists!";
return false;
}
return false;
@@ -93,7 +93,7 @@ bool PISerial::isPin(int number) const {
case 8: return isCTS(); break;
case 9: return isRNG(); break;
default:
piCout << "[PISerial] Pin number " << number << " doesn`t exists!";
piCoutObj << "[PISerial] Pin number " << number << " doesn`t exists!";
return false;
}
return false;
@@ -103,16 +103,16 @@ bool PISerial::isPin(int number) const {
bool PISerial::setBit(int bit, bool on, const PIString & bname) {
#ifndef WINDOWS
if (fd < 0) {
piCout << "[PISerial] set" << bname << " error: \"" << path_ << "\" is not opened!";
piCoutObj << "[PISerial] set" << bname << " error: \"" << path_ << "\" is not opened!";
return false;
}
if (ioctl(fd, on ? TIOCMBIS : TIOCMBIC, &bit) < 0) {
piCout << "[PISerial] set" << bname << " error: " << errorString();
piCoutObj << "[PISerial] set" << bname << " error: " << errorString();
return false;
}
return true;
#else
piCout << "[PISerial] set" << bname << " doesn`t implemented on Windows, sorry :-(";
piCoutObj << "[PISerial] set" << bname << " doesn`t implemented on Windows, sorry :-(";
return false;
#endif
}
@@ -121,15 +121,15 @@ bool PISerial::setBit(int bit, bool on, const PIString & bname) {
bool PISerial::isBit(int bit, const PIString & bname) const {
#ifndef WINDOWS
if (fd < 0) {
piCout << "[PISerial] is" << bname << " error: \"" << path_ << "\" is not opened!";
piCoutObj << "[PISerial] is" << bname << " error: \"" << path_ << "\" is not opened!";
return false;
}
int ret = 0;
if (ioctl(fd, TIOCMGET, &ret) < 0)
piCout << "[PISerial] is" << bname << " error: " << errorString();
piCoutObj << "[PISerial] is" << bname << " error: " << errorString();
return ret & bit;
#else
piCout << "[PISerial] set" << bname << " doesn`t implemented on Windows, sorry :-(";
piCoutObj << "[PISerial] set" << bname << " doesn`t implemented on Windows, sorry :-(";
return false;
#endif
}
@@ -301,7 +301,7 @@ bool PISerial::openDevice() {
if (isWriteable()) {ds |= GENERIC_WRITE; sm |= FILE_SHARE_WRITE;}
hCom = CreateFileA(path_.data(), ds, sm, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
if(hCom == INVALID_HANDLE_VALUE) {
piCout << "[PISerial] Unable to open \"" << path_ << "\"";
piCoutObj << "[PISerial] Unable to open \"" << path_ << "\"";
return false;
}
fd = 0;
@@ -312,7 +312,7 @@ bool PISerial::openDevice() {
times.WriteTotalTimeoutConstant = 1;
times.WriteTotalTimeoutMultiplier = 0;
if (SetCommTimeouts(hCom, &times) == -1) {
piCout << "[PISerial] Unable to set timeouts for \"" << path_ << "\"";
piCoutObj << "[PISerial] Unable to set timeouts for \"" << path_ << "\"";
CloseHandle(hCom);
fd = -1;
return false;
@@ -330,7 +330,7 @@ bool PISerial::openDevice() {
}
desc.StopBits = params[PISerial::TwoStopBits] ? TWOSTOPBITS : ONESTOPBIT;
if (SetCommState(hCom, &desc) == -1) {
piCout << "[PISerial] Unable to set comm state for \"" << path_ << "\"";
piCoutObj << "[PISerial] Unable to set comm state for \"" << path_ << "\"";
CloseHandle(hCom);
fd = -1;
return false;
@@ -345,7 +345,7 @@ bool PISerial::openDevice() {
//cout << "init ser " << path_ << " mode " << om << " param " << params << endl;
fd = ::open(path_.data(), O_NOCTTY | om);
if(fd == -1) {
piCout << "[PISerial] Unable to open \"" << path_ << "\"";
piCoutObj << "[PISerial] Unable to open \"" << path_ << "\"";
return false;
}
@@ -371,20 +371,20 @@ bool PISerial::openDevice() {
fcntl(fd, F_SETFL, 0);
if(tcsetattr(fd, TCSANOW, &desc) < 0) {
piCout << "[PISerial] Can`t set attributes for \"" << path_ << "\"";
piCoutObj << "[PISerial] Can`t set attributes for \"" << path_ << "\"";
::close(fd);
return false;
}
//piCout << "[PISerial] Initialized " << path_;
//piCoutObj << "[PISerial] Initialized " << path_;
#endif
return true;
}
int PISerial::write(const void * data, int max_size, bool wait) {
//piCout << "[PISerial] send " << max_size << ": " << PIString((char*)data, max_size);
//piCoutObj << "[PISerial] send " << max_size << ": " << PIString((char*)data, max_size);
if (fd == -1 || !canWrite()) {
//piCout << "[PISerial] Can`t write to uninitialized COM";
//piCoutObj << "[PISerial] Can`t write to uninitialized COM";
return -1;
}
#ifdef WINDOWS
@@ -402,6 +402,6 @@ int PISerial::write(const void * data, int max_size, bool wait) {
if (wait) tcdrain(fd);
#endif
return (int)wrote;
//piCout << "[PISerial] Error while sending";
//piCout << "[PISerial] Wrote " << wrote << " bytes in " << path_;
//piCoutObj << "[PISerial] Error while sending";
//piCoutObj << "[PISerial] Wrote " << wrote << " bytes in " << path_;
}

318
pistatemachine.h Normal file
View File

@@ -0,0 +1,318 @@
/*! \file pistatemachine.h
* \brief Base class for custom state machine
*/
/*
PIP - Platform Independent Primitives
State machine
Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PISTATEMACHINE_H
#define PISTATEMACHINE_H
#include "piobject.h"
/*! \brief Base class for custom state machine
*
* \section PIStateMachine_synopsis Synopsis
* This class provide functionality of state machine.
* You should inherit from this class, implement \a execution()
* and \a transition() functions, set rules and periodically
* call \a tick() function to proper work of machine.
*
* \section PIStateMachine_prepare Prepare for work
* %State machine operates with "state", "rule" and "condition".
* * "State" is some class (by default \c int), associated name and
* optional "handler" - pointer to function executed on every \a tick();
* * "Rule" define rule of transition from one machine state to other.
* It is also has optional "handler";
* * "Condition" is a part of rule and define possibility of transition.
*
* First of all you should define states of your machine by function
* \a addState(). Then you should define transition rules for machine
* by function \a addRule(). Finally you can set initial state by function
* \a setInitialState() and provide periodically execution of function
* \a tick().
*
* \section PIStateMachine_principle Principle of work
* At any time the state machine is in some state. You can ask machine
* to enter in new state by function \a switchToState(). If all conditions
* done machine switch it state immediately, else machine remember request
* and will be try switch to the new state every tick. Successfull state
* switching execute function \a transition(), every tick execute
* function \a execution() with current state. On successfull transition
* if rule "handler" is not null it execute. Every \a tick() if current
* state "handler" is not null it execute.
*
* \section PIStateMachine_conditions Conditions
* Each rule has transition condition. Condition is array of pairs
* (string, number). It means that every condition by name "string"
* should be performed as least "number" times. Empty condition always
* permits transition.
*
* %State machine have current performed conditions. You can read this
* conditions by function \a currentConditions() and perform new
* conditions by functions \a performCondition() and \a performConditions().
* Currend conditions can de erased by function \a resetConditions().
*
* \section PIStateMachine_example Example
* This is simple example demonstrates all features:
* \snippet pistatemachine.cpp main
*/
template <typename Type = int>
class PIP_EXPORT PIStateMachine: public PIObject
{
PIOBJECT(PIStateMachine)
public:
//! Constructs an empty state machine
PIStateMachine() {resetConditions();}
~PIStateMachine() {;}
//! %Condition is a pair (string, number)
typedef PIPair<PIString, int> Condition;
//! %Rule of transition between states of machine
struct Rule {
//! Constuctor
Rule() {;}
//! Constuctor
Rule(Type f, Type t, const PIStringList & c = PIStringList(), Handler h = 0, bool rac = false) {
from = f;
to = t;
for (int i = 0; i < c.size_s(); ++i)
conditions << Condition(c[i], 1);
resetAllConditions = rac;
handler = h;
}
//! Source state
Type from;
//! Destination state
Type to;
//! %Conditions of transition
PIVector<Condition> conditions;
//! Reset or not all performed conditions of machine on transition
bool resetAllConditions;
//! Pointer to function executed on transition
Handler handler;
//! Add condition of transition
void addCondition(const PIString & name, int times = 1) {if (times > 0) conditions << Condition(name, times);}
bool operator ==(const Rule & other) const {return (from == other.from) && (to == other.to);}
bool operator !=(const Rule & other) const {return (from != other.from) || (to != other.to);}
};
//! %State of machine
struct State {
//! Constuctor
State() {;}
//! Constuctor
State(Type v, const PIString & n = "", Handler h = 0) {value = v; name = n; handler = h;}
//! %State value
Type value;
//! %State name
PIString name;
//! Pointer to function executed on tick
Handler handler;
bool operator ==(const State & other) const {return value == other.value;}
bool operator !=(const State & other) const {return value != other.value;}
};
//! Add state of machine
void addState(Type value, const PIString & name = "", Handler handler = 0) {if (states_.contain(State(value, name))) return; states_ << State(value, name, handler);}
//! States count
int statesCount() const {return states_.size_s();}
//! Remove all states
void clearStates() {states_.clear();}
//! Add rule of transition
void addRule(Type from, Type to, const PIString & condition, Handler handler = 0, bool resetAllConditions = false) {if (rules_.contain(Rule(from, to))) return; rules_ << Rule(from, to, PIStringList(condition), handler, resetAllConditions);}
//! Add rule of transition
void addRule(Type from, Type to, Handler handler, bool resetAllConditions = false) {if (rules_.contain(Rule(from, to))) return; rules_ << Rule(from, to, PIStringList(), handler, resetAllConditions);}
//! Add rule of transition
void addRule(Type from, Type to, const PIStringList & conditions = PIStringList(), Handler handler = 0, bool resetAllConditions = false) {if (rules_.contain(Rule(from, to))) return; rules_ << Rule(from, to, conditions, handler, resetAllConditions);}
//! Add rule of transition
void addRule(const Rule & rule) {if (rules_.contain(rule)) return; rules_ << rule;}
//! Rules count
int rulesCount() const {return rules_.size_s();}
//! Remove all rules
void clearRules() {rules_.clear();}
//! Setup initial state. \a reset() will set machine state to "value"
void setInitialState(Type value) {
for (int i = 0; i < states_.size_s(); ++i)
if (states_[i].value == value) {
init_ = state_ = states_[i];
return;
}
}
/** \brief Try to switch machine state to state "to"
* \details If there is rule of transition exists and this rule conditions
* is performed then machine switched to new state immediately. Otherwise machine
* will be try to enter to new state every \a tick().
* \return \c true if state switched immediately, otherwise \c false */
bool switchToState(Type to) {
switch_to = to;
for (int i = 0; i < rules_.size_s(); ++i) {
Rule & r(rules_[i]);
if ((r.from != state_.value) || (r.to != to)) continue;
if (!checkConditions(r)) continue;
State ts = findState(to);
if (r.handler != 0) r.handler(this);
transition(state_, ts);
state_ = ts;
resetConditions(r);
return true;
}
return false;
}
//! Reset machine state to initial and clear all conditions
void reset() {state_ = init_; resetConditions();}
//! Returns current state of machine
const State & currentState() const {return state_;}
//! Reset all performed conditions
void resetConditions() {cond.clear();}
//! Reset performed condition with name "name"
void resetCondition(const PIString & name) {
for (int i = 0; i < cond.size_s(); ++i)
if (cond[i].first == name) {
cond.remove(i);
i--;
}
}
//! Perform condition with name "name" "times" times.
void performCondition(const PIString & name, int times = 1) {
if (times <= 0) return;
for (int i = 0; i < cond.size_s(); ++i)
if (cond[i].first == name) {
cond[i].second += times;
return;
}
cond << Condition(name, times);
}
//! Perform every condition with name from "names" one time.
void performConditions(const PIStringList & names) {
bool ok;
for (int n = 0; n < names.size_s(); ++n) {
ok = false;
for (int i = 0; i < cond.size_s(); ++i) {
if (cond[i].first == names[n]) {
cond[i].second++;
ok = true;
break;
}
}
if (ok) continue;
cond << Condition(names[n], 1);
}
}
//! Returns all current performed conditions
const PIVector<Condition> & currentConditions() const {return cond;}
Type * currentState_ptr() {return &state_.value;}
int * conditionsCount_ptr() {static int c = 0; c = cond.size_s(); return &c;}
//! \handlers
//! \{
//! \fn void tick()
//! \brief Main function of machine. Execute \a execution() and check if need to switch state
//! \fn void tick(void * data, int delim)
//! \brief Main function of machine. Execute \a execution() and check if need to switch state
//! \}
EVENT_HANDLER(void, tick) {tick(0, 0);}
EVENT_HANDLER2(void, tick, void * , data, int, delim) {
if (switch_to != state_.value) switchToState(switch_to);
execution(state_);
if (state_.handler != 0) state_.handler(this);
}
protected:
//! Reimplement this function to process current state of machine
virtual void execution(const State & state) {;}
//! Reimplement this function to process switching current state of machine
virtual void transition(const State & from, const State & to) {;}
private:
State findState(Type value) {
for (int i = 0; i < states_.size_s(); ++i)
if (states_[i].value == value)
return states_[i];
return State();
}
bool checkConditions(const Rule & rule) {
//if (cond.size_s() < rule.conditions.size_s()) return false;
int oc = 0;
for (int i = 0; i < cond.size_s(); ++i) {
PIString & rn(cond[i].first);
for (int j = 0; j < rule.conditions.size_s(); ++j) {
if (rn != rule.conditions[j].first) continue;
if (cond[i].second < rule.conditions[j].second) return false;
oc++;
}
}
return (rule.conditions.size_s() == oc);
}
void resetConditions(const Rule & rule) {
if (rule.resetAllConditions) {
cond.clear();
return;
}
for (int i = 0; i < cond.size_s(); ++i) {
PIString & rn(cond[i].first);
for (int j = 0; j < rule.conditions.size_s(); ++j) {
if (rn != rule.conditions[j].first) continue;
cond[i].second -= rule.conditions[j].second;
if (cond[i].second <= 0) {
cond.remove(i);
i--;
}
}
}
}
PIVector<State> states_;
PIVector<Rule> rules_;
State init_, state_;
Type switch_to;
PIVector<Condition> cond;
};
#endif // PISTATEMACHINE_H

View File

@@ -249,10 +249,10 @@ PIString & PIString::cutMid(const int start, const int len) {
PIString & PIString::trim() {
int st = 0, fn = 0;
for (int i = 0; i < length(); ++i)
if (at(i) != ' ' && at(i) != '\t')
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r')
{st = i; break;}
for (int i = length() - 1; i >= 0; --i)
if (at(i) != ' ' && at(i) != '\t')
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r')
{fn = i; break;}
*this = mid(st, fn - st + 1);
return *this;
@@ -262,10 +262,10 @@ PIString & PIString::trim() {
PIString PIString::trimmed() const {
int st = 0, fn = 0;
for (int i = 0; i < length(); ++i)
if (at(i) != ' ' && at(i) != '\t')
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r')
{st = i; break;}
for (int i = length() - 1; i >= 0; --i)
if (at(i) != ' ' && at(i) != '\t')
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r')
{fn = i; break;}
return mid(st, fn - st + 1);
}
@@ -293,7 +293,7 @@ PIString & PIString::replace(const PIString & what, const PIString & with, bool
PIString & PIString::replaceAll(const PIString & what, const PIString & with) {
if (what.isEmpty()) return *this;
if (what.isEmpty() || what == with) return *this;
bool ok = true;
while (ok) replace(what, with, &ok);
return *this;
@@ -356,6 +356,152 @@ int PIString::findLast(const PIString str, const int start) const {
}
PIString PIString::takeSymbol() {
PIString ret;
int sz = size_s(), ss = -1;
for (int i = 0; i < sz; ++i) {
PIChar c = at(i);
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
continue;
ss = i;
break;
}
if (ss < 0) return ret;
ret = mid(ss, 1);
cutLeft(ss + 1);
return ret;
}
PIString PIString::takeWord() {
int sz = size_s(), ws = -1, we = -1;
for (int i = 0; i < sz; ++i) {
PIChar c = at(i);
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
if (we < 0 && ws >= 0) we = i;
} else {
if (ws < 0) ws = i;
if (we >= 0) break;
}
}
PIString ret = mid(ws, we - ws);
cutLeft(we < 0 ? sz : we);
return ret;
}
PIString PIString::takeLine() {
int sz = size_s(), le = -1;
for (int i = 0; i < sz; ++i) {
PIChar c = at(i);
if (c == '\n') {
le = i;
break;
}
}
PIString ret = left(le);
if (!ret.isEmpty())
if (ret.back() == '\r')
ret.cutRight(1);
cutLeft(le < 0 ? sz : le + 1);
return ret;
}
PIString PIString::takeNumber() {
PIString ret;
int sz = size_s(), ls = -1, le = -1, phase = 0;
for (int i = 0; i < sz; ++i) {
if (phase > 7) break;
PIChar c = at(i);
//piCout << "char " << c << "phase" << phase;
switch (phase) {
case 0: // trim
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
continue;
phase = 7;
case 7: // sign
if (c == '-' || c == '+') {ls = i; phase = 1; break;}
case 1: // search start
if (c >= '0' && c <= '9') {le = i; if (ls < 0) ls = i; phase = 2; break;}
if (c == '.') {le = i; if (ls < 0) ls = i; phase = 3; break;}
phase = 9;
break;
case 2: // integer
if (c == '.') {le = i; phase = 3; break;}
if (c == 'e' || c == 'E') {le = i; phase = 4; break;}
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || c == 'x') {le = i; break;}
phase = 6;
break;
case 3: // point
if (c == 'e' || c == 'E') {le = i; phase = 4; break;}
if (c >= '0' && c <= '9') {le = i; break;}
phase = 6;
break;
case 4: // exp
if ((c >= '0' && c <= '9') || c == '-' || c == '+') {le = i; phase = 5; break;}
phase = 6;
break;
case 5: // power
if (c >= '0' && c <= '9') {le = i; break;}
phase = 6;
break;
case 6: // suffix
if (c == 'f' || c == 's' || c == 'u' || c == 'l' || c == 'L') {le = i; break;}
phase = 9;
break;
}
if (phase == 6) {
if (c == 'f' || c == 's' || c == 'u' || c == 'l' || c == 'L') le = i;
else phase = 9;
}
}
//piCout << ls << le;
if (le < ls) return ret;
ret = mid(ls, le - ls + 1);
cutLeft(le + 1);
return ret;
}
PIString PIString::takeRange(const PIChar & start, const PIChar & end, const PIChar & shield) {
PIString ret;
bool trim_ = (start != ' ' && start != '\t' && start != '\n' && start != '\r'), eq = (start == end);
int sz = size_s(), ls = -1, le = -1, cnt = 0;
for (int i = 0; i < sz; ++i) {
PIChar c = at(i);
if (c == shield) {++i; continue;}
if (trim_) {
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
continue;
trim_ = false;
}
if (eq) {
if (c == start) {
if (cnt == 0) ls = i;
else {le = i; cnt = 0; break;}
cnt++;
}
} else {
if (c == start) {
if (cnt == 0) ls = i;
cnt++;
}
if (c == end) {
cnt--;
if (cnt == 0) le = i;
}
}
if (cnt <= 0) break;
}
//piCout << ls << le << cnt;
if (le < ls || ls < 0 || le < 0 || cnt != 0) return ret;
ret = mid(ls + 1, le - ls - 1);
cutLeft(le + 1);
return ret;
}
PIString PIString::toUpperCase() const {
PIString str(*this);
int l = str.size();

View File

@@ -86,7 +86,7 @@ public:
PIString(const int len, const PIChar & c) {reserve(256); piMonitor.strings++; piMonitor.containers--; for (int i = 0; i < len; ++i) push_back(c);}
//! Contructs string from other string "str"
PIString(const PIString & str) {reserve(256); piMonitor.strings++; piMonitor.containers--; *this += str;}
PIString(const PIString & str) {reserve(256); piMonitor.strings++; piMonitor.containers--; uint len = str.size(); for (uint i = 0; i < len; ++i) push_back(str[i]);}
~PIString() {piMonitor.strings--; piMonitor.containers++;}
@@ -340,12 +340,40 @@ public:
* \details Example: \snippet pistring.cpp PIString::reversed
* \sa \a reverse() */
PIString reversed() const {PIString str(*this); str.reverse(); return str;}
/*! \brief Take a symbol from the begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeSymbol
* \sa \a \a takeWord(), takeLine(), \a takeNumber(), \a takeRange() */
PIString takeSymbol();
/*! \brief Take a word from the begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeWord
* \sa \a takeSymbol(), \a takeLine(), \a takeNumber(), \a takeRange() */
PIString takeWord();
/*! \brief Take a line from the begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeLine
* \sa \a takeSymbol(), \a takeWord(), \a takeNumber(), \a takeRange() */
PIString takeLine();
/*! \brief Take a number with C-format from the begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeNumber
* \sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeRange() */
PIString takeNumber();
/*! \brief Take a range between "start" and "end" symbols from the begin of this
* string and return it.
* \details "Shield" symbol prevent analysis of the next symbol.
* Example: \snippet pistring.cpp PIString::takeRange
* \sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber() */
PIString takeRange(const PIChar & start, const PIChar & end, const PIChar & shield = '\\');
//const char * data() {return convertToStd().c_str();}
/*! \brief Return real bytes count of this string
* \details It`s equivalent length os char sequence
* \details It`s equivalent length of char sequence
* returned by function \a data() \n
* Example: \snippet pistring.cpp PIString::lengthAscii
* \sa \a data() */
@@ -353,7 +381,7 @@ public:
/*! \brief Return \c char * representation of this string
* \details This function fill buffer by sequence
* of chars. Minimum length of this buffer is count
* of chars. Minimum length of this buffer is count
* of symbols. Returned \c char * is valid until next
* execution of this function.\n
* Example: \snippet pistring.cpp PIString::data
@@ -645,10 +673,10 @@ inline PICout operator <<(PICout s, const PIString & v) {s.space(); s.quote(); s
//! \relatesalso PIString \relatesalso PIByteArray \brief Output operator to PIByteArray
inline PIByteArray & operator <<(PIByteArray & s, const PIString & v) {s << v.size_s(); for (int i = 0; i < v.length(); ++i) s << v[i]; return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIString & v) {int l = v.lengthAscii(); s << l; if (l <= 0) return s; int os = s.size_s(); s.enlarge(l); memcpy(s.data(os), v.data(), l); return s;}
//! \relatesalso PIString \relatesalso PIByteArray \brief Input operator from PIByteArray
inline PIByteArray & operator >>(PIByteArray & s, PIString & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIString & v) {int l; s >> l; if (l <= 0) return s; v = PIString((const char * )s.data(), l); s.remove(0, l); return s;}
//! \relatesalso PIString \brief Return concatenated string
@@ -728,6 +756,14 @@ public:
};
//! \relatesalso PIStringList \relatesalso PIByteArray \brief Output operator to PIByteArray
inline PIByteArray & operator <<(PIByteArray & s, const PIStringList & v) {s << v.size_s(); for (int i = 0; i < v.size_s(); ++i) s << v[i]; return s;}
//! \relatesalso PIStringList \relatesalso PIByteArray \brief Input operator from PIByteArray
inline PIByteArray & operator >>(PIByteArray & s, PIStringList & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
//! \relatesalso PIStringList \brief Output operator to std::ostream (cout)
inline std::ostream & operator <<(std::ostream & s, const PIStringList & v) {s << "{"; for (uint i = 0; i < v.size(); ++i) {s << '\"' << v[i] << '\"'; if (i < v.size() - 1) s << ", ";} s << "}"; return s;}

View File

@@ -42,7 +42,7 @@ bool PISystemMonitor::startOnProcess(int pID) {
file.open("/proc/" + PIString::fromNumber(pID_) + "/stat", PIIODevice::ReadOnly);
filem.open("/proc/" + PIString::fromNumber(pID_) + "/statm", PIIODevice::ReadOnly);
if (!file.isOpened()) {
piCout << "[PISystemMonitor] Can`t find process with ID = " << pID_ << "!";
piCoutObj << "[PISystemMonitor] Can`t find process with ID = " << pID_ << "!";
return false;
}
cycle = -1;

View File

@@ -174,7 +174,7 @@ void PITimer::start(double msecs) {
ti = timer_create(CLOCK_REALTIME, &se, &timer);
//cout << "***create timer " << msecs << " msecs\n";
if (ti == -1) {
piCout << "[PITimer] Can`t create timer for " << msecs << " msecs: " << errorString();
piCoutObj << "[PITimer] Can`t create timer for " << msecs << " msecs: " << errorString();
return;
}
timer_settime(timer, 0, &spec, 0);
@@ -192,7 +192,7 @@ void PITimer::deferredStart(double interval_msecs, double delay_msecs) {
ti = timer_create(CLOCK_REALTIME, &se, &timer);
//cout << "***create timer\n";
if (ti == -1) {
piCout << "[PITimer] Can`t create timer for " << interval_msecs << " msecs: " << errorString();
piCoutObj << "[PITimer] Can`t create timer for " << interval_msecs << " msecs: " << errorString();
return;
}
timer_settime(timer, 0, &spec, 0);
@@ -218,7 +218,7 @@ void PITimer::deferredStart(double interval_msecs, const PIDateTime & start_date
ti = timer_create(CLOCK_REALTIME, &se, &timer);
//cout << "***create timer\n";
if (ti == -1) {
piCout << "[PITimer] Can`t create timer for " << interval_msecs << " msecs: " << errorString();
piCoutObj << "[PITimer] Can`t create timer for " << interval_msecs << " msecs: " << errorString();
return;
}
timer_settime(timer, TIMER_ABSTIME, &spec, 0);
@@ -246,7 +246,7 @@ void PITimer::TimerPool::begin() {
sa.sa_handler = empty_handler;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGALRM, &sa, 0) == -1) {
piCout << "[PITimer] sigaction error: " << errorString();
piCoutObj << "[PITimer] sigaction error: " << errorString();
stop();
return;
}*/
@@ -260,12 +260,12 @@ void PITimer::TimerPool::begin() {
spec.it_value = spec.it_interval;
//cout << "***create pool timer\n";
if (timer_create(CLOCK_REALTIME, &se, &timer) == -1) {
piCout << "[PITimer] Can`t create timer for pool: " << errorString();
piCoutObj << "[PITimer] Can`t create timer for pool: " << errorString();
stop();
return;
}
if (timer_settime(timer, 0, &spec, 0) == -1) {
piCout << "[PITimer] Can`t set timer for pool: " << errorString();
piCoutObj << "[PITimer] Can`t set timer for pool: " << errorString();
stop();
return;
}
@@ -358,7 +358,7 @@ void PITimer::start(double msecs) {
void PITimer::deferredStart(double interval_msecs, double delay_msecs) {
//piCout << "defStart exec with" << delay_msecs << interval_msecs;
//piCoutObj << "defStart exec with" << delay_msecs << interval_msecs;
if (interval_msecs < 0 || running_) return;
interval_ = interval_msecs;
PISystemTime cst = currentSystemTime();
@@ -367,12 +367,12 @@ void PITimer::deferredStart(double interval_msecs, double delay_msecs) {
if (st_time < cst) st_time = cst;
running_ = deferred_ = true;
PIThread::start();
//piCout << "timer start def";
//piCoutObj << "timer start def";
}
void PITimer::deferredStart(double interval_msecs, const PIDateTime & start_datetime) {
//piCout << "defStart exec to" << start_datetime.toString() << interval_msecs;
//piCoutObj << "defStart exec to" << start_datetime.toString() << interval_msecs;
if (interval_msecs < 0 || running_) return;
interval_ = interval_msecs;
PISystemTime cst = currentSystemTime();
@@ -381,7 +381,7 @@ void PITimer::deferredStart(double interval_msecs, const PIDateTime & start_date
if (st_time < cst) st_time = cst;
running_ = deferred_ = true;
PIThread::start();
//piCout << "timer start def";
//piCoutObj << "timer start def";
}
@@ -621,6 +621,7 @@ PIDateTime currentDateTime() {
time_t rt = time(0);
tm * pt = localtime(&rt);
PIDateTime dt;
dt.milliseconds = 0;
dt.seconds = pt->tm_sec;
dt.minutes = pt->tm_min;
dt.hours = pt->tm_hour;

View File

@@ -190,6 +190,11 @@ public:
void removeDelimiter(int delim) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].delim == delim) {ret_funcs.remove(i); i--;}}
void removeDelimiter(TimerEvent slot) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].slot == slot) {ret_funcs.remove(i); i--;}}
void removeDelimiter(int delim, TimerEvent slot) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].slot == slot && ret_funcs[i].delim == delim) {ret_funcs.remove(i); i--;}}
void setDelimiterValue(int delim, int value) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].delim == delim) ret_funcs[i].tick = value;}
void setDelimiterValue(TimerEvent slot, int value) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].slot == slot) ret_funcs[i].tick = value;}
void setDelimiterValue(int delim, TimerEvent slot, int value) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].slot == slot && ret_funcs[i].delim == delim) ret_funcs[i].tick = value;}
int delimiterValue(int delim) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].delim == delim) return ret_funcs[i].tick; return -1;}
int delimiterValue(int delim, TimerEvent slot) {for (int i = 0; i < ret_funcs.size_s(); ++i) if (ret_funcs[i].slot == slot && ret_funcs[i].delim == delim) return ret_funcs[i].tick; return -1;}
EVENT_HANDLER0(void, clearDelimiters) {ret_funcs.clear();}
double elapsed_n(); // nanoseconds

357
piusb.cpp Normal file
View File

@@ -0,0 +1,357 @@
#include "piusb.h"
#ifdef PIP_USB
# ifdef WINDOWS
# include <lusb0_usb.h>
# else
# include <usb.h>
# endif
#endif
PIUSB::PIUSB(ushort vid, ushort pid): PIIODevice("", ReadWrite, false) {
vid_ = vid;
pid_ = pid;
path_ = PIString::fromNumber(vid_, 16).expandLeftTo(4, "0") + ":" + PIString::fromNumber(pid_, 16).expandLeftTo(4, "0");
dev_num = 1;
intefrace_ = 0;
hdev = 0;
interface_claimed = -1;
timeout_r = timeout_w = 1000;
}
void PIUSB::Endpoint::parse() {
direction = Write;
transfer_type = Control;
synchronisation_type = NoSynchonisation;
usage_type = DataEndpoint;
direction = (Direction)((address >> 7) & 1);
transfer_type = (TransferType)(attributes & 3);
if (transfer_type == Isochronous) {
synchronisation_type = (SynchronisationType)((attributes >> 2) & 3);
usage_type = (UsageType)((attributes >> 4) & 3);
}
}
PIUSB::Endpoint PIUSB::getEndpointByAddress(uchar address) {
piForeachC (Endpoint & i, eps)
if (i.address == address)
return i;
return Endpoint();
}
PIVector<PIUSB::Endpoint> PIUSB::endpointsRead() {
PIVector<Endpoint> ret;
piForeachC (Endpoint & i, eps)
if (i.direction == Endpoint::Read)
ret << i;
return ret;
}
PIVector<PIUSB::Endpoint> PIUSB::endpointsWrite() {
PIVector<Endpoint> ret;
piForeachC (Endpoint & i, eps)
if (i.direction == Endpoint::Write)
ret << i;
return ret;
}
bool PIUSB::setConfiguration(uchar value) {
#ifdef PIP_USB
if (hdev == 0) return false;
bool found = false;
piForeachC (Configuration & c, desc_.configurations)
if (c.value_to_select == value) {found = true; conf_ = c; break;}
if (!found) {
piCoutObj << "[PIUSB] Can`t find configuration with \"value_to_select\" =" << value;
return false;
}
if (interface_claimed >= 0)
usb_release_interface(hdev, interface_claimed);
interface_claimed = -1;
return setInterface(conf_.interfaces.front().value_to_select);
#else
return false;
#endif
}
bool PIUSB::setInterface(uchar value) {
#ifdef PIP_USB
if (hdev == 0) return false;
bool found = false;
piForeachC (Interface & i, conf_.interfaces)
if (i.value_to_select == value) {found = true; iface_ = i; break;}
if (!found) {
piCoutObj << "[PIUSB] Can`t find interface with \"value_to_select\" =" << value;
return false;
}
if (interface_claimed >= 0)
usb_release_interface(hdev, interface_claimed);
interface_claimed = -1;
if (usb_claim_interface(hdev, iface_.value_to_select) < 0) {
piCoutObj << "[PIUSB] Error: Cant`t claim interface!";
return false;
}
eps.clear();
eps = iface_.endpoints;
ep_read = ep_write = Endpoint();
for (int i = 0; i < eps.size_s(); ++i) {
if (eps[i].direction == Endpoint::Read && ep_read.isNull())
ep_read = eps[i];
if (eps[i].direction == Endpoint::Write && ep_write.isNull())
ep_write = eps[i];
}
interface_claimed = value;
return true;
#else
return false;
#endif
}
bool PIUSB::openDevice() {
#ifdef PIP_USB
if (path_.size_s() >= 8) {
vid_ = path_.left(4).toInt(16);
pid_ = path_.right(4).toInt(16);
}
if (hdev != 0) closeDevice();
hdev = 0;
interface_claimed = -1;
ep_write = ep_read = Endpoint();
usb_init();
//usb_set_debug(4);
if (usb_find_busses() < 0) {
piCoutObj << "[PIUSB] Error: Cant`t find busses!";
return false;
}
if (usb_find_devices() < 0) {
piCoutObj << "[PIUSB] Error: Cant`t find devices!";
return false;
}
//piCoutObj << "[PIUSB] Search for device ... " << flush;
int cur_num = 1;
bool found = false;
struct usb_device * dev;
struct usb_bus * bus;
for (bus = usb_get_busses(); bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
if (dev->descriptor.idVendor == vid_ && dev->descriptor.idProduct == pid_) {
if (cur_num == dev_num) {
struct usb_device_descriptor & dd(dev->descriptor);
desc_.usb_spec_number = dd.bcdUSB;
desc_.device_class = dd.bDeviceClass;
desc_.device_subclass = dd.bDeviceSubClass;
desc_.device_protocol = dd.bDeviceProtocol;
desc_.max_packet_size = dd.bMaxPacketSize0;
desc_.id_vendor = dd.idVendor;
desc_.id_product = dd.idProduct;
desc_.id_device_release = dd.bcdDevice;
desc_.index_manufacturer = dd.iManufacturer;
desc_.index_product = dd.iProduct;
desc_.index_serial = dd.iSerialNumber;
desc_.configurations.clear();
for (int c = 0; c < dd.bNumConfigurations; ++c) {
desc_.configurations << Configuration();
Configuration & conf(desc_.configurations.back());
struct usb_config_descriptor & dc(dev->config[c]);
conf.index = c;
conf.value_to_select = dc.bConfigurationValue;
conf.attributes = dc.bmAttributes;
conf.max_power = ushort(dc.MaxPower) * 2;
conf.self_powered = (conf.attributes >> 6) & 1;
conf.remote_wakeup = (conf.attributes >> 5) & 1;
conf.interfaces.clear();
for (int i = 0; i < dc.bNumInterfaces; ++i) {
conf.interfaces << Interface();
Interface & infc(conf.interfaces.back());
struct usb_interface_descriptor * di(dc.interface[c].altsetting);
infc.index = i;
infc.value_to_select = di->bAlternateSetting;
infc.class_code = di->bInterfaceClass;
infc.subclass_code = di->bInterfaceSubClass;
infc.protocol_code = di->bInterfaceProtocol;
infc.endpoints.clear();
for (int e = 0; e < di->bNumEndpoints; ++e) {
infc.endpoints << Endpoint(di->endpoint[e].bEndpointAddress,
di->endpoint[e].bmAttributes,
di->endpoint[e].wMaxPacketSize);
}
}
}
if (!desc_.configurations.isEmpty())
conf_ = desc_.configurations.front();
struct usb_interface_descriptor * is = dev->config->interface->altsetting;
int epn = is->bNumEndpoints;
eps.clear();
for (int i = 0; i < epn; ++i) {
eps << Endpoint(is->endpoint[i].bEndpointAddress,
is->endpoint[i].bmAttributes,
is->endpoint[i].wMaxPacketSize);
if (eps.back().direction == Endpoint::Write && ep_write.address == 0) ep_write = eps.back();
if (eps.back().direction == Endpoint::Read && ep_read.address == 0) ep_read = eps.back();
}
//piCoutObj << "[PIUSB] Device found at address:" << "Bus: " << dev->bus->dirname << ", Device: " << dev->filename;
found = true;
break;
} else cur_num++;
}
}
if (found) break;
}
if (!found) {
piCoutObj << "[PIUSB] Error: Cant`t find device!";
return false;
}
//piCoutObj << "[PIUSB] Open ... " << flush;
hdev = usb_open(dev);
if (hdev == 0) {
piCoutObj << "[PIUSB] Error: Cant`t open device:" << usb_strerror();
return false;
}// else piCoutObj << "[PIUSB] ok";
//usb_reset(hdev);
//usb_set_configuration(hdev, 1);
//usb_set_altinterface(hdev, 0);
# ifndef WINDOWS
char tbuff[256];
//piCoutObj << "[PIUSB] Check for bounded driver ... " << flush;
if (usb_get_driver_np(hdev, intefrace_, tbuff, sizeof(tbuff) - 1) >= 0) {
//piCoutObj << "[PIUSB] yes" << "Found driver: " << tbuff;
//piCoutObj << "[PIUSB] Detach driver ... " << flush;
if (usb_detach_kernel_driver_np(hdev, intefrace_)< 0) {
piCoutObj << "[PIUSB] Error: Cant`t detach bounded driver!";
return false;
}// else piCoutObj << "[PIUSB] ok";
}// else piCoutObj << "[PIUSB] no";
# endif
//piCoutObj << "[PIUSB] Claim interface ... " << flush;
if (usb_claim_interface(hdev, intefrace_) < 0) {
piCoutObj << "[PIUSB] Error: Cant`t claim interface:" << usb_strerror();
return false;
} // else piCoutObj << "[PIUSB] ok";
interface_claimed = intefrace_;
return true;
#else
return false;
#endif
}
bool PIUSB::closeDevice() {
#ifdef PIP_USB
if (hdev == 0) return true;
//usb_reset(hdev);
usb_release_interface(hdev, intefrace_);
usb_close(hdev);
hdev = 0;
interface_claimed = -1;
return true;
#else
return false;
#endif
}
int PIUSB::read(void * read_to, int max_size) {
#ifdef PIP_USB
if (!opened_ || ep_read.isNull()) return -1;
switch (ep_read.transfer_type) {
case Endpoint::Bulk: /*piCoutObj << "bulk read" << max_size;*/ return usb_bulk_read(hdev, ep_read.address, (char * )read_to, max_size, timeout_r); break;
case Endpoint::Interrupt: return usb_interrupt_read(hdev, ep_read.address, (char * )read_to, max_size, timeout_r); break;
default: break;
}
return -1;
#else
return -1;
#endif
}
int PIUSB::write(const void * data, int max_size) {
#ifdef PIP_USB
if (!opened_ || ep_write.isNull()) return -1;
switch (ep_read.transfer_type) {
case Endpoint::Bulk: /*piCoutObj << "bulk write" << max_size;*/ return usb_bulk_write(hdev, ep_write.address, (char * )const_cast<void * >(data), max_size, timeout_w); break;
case Endpoint::Interrupt: return usb_interrupt_write(hdev, ep_read.address, (char * )data, max_size, timeout_w); break;
default: break;
}
return -1;
#else
return -1;
#endif
}
int PIUSB::controlWrite(const void * data, int max_size) {
#ifdef PIP_USB
if (!opened_) return -1;
//return usb_control_msg(hdev, );
return -1;
#else
return -1;
#endif
}
void PIUSB::flush() {
#ifdef PIP_USB
if (!opened_) return;
if (!ep_read.isNull()) usb_resetep(hdev, ep_read.address);
if (!ep_write.isNull()) usb_resetep(hdev, ep_write.address);
#endif
}
PICout operator<<(PICout s, const PIUSB::Endpoint & v) {
s.setControl(0, true);
s << NewLine << "{" << NewLine;
if (v.isNull())
s << " " << "Null Endpoint";
else {
s << " " << "Address: " << v.address << NewLine;
s << " " << "Attributes: " << v.attributes << NewLine;
s << " " << "Direction: " << (v.direction == PIUSB::Endpoint::Write ? "Write" : "Read") << NewLine;
s << " " << "Transfer Type: ";
switch (v.transfer_type) {
case PIUSB::Endpoint::Control: s << "Control" << NewLine; break;
case PIUSB::Endpoint::Bulk: s << "Bulk" << NewLine; break;
case PIUSB::Endpoint::Interrupt: s << "Interrupt" << NewLine; break;
case PIUSB::Endpoint::Isochronous: s << "Isochronous" << NewLine; break;
default: break;
}
if (v.transfer_type == PIUSB::Endpoint::Isochronous) {
s << " " << "Synchronisation Type: ";
switch (v.synchronisation_type) {
case PIUSB::Endpoint::NoSynchonisation: s << "No Synchonisation" << NewLine; break;
case PIUSB::Endpoint::Asynchronous: s << "Asynchronous" << NewLine; break;
case PIUSB::Endpoint::Adaptive: s << "Adaptive" << NewLine; break;
case PIUSB::Endpoint::Synchronous: s << "Synchronous" << NewLine; break;
default: break;
}
s << " " << "Usage Type: ";
switch (v.usage_type) {
case PIUSB::Endpoint::DataEndpoint: s << "Data Endpoint" << NewLine; break;
case PIUSB::Endpoint::FeedbackEndpoint: s << "Feedback Endpoint" << NewLine; break;
case PIUSB::Endpoint::ExplicitFeedbackDataEndpoint: s << "Explicit Feedback Data Endpoint" << NewLine; break;
default: break;
}
}
s << " " << "Max Packet Size: " << v.max_packet_size << NewLine;
}
s << "}" << NewLine;
s.restoreControl();
return s;
}

137
piusb.h Normal file
View File

@@ -0,0 +1,137 @@
/*
PIP - Platform Independent Primitives
USB, based on libusb
Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIUSB_H
#define PIUSB_H
#include "piiodevice.h"
struct usb_dev_handle;
class PIP_EXPORT PIUSB: public PIIODevice {
public:
PIUSB(ushort vid = 0, ushort pid = 0);
struct Endpoint {
Endpoint(uchar a = 0, uchar at = 0, ushort mps = 0) {address = a; attributes = at; max_packet_size = mps; parse();}
enum Direction {Write = 0, Read = 1};
enum TransferType {Control = 0, Isochronous = 1, Bulk = 2, Interrupt = 3};
enum SynchronisationType {NoSynchonisation= 0, Asynchronous = 2, Adaptive = 1, Synchronous = 3};
enum UsageType {DataEndpoint = 0, FeedbackEndpoint = 2, ExplicitFeedbackDataEndpoint = 1};
void parse();
bool isNull() const {return address == 0;}
uchar address;
uchar attributes;
ushort max_packet_size;
Direction direction;
TransferType transfer_type;
SynchronisationType synchronisation_type;
UsageType usage_type;
};
struct Interface {
Interface() {index = value_to_select = class_code = subclass_code = protocol_code = 0;}
uchar index;
uchar value_to_select;
ushort class_code;
ushort subclass_code;
ushort protocol_code;
PIVector<Endpoint> endpoints;
};
struct Configuration {
Configuration() {index = value_to_select = attributes = max_power = 0; self_powered = remote_wakeup = false;}
uchar index;
uchar value_to_select;
uchar attributes;
ushort max_power; // mA
bool self_powered;
bool remote_wakeup;
PIVector<Interface> interfaces;
};
struct Descriptor {
Descriptor() {memset(this, 0, sizeof(Descriptor));}
ushort usb_spec_number;
uchar device_class;
uchar device_subclass;
uchar device_protocol;
uchar max_packet_size;
ushort id_vendor;
ushort id_product;
ushort id_device_release;
uchar index_manufacturer;
uchar index_product;
uchar index_serial;
PIVector<Configuration> configurations;
};
const Descriptor & currentDescriptor() const {return desc_;}
const Configuration & currentConfiguration() const {return conf_;}
const Interface & currentInterface() const {return iface_;}
ushort vendorID() const {return vid_;}
ushort productID() const {return pid_;}
const PIVector<Endpoint> & endpoints() const {return eps;}
PIVector<Endpoint> endpointsRead();
PIVector<Endpoint> endpointsWrite();
Endpoint getEndpointByAddress(uchar address);
const Endpoint & endpointRead() {return ep_read;}
const Endpoint & endpointWrite() {return ep_write;}
bool setConfiguration(uchar value);
bool setInterface(uchar value);
void setEndpointRead(const Endpoint & ep) {ep_read = ep;}
void setEndpointWrite(const Endpoint & ep) {ep_write = ep;}
void setDeviceNumber(int dn) {dev_num = dn;}
void setTimeoutRead(int t) {timeout_r = t;}
void setTimeoutWrite(int t) {timeout_w = t;}
int read(void * read_to, int max_size);
int write(const void * data, int max_size);
int controlWrite(const void * data, int max_size);
void flush();
protected:
//bool init();
bool openDevice();
bool closeDevice();
PIVector<Endpoint> eps;
ushort vid_, pid_;
int dev_num, intefrace_, timeout_r, timeout_w;
int interface_claimed;
Endpoint ep_read, ep_write;
Descriptor desc_;
Configuration conf_;
Interface iface_;
usb_dev_handle * hdev;
};
PICout operator <<(PICout s, const PIUSB::Endpoint & v);
#endif // PIUSB_H

View File

@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 2.6)
include_directories(${CMAKE_CURRENT_SOURCE_DIR} . ../)
file(GLOB CPPS "*.cpp")
add_definitions(-Wall -O2)
add_executable(pip_remote_console "main.cpp")
target_link_libraries(pip_remote_console pip)

66
remote_console/main.cpp Normal file
View File

@@ -0,0 +1,66 @@
/*
PIP - Platform Independent Primitives
Remote console viewer
Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pip.h"
void key_event(char key, void * );
PIConsole console(false, key_event);
PIStringList as;
bool selected = false;
void key_event(char key, void * ) {
if (key < '1' || key > '9') return;
int ind = key - '1';
if (ind < 0 || ind >= as.size_s()) return;
selected = true;
console.connectToServer(as[ind]);
console.clearScreen();
piCout << "Connecting to" << console.selectedServer() << "...";
}
int main(int argc, char * argv[]) {
console.enableExitCapture();
console.listenServers();
while (!PIKbdListener::exiting) {
msleep(200);
if (selected) break;
console.clearScreen();
as = console.availableServers();
if (as.isEmpty()) {
piCout << "No servers are available!";
} else {
piCout << "Select one with numeric key:";
for (int i = 0; i < as.size_s(); ++i)
piCout << (i + 1) << as[i];
}
}
if (!selected) return 0;
console.clearScreen();
piCout << "Connecting to" << console.selectedServer() << "...";
while (!PIKbdListener::exiting) {
msleep(20);
if (console.isConnected())
break;
}
if (PIKbdListener::exiting)
return 0;
console.start();
console.waitForFinish();
};