diff --git a/.gitignore b/.gitignore index a100be6..193d43b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,328 @@ build *.vcproj CMakeFiles *.dir + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f1398bb --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "cppunit"] + path = cppunit + url = https://anongit.freedesktop.org/git/libreoffice/cppunit +[submodule "date"] + path = date + url = https://github.com/HowardHinnant/date.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d703ac9 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.7 FATAL_ERROR) #This minimum version is to support Visual Studio 2017 and C++ feature checking + +project(adapters) + +# All of the C++ code and CppUnit require C++ 11 features to compile. +# We will define these properties by default for each CMake target to be created. +set_property(GLOBAL PROPERTY CXX_STANDARD 11) +set_property(GLOBAL PROPERTY CXX_STANDARD_REQUIRED ON) + +# By default only generate 2 configurations (Debug and Release) for simplicity. +# The user can change this option if required for the additional ones such as 'RelWithDebInfo'. +set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configs" FORCE) +if(DEFINED CMAKE_BUILD_TYPE) + set_property( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${CMAKE_CONFIGURATION_TYPES} ) +endif() + +# Add our './cmake' sub-folder to the lists searched when calling functions +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") + +# Setup compiler options for Windows, OSX, Linux (each file guards against usage on an inappropriate platform) +if(MSVC) + # Default winver to Vista and Later + set(WINVER "0x0600" CACHE STRING "Windows Target Version: 0x0400 - 95 & NT 4.0, 0x0500 - 2000, 0x0501 - XP, 0x0600 - Vista, 0x0601 - 7, 0x0602 - 8") +endif() +include(cmake/osx_no_app_or_frameworks.cmake) +include(cmake/msvc_xp_support.cmake) +include(cmake/vs_set_working_directory.cmake) +include(cmake/date.cmake) +include(cmake/adapter_fanuc.cmake) + +# Add our dependency projects +set(MSVC_SHARED_RT ON) # Use shared runtime libraries for Microsoft compiles +include(cmake/CppUnit.cmake) + +# Add our projects +if(${BUILD_FANUC}) # This is conditional as it requires the externally specified FOCAS-2 libraries to be purchased + add_subdirectory(fanuc) +endif() + +add_subdirectory(fake) +add_subdirectory(test) \ No newline at end of file diff --git a/_clang-format b/_clang-format new file mode 100644 index 0000000..8dcb295 --- /dev/null +++ b/_clang-format @@ -0,0 +1,32 @@ +--- +AccessModifierOffset: '-4' +AlignAfterOpenBracket: AlwaysBreak +AllowShortBlocksOnASingleLine: 'false' +AllowShortCaseLabelsOnASingleLine: 'false' +AllowShortIfStatementsOnASingleLine: 'false' +AllowShortLoopsOnASingleLine: 'false' +BinPackParameters: 'false' +BreakBeforeBraces: Allman +BreakConstructorInitializersBeforeComma: 'true' +ColumnLimit: '0' +Cpp11BracedListStyle: 'true' +IndentCaseLabels: 'false' +IndentWidth: '4' +KeepEmptyLinesAtTheStartOfBlocks: 'true' +Language: Cpp +MaxEmptyLinesToKeep: '2' +NamespaceIndentation: None +PointerAlignment: Right +SortIncludes: 'false' +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: 'false' +SpacesBeforeTrailingComments: '1' +SpacesInAngles: 'true' +SpacesInContainerLiterals: 'false' +SpacesInParentheses: 'true' +SpacesInSquareBrackets: 'false' +Standard: Cpp11 +TabWidth: '4' +UseTab: Always + +... diff --git a/cmake/CppUnit.cmake b/cmake/CppUnit.cmake new file mode 100644 index 0000000..5744e5d --- /dev/null +++ b/cmake/CppUnit.cmake @@ -0,0 +1,32 @@ +# This module allows the addition of CppUnit to a target +# Depending on or compiler this is either via our sub-module or searching +# for a package on the system + +if(MSVC) + add_subdirectory(${CMAKE_SOURCE_DIR}/cppunit_make "${CMAKE_BINARY_DIR}/cppunit") +endif(MSVC) + +################################################################################# +# # +# Functions # +# # +################################################################################# + +function(AddCppUnitSupport projectTarget) + + if(WIN32) + # For Windows we compile our own version of CppUnit from our Git submodule source + # Define a dependency between the targets and link them. + set(CPPUNIT_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/cppunit/include) + set(CPPUNIT_LIBRARY cppunit) + + add_dependencies(${projectTarget} cppunit) + elseif(UNIX) + # We will use the system's installed packages; which we have to look for. + find_package(CppUnit REQUIRED) + endif() + + target_include_directories(${projectTarget} PRIVATE ${CPPUNIT_INCLUDE_DIR}) + target_link_libraries(${projectTarget} PRIVATE ${CPPUNIT_LIBRARY}) + +endfunction() \ No newline at end of file diff --git a/cmake/Date.cmake b/cmake/Date.cmake new file mode 100644 index 0000000..f1a6f66 --- /dev/null +++ b/cmake/Date.cmake @@ -0,0 +1,12 @@ +# This module allows the addition of Date to a target + +################################################################################# +# # +# Functions # +# # +################################################################################# + +function(AddDateSupport projectTarget) + # Only support the header-only implementation of date, so just add an include path to the target + target_include_directories(${projectTarget} PRIVATE ${CMAKE_SOURCE_DIR}/date/include) +endfunction() \ No newline at end of file diff --git a/test/CMake/FindCppUnit.cmake b/cmake/FindCppUnit.cmake similarity index 100% rename from test/CMake/FindCppUnit.cmake rename to cmake/FindCppUnit.cmake diff --git a/test/CMake/LibFindMacros.cmake b/cmake/LibFindMacros.cmake similarity index 100% rename from test/CMake/LibFindMacros.cmake rename to cmake/LibFindMacros.cmake diff --git a/cmake/adapter_fanuc.cmake b/cmake/adapter_fanuc.cmake new file mode 100644 index 0000000..479797f --- /dev/null +++ b/cmake/adapter_fanuc.cmake @@ -0,0 +1,129 @@ +option(BUILD_FANUC "Build the FOCAS-2 Fanuc Adapter" OFF) + +# If we do not have a cache entry for the FOCAS directory, create one now +# and default its value relative to the project root +if(NOT DEFINED FOCAS2_DIR) + set(FOCAS2_DIR "${CMAKE_SOURCE_DIR}/../FOCAS2" CACHE PATH "Path to the top-level Fanuc FOCAS2 directory") +endif() + +# Define a drop-list of FANUC controls that can be targeted +if(NOT DEFINED FANUC_CONTROL) + set(FANUC_CONTROL "FS16/18/21, 0i-B, 0i-C, 16i/18i-W, PMi" CACHE STRING "Control to target within the FOCAS-2 library, affects maximum number of axis") +endif() + +# Constrain this list in the UI +# |-----------------------------------------------|---------------|-------------------| +# | Value | MAX_AXIS | Compile Symbol | +# |-----------------------------------------------|---------------|-------------------| +# | FS16/18/21, 0i-B, 0i-C, 16i/18i-W, PMi (8) | 8 | - | +# | FS0i-A (4) | 4 | FS0ID | +# | FS0i-D (32) | 32 | FS0IDD | +# | FS0i-F (32) | 32 | FS30D | +# | FS15-B (10) | 10 | FS15BD | +# | FS15-B Multi axes (15) | 15 | M_AXIS1 | +# | FS15-B/15i Multi axes (24) | 24 | M_AXIS2 | +# | FS30i/31i/32i/35i (32) | 32 | FS30D | +# | PMi-A (32) | 32 | FS30D | +# | PM (6) | 32 | PMD | +# |-----------------------------------------------|---------------|-------------------| +# +set_property(CACHE FANUC_CONTROL PROPERTY STRINGS + "FS16/18/21, 0i-B, 0i-C, 16i/18i-W, PMi (8)" + "FS0i-A (4)" + "FS0i-D (32)" + "FS0i-F (32)" + "FS15-B (10)" + "FS15-B Multi axes (15)" + "FS15-B/15i Multi axes (24)" + "FS30i/31i/32i/35i (32)" + "PMi-A (32)" + "PM (6)" + ) + +# Perform global checks if the user has chosen to build the Fanuc adapter +if(${BUILD_FANUC}) + if(NOT EXISTS ${FOCAS2_DIR}) + message(WARNING "The FOCAS2 directory '${FOCAS2_DIR}' does not exists. Skipping Fanuc adapter generation") + set(BUILD_FANUC OFF) + endif() +endif() + +# FANUC only supports Windows for 64-bit compilations +if( ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") AND UNIX) + message(WARNING "FOCAS2 only supports 32-bit compilations when targeting Linux. Skipping Fanuc adapter generation") + set(BUILD_FANUC OFF) +endif() + +# Fanuc include directories are based upon architecture and platform +# Default to 32-bit systems +set(FANUC_INC_BASE_DIR ${FOCAS2_DIR}/Fwlib) +if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + # 64-bit system + set(FANUC_INC_BASE_DIR ${FOCAS2_DIR}/Fwlib64) +endif() +set(FANUC_INC_CTRL_DIR ${FANUC_INC_BASE_DIR}/e1) # This header is suitable for all controls if compilation definitions are set + +# These properties are different for Linux +if(UNIX AND (CMAKE_SYSTEM_NAME MATCHES Linux) ) + set(FANUC_INC_BASE_DIR ${FOCAS2_DIR}/Fwlib/Linux) + set(FANUC_INC_CTRL_DIR ${FANUC_INC_BASE_DIR}) +endif() + +################################################################################# +# # +# Functions # +# # +################################################################################# +function(AddFocas2Support projectTarget) + + # Add compile definitions based upon the current value of FANUC_CONTROL + if(${FANUC_CONTROL} STREQUAL "FS0i-A (4)") + target_compile_definitions(${projectTarget} PRIVATE FS0ID) + elseif(${FANUC_CONTROL} STREQUAL "FS0i-D (32)") + target_compile_definitions(${projectTarget} PRIVATE FS0IDD) + elseif(${FANUC_CONTROL} STREQUAL "FS0i-F (32)") + target_compile_definitions(${projectTarget} PRIVATE FS30D) + elseif(${FANUC_CONTROL} STREQUAL "FS15-B (10)") + target_compile_definitions(${projectTarget} PRIVATE FS15BD) + elseif(${FANUC_CONTROL} STREQUAL "FS15-B Multi axes (15)") + target_compile_definitions(${projectTarget} PRIVATE M_AXIS1) + elseif(${FANUC_CONTROL} STREQUAL "FS15-B/15i Multi axes (24)") + target_compile_definitions(${projectTarget} PRIVATE M_AXIS2) + elseif(${FANUC_CONTROL} STREQUAL "FS30i/31i/32i/35i (32)") + target_compile_definitions(${projectTarget} PRIVATE FS30D) + elseif(${FANUC_CONTROL} STREQUAL "PMi-A (32)") + target_compile_definitions(${projectTarget} PRIVATE FS30D) + elseif(${FANUC_CONTROL} STREQUAL "PM (6)") + target_compile_definitions(${projectTarget} PRIVATE PMD) + endif() + + # Target the correct link libraries + if(WIN32) + if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + target_link_libraries(${projectTarget} + PRIVATE ${FANUC_INC_BASE_DIR}/Fwlib64.lib + ) + else() + target_link_libraries(${projectTarget} + PRIVATE ${FANUC_INC_BASE_DIR}/Fwlib32.lib + ) + endif() + elseif(UNIX) + if(CMAKE_SYSTEM_PROCESSOR EQUAL "arm") + target_link_libraries(${projectTarget} + PRIVATE ${FANUC_INC_BASE_DIR}/arm/libfwlib32.so.1.0.1 + ) + else() + target_link_libraries(${projectTarget} + PRIVATE ${FANUC_INC_BASE_DIR}/x86/libfwlib32.so.1.0.2 + ) + endif() + endif() + + # Add include directories + target_include_directories(${projectTarget} + PRIVATE ${FANUC_INC_BASE_DIR} + PRIVATE ${FANUC_INC_CTRL_DIR} + ) + +endfunction() diff --git a/cmake/msvc_xp_support.cmake b/cmake/msvc_xp_support.cmake new file mode 100644 index 0000000..99cbe21 --- /dev/null +++ b/cmake/msvc_xp_support.cmake @@ -0,0 +1,45 @@ +# If we are using a XP compatable toolset (specified with the '-T' argument to cmake.exe) then +# we may need to make some changes to the way projects are compiled. + +# Force CMake to show the toolset generator option. This will allow a user to specify a toolset not available in the GUI (Option is now available from CMake v3.5.1). +# Values could be something like: +# - v120_xp (Visual Studio 2013 targeted for XP) +# - v140_xp (Visual Studio 2015 targeted for XP) +# - v141_xp (Visual Studio 2017 targeted for XP) +# - v120 (Normal Visual Studio 2013) +# - v140 (Normal Visual Studio 2015) +# - v141 (Normal isual Studio 2017) +set(CMAKE_GENERATOR_TOOLSET ${CMAKE_GENERATOR_TOOLSET} CACHE string "Use to target a toolset not available in the CMake GUI list of options, e.g. 'v141_xp'" FORCE) + + +################################################################################# +# # +# Functions # +# # +################################################################################# + +function(AddMsvcXPSupport projectTarget) + if (CMAKE_GENERATOR_TOOLSET MATCHES "v[0-9]*_xp") + message(STATUS "Visual Studio XP compliant generator toolkit specified for target ${projectTarget}") + + # Define compiler flags for the target to prevent use of Windows APIs that are not XP compliant + target_compile_definitions(${projectTarget} + PRIVATE WINVER=0x502 + PRIVATE _WIN32_WINNT=0x502) + + # From Visual Studio 2015 and later, the compiler initialises static variables + # in a thread-safe manner. This can cause issues when running under Windows XP + # from a C# host application or anything dynamically loading a module. + # So to be extra safe we will disable this behaviour for shared libraries. + # https://docs.microsoft.com/en-us/cpp/build/reference/zc-threadsafeinit-thread-safe-local-static-initialization + # https://support.microsoft.com/en-gb/help/118816/prb-calling-loadlibrary-to-load-a-dll-that-has-static-tls + # https://msdn.microsoft.com/en-us/library/windows/desktop/6yh4a9k1(v=vs.140).aspx + # https://blogs.msdn.microsoft.com/oldnewthing/20101122-00/?p=12233/#10095505 + if(MSVC_VERSION GREATER 1700) + get_target_property(target_type ${projectTarget} TYPE) + if(target_type STREQUAL "SHARED_LIBRARY") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:threadSafeInit- ") + endif() + endif() + endif() +endfunction() \ No newline at end of file diff --git a/cmake/osx_no_app_or_frameworks.cmake b/cmake/osx_no_app_or_frameworks.cmake new file mode 100644 index 0000000..42ebe15 --- /dev/null +++ b/cmake/osx_no_app_or_frameworks.cmake @@ -0,0 +1,9 @@ +# Change how CMake find_* commands choose between OS X Application Bundles and unix-style package components. +# We will always prefer packages +# +set(CMAKE_FIND_APPBUNDLE NEVER) + +# Change how CMake find_* commands choose between OS X frameworks and unix-style package components. +# We will always prefer packages +# +set(CMAKE_FIND_FRAMEWORK NEVER FORCE) diff --git a/cmake/vs_set_working_directory.cmake b/cmake/vs_set_working_directory.cmake new file mode 100644 index 0000000..fa59966 --- /dev/null +++ b/cmake/vs_set_working_directory.cmake @@ -0,0 +1,16 @@ +# By default Visual Studio sets its 'working directory' for debugging to the MSBuild property $(ProjectDir). +# Some targets may require a specific working folder (for example to locate files or libraries). +# This CMake module contains a function that can set the 'working directory'. +# + +################################################################################# +# # +# Functions # +# # +################################################################################# + +function(SetVisualStudioWorkingDirectory projectTarget workingDirectory) + if(MSVC) + set_target_properties(${projectTarget} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${workingDirectory}) + endif() +endfunction() \ No newline at end of file diff --git a/cppunit b/cppunit new file mode 160000 index 0000000..b8a9398 --- /dev/null +++ b/cppunit @@ -0,0 +1 @@ +Subproject commit b8a9398b3352c6560af646e1492aae4bf2bd3101 diff --git a/cppunit_make/CMakeLists.txt b/cppunit_make/CMakeLists.txt new file mode 100644 index 0000000..47b978d --- /dev/null +++ b/cppunit_make/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 2.6) + +project(cppunit) + +set(CPPUNIT_SRC_DIR ../cppunit/src/cppunit) +set(CPPUNIT_INCLUDE_DIRS ../cppunit/include) + +file(GLOB internal_headers ${CPPUNIT_SRC_DIR}/A-Za-z_]*.h) +file(GLOB install_headers ${CPPUNIT_INCLUDE_DIRS}/A-Za-z_]/*.h) +file(GLOB sources ${CPPUNIT_SRC_DIR}/[A-Za-z_]*.cpp) +list(REMOVE_ITEM sources ${CPPUNIT_SRC_DIR}/UnixDynamicLibraryManager.cpp) + +include_directories(${CPPUNIT_INCLUDE_DIRS} ${CPPUNIT_SRC_DIR}) + +add_library(cppunit ${sources} ${headers}) + +# correct library names +set_target_properties(cppunit PROPERTIES + DEBUG_POSTFIX "d" + RELEASE_POSTFIX "" + MINSIZEREL_POSTFIX "" + RELWITHDEBINFO_POSTFIX "" +) + +if(MSVC) + ### General stuff + # a) Change MSVC runtime library settings (/MD[d], /MT[d], /ML[d] (single-threaded until VS 2003)) + # plus set lib suffix for later use and project label accordingly + # see http://msdn.microsoft.com/en-us/library/aa278396(v=VS.60).aspx + # http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=VS.71).aspx + set(LIB_RT_SUFFIX "md") # CMake defaults to /MD for MSVC + set(LIB_RT_OPTION "/MD") + # + + if(NOT MSVC_SHARED_RT) # User wants to have static runtime libraries (/MT, /ML) + if(MSVC_STHREADED_RT) # User wants to have old single-threaded static runtime libraries + set(LIB_RT_SUFFIX "ml") + set(LIB_RT_OPTION "/ML") + if(NOT ${MSVC_VERSION} LESS 1400) + message(FATAL_ERROR "Single-threaded static runtime libraries (/ML) only available until VS .NET 2003 (7.1).") + endif() + else() + set(LIB_RT_SUFFIX "mt") + set(LIB_RT_OPTION "/MT") + endif() + + # correct linker options + foreach(flag_var CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + foreach(config_name "" DEBUG RELEASE MINSIZEREL RELWITHDEBINFO) + set(var_name "${flag_var}") + if(NOT "${config_name}" STREQUAL "") + set(var_name "${var_name}_${config_name}") + endif() + string(REPLACE "/MD" "${LIB_RT_OPTION}" ${var_name} "${${var_name}}") + endforeach() + endforeach() + endif() +endif(MSVC) + + diff --git a/date b/date new file mode 160000 index 0000000..a91ceef --- /dev/null +++ b/date @@ -0,0 +1 @@ +Subproject commit a91ceefb4e594648540cc0a3c00611cd962989f9 diff --git a/fake/CMakeLists.txt b/fake/CMakeLists.txt new file mode 100644 index 0000000..0d9ac3e --- /dev/null +++ b/fake/CMakeLists.txt @@ -0,0 +1,51 @@ +set(FAKE_HEADERS + fake_adapter.hpp +) + +set(FAKE_SOURCES + fake.cpp + fake_adapter.cpp +) + +set(ADDITIONAL_HEADERS + ${CMAKE_SOURCE_DIR}/src/adapter.hpp + ${CMAKE_SOURCE_DIR}/src/client.hpp + ${CMAKE_SOURCE_DIR}/src/condition.hpp + ${CMAKE_SOURCE_DIR}/src/device_datum.hpp + ${CMAKE_SOURCE_DIR}/src/server.hpp + ${CMAKE_SOURCE_DIR}/src/service.hpp + ${CMAKE_SOURCE_DIR}/src/string_buffer.hpp +) + +set(ADDITIONAL_SOURCES + ${CMAKE_SOURCE_DIR}/src/adapter.cpp + ${CMAKE_SOURCE_DIR}/src/client.cpp + ${CMAKE_SOURCE_DIR}/src/condition.cpp + ${CMAKE_SOURCE_DIR}/src/device_datum.cpp + ${CMAKE_SOURCE_DIR}/src/logger.cpp + ${CMAKE_SOURCE_DIR}/src/server.cpp + ${CMAKE_SOURCE_DIR}/src/service.cpp + ${CMAKE_SOURCE_DIR}/src/string_buffer.cpp +) + +add_executable(fake_adapter + ${FAKE_HEADERS} + ${FAKE_SOURCES} + ${ADDITIONAL_HEADERS} + ${ADDITIONAL_SOURCES} +) + +target_include_directories(fake_adapter + PRIVATE ${CMAKE_SOURCE_DIR}/src +) + + +if(WIN32) + target_link_libraries(fake_adapter + PRIVATE wsock32.lib + PRIVATE Ws2_32.lib + ) +endif() + +AddMsvcXPSupport(fake_adapter) #This will only apply if an XP compatible toolset has been selected in CMake +AddDateSupport(fake_adapter) \ No newline at end of file diff --git a/fake/fake.cpp b/fake/fake.cpp index ed0dd11..30d88b3 100644 --- a/fake/fake.cpp +++ b/fake/fake.cpp @@ -1,46 +1,47 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#include "internal.hpp" -#include "fake_adapter.hpp" -#include "server.hpp" -#include "string_buffer.hpp" - -int main(int aArgc, const char *aArgv[]) -{ - /* Construct the adapter and start the server */ - FakeAdapter *adapter = new FakeAdapter(7878); - adapter->setName("Fake MTConnect Adapter"); - return adapter->main(aArgc, aArgv); -} - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// + +#include "internal.hpp" +#include "fake_adapter.hpp" +#include "server.hpp" +#include "string_buffer.hpp" + + +int main(int aArgc, const char *aArgv[]) +{ + // Construct the adapter and start the server + FakeAdapter *adapter = new FakeAdapter(7878); + adapter->setName("Fake MTConnect Adapter"); + return adapter->main(aArgc, aArgv); +} + diff --git a/fake/fake_adapter.cpp b/fake/fake_adapter.cpp index 15031d4..d599c37 100644 --- a/fake/fake_adapter.cpp +++ b/fake/fake_adapter.cpp @@ -1,122 +1,130 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#include "internal.hpp" -#include "fake_adapter.hpp" - -FakeAdapter::FakeAdapter(int aPort) - : Adapter(aPort, 1000), - mAvailability("avail"), mSystem("system"), mPos("pos"), - mExecution("exec") -{ - addDatum(mAvailability); - addDatum(mSystem); - addDatum(mPos); - addDatum(mExecution); -} - -FakeAdapter::~FakeAdapter() -{ -} - -void FakeAdapter::initialize(int aArgc, const char *aArgv[]) -{ - MTConnectService::initialize(aArgc, aArgv); - if (aArgc > 1) { - mPort = atoi(aArgv[1]); - } -} - -void FakeAdapter::start() -{ - startServer(); -} - -void FakeAdapter::stop() -{ - stopServer(); -} - -static int count = 0; -void FakeAdapter::gatherDeviceData() -{ - mAvailability.available(); - - printf("Count: %d\n", count); - mPos.setValue(count); - switch (count % 6) - { - case 0: - mExecution.setValue(Execution::eREADY); - printf("Add 0\n"); - mSystem.add(Condition::eFAULT, "Fault 1", "0"); - break; - - case 1: - mExecution.setValue(Execution::eACTIVE); - printf("Add 0, 1\n"); - mSystem.add(Condition::eFAULT, "Fault 1", "0"); - mSystem.add(Condition::eFAULT, "Fault 2", "1"); - break; - - case 2: - printf("Add 0, 1, 2\n"); - mSystem.add(Condition::eFAULT, "Fault 1", "0"); - mSystem.add(Condition::eFAULT, "Fault 2", "1"); - mSystem.add(Condition::eFAULT, "Fault 3", "2"); - break; - - case 3: - printf("Add 1, 3\n"); - mSystem.add(Condition::eFAULT, "Fault 2", "1"); - mSystem.add(Condition::eFAULT, "Fault 4", "3"); - break; - - case 4: - mExecution.setValue(Execution::eSTOPPED); - printf("Stay the same\n"); - mSystem.add(Condition::eFAULT, "Fault 2", "1"); - mSystem.add(Condition::eFAULT, "Fault 4", "3"); - break; - - - case 5: - // Clear all - printf("Clear\n"); - mAvailability.unavailable(); - break; - } - - count++; -} - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// + +#include "internal.hpp" +#include "fake_adapter.hpp" + +FakeAdapter::FakeAdapter(int aPort) : + Adapter(aPort, 1000), + mAvailability("avail"), + mSystem("system"), + mPos("pos"), + mExecution("exec") +{ + addDatum(mAvailability); + addDatum(mSystem); + addDatum(mPos); + addDatum(mExecution); +} + + +FakeAdapter::~FakeAdapter() +{ +} + + +void FakeAdapter::initialize(int argc, const char *argv[]) +{ + MTConnectService::initialize(argc, argv); + + if (argc > 1) + mPort = atoi(argv[1]); +} + + +void FakeAdapter::start() +{ + startServer(); +} + + +void FakeAdapter::stop() +{ + stopServer(); +} + + +static int count = 0; +void FakeAdapter::gatherDeviceData() +{ + mAvailability.available(); + + printf("Count: %d\n", count); + mPos.setValue(count); + + switch (count % 6) + { + case 0: + mExecution.setValue(Execution::eREADY); + printf("Add 0\n"); + mSystem.add(Condition::eFAULT, "Fault 1", "0"); + break; + + case 1: + mExecution.setValue(Execution::eACTIVE); + printf("Add 0, 1\n"); + mSystem.add(Condition::eFAULT, "Fault 1", "0"); + mSystem.add(Condition::eFAULT, "Fault 2", "1"); + break; + + case 2: + printf("Add 0, 1, 2\n"); + mSystem.add(Condition::eFAULT, "Fault 1", "0"); + mSystem.add(Condition::eFAULT, "Fault 2", "1"); + mSystem.add(Condition::eFAULT, "Fault 3", "2"); + break; + + case 3: + printf("Add 1, 3\n"); + mSystem.add(Condition::eFAULT, "Fault 2", "1"); + mSystem.add(Condition::eFAULT, "Fault 4", "3"); + break; + + case 4: + mExecution.setValue(Execution::eSTOPPED); + printf("Stay the same\n"); + mSystem.add(Condition::eFAULT, "Fault 2", "1"); + mSystem.add(Condition::eFAULT, "Fault 4", "3"); + break; + + + case 5: + // Clear all + printf("Clear\n"); + mAvailability.unavailable(); + break; + } + + count++; +} + diff --git a/fake/fake_adapter.hpp b/fake/fake_adapter.hpp index 1995663..1193773 100644 --- a/fake/fake_adapter.hpp +++ b/fake/fake_adapter.hpp @@ -1,64 +1,58 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef FAKE_ADAPTER_HPP -#define FAKE_ADAPTER_HPP - -#include "adapter.hpp" -#include "device_datum.hpp" -#include "service.hpp" -#include "condition.hpp" - -class FakeAdapter : public Adapter, public MTConnectService -{ -protected: - /* Define all the data values here */ - - /* Events */ - Availability mAvailability; - Condition mSystem; - Sample mPos; - Execution mExecution; - -public: - FakeAdapter(int aPort); - ~FakeAdapter(); - - virtual void initialize(int aArgc, const char *aArgv[]); - virtual void start(); - virtual void stop(); - virtual void gatherDeviceData(); -}; - -#endif - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include "adapter.hpp" +#include "device_datum.hpp" +#include "service.hpp" +#include "condition.hpp" + +class FakeAdapter : public Adapter, public MTConnectService +{ +protected: + // Events + Availability mAvailability; + Condition mSystem; + Sample mPos; + Execution mExecution; + +public: + FakeAdapter(int port); + ~FakeAdapter(); + + void initialize(int argc, const char *argv[]) final; + void start() final; + void stop() final; + void gatherDeviceData() final; +}; + diff --git a/fanuc/CMakeLists.txt b/fanuc/CMakeLists.txt new file mode 100644 index 0000000..e4f17be --- /dev/null +++ b/fanuc/CMakeLists.txt @@ -0,0 +1,104 @@ +set(FANUC_HEADERS + fanuc_adapter.hpp + fanuc_axis.hpp + fanuc_helpers.hpp + fanuc_path.hpp +) + +set(FANUC_SOURCES + fanuc_adapter.cpp + fanuc_axis.cpp + fanuc_path.cpp + FanucAdapter.cpp +) + +set(MIN_INI_HEADERS + ${CMAKE_SOURCE_DIR}/minIni_07/minIni.h +) + +set(MIN_INI_SOURCES + ${CMAKE_SOURCE_DIR}/minIni_07/minIni.c +) + +set(ADDITIONAL_SOURCES + ${CMAKE_SOURCE_DIR}/src/adapter.cpp + ${CMAKE_SOURCE_DIR}/src/client.cpp + ${CMAKE_SOURCE_DIR}/src/condition.cpp + ${CMAKE_SOURCE_DIR}/src/device_datum.cpp + ${CMAKE_SOURCE_DIR}/src/logger.cpp + ${CMAKE_SOURCE_DIR}/src/server.cpp + ${CMAKE_SOURCE_DIR}/src/service.cpp + ${CMAKE_SOURCE_DIR}/src/string_array.cpp + ${CMAKE_SOURCE_DIR}/src/string_buffer.cpp +) + +set(ADDITIONAL_HEADERS + ${CMAKE_SOURCE_DIR}/src/adapter.hpp + ${CMAKE_SOURCE_DIR}/src/client.hpp + ${CMAKE_SOURCE_DIR}/src/condition.hpp + ${CMAKE_SOURCE_DIR}/src/device_datum.hpp + ${CMAKE_SOURCE_DIR}/src/internal.hpp + ${CMAKE_SOURCE_DIR}/src/logger.hpp + ${CMAKE_SOURCE_DIR}/src/server.hpp + ${CMAKE_SOURCE_DIR}/src/service.hpp + ${CMAKE_SOURCE_DIR}/src/string_array.hpp + ${CMAKE_SOURCE_DIR}/src/string_buffer.hpp +) + +set(CONFIGURATION_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/adapter.ini + ${CMAKE_CURRENT_SOURCE_DIR}/fanuc.xml +) + +# Allow better viewing and grouping of files in Visual Studio by defining source groups +source_group("Headers Files" FILES ${FANUC_HEADERS}) +source_group("Headers Files\\adapter" FILES ${ADDITIONAL_HEADERS}) +source_group("Headers Files\\Min Ini" FILES ${MIN_INI_HEADERS}) +source_group("Source Files" FILES ${FANUC_SOURCES}) +source_group("Source Files\\adapter" FILES ${ADDITIONAL_SOURCES}) +source_group("Source Files\\Min Ini" FILES ${MIN_INI_SOURCES}) +source_group("Configuration" FILES ${CONFIGURATION_FILES}) + + +add_executable(fanuc + ${FANUC_HEADERS} + ${FANUC_SOURCES} + ${MIN_INI_HEADERS} + ${MIN_INI_SOURCES} + ${ADDITIONAL_HEADERS} + ${ADDITIONAL_SOURCES} +) + +# Add our auxilliary configurations files to the target for Visual Studio, otherwise +# they do not show up in the UI +if(MSVC) + target_sources(fanuc PRIVATE ${CONFIGURATION_FILES}) +endif() + +target_include_directories(fanuc + PRIVATE ${CMAKE_SOURCE_DIR}/minIni_07 + PRIVATE ${CMAKE_SOURCE_DIR}/src +) + +target_compile_definitions(fanuc + PRIVATE INI_ANSIONLY +) + +if(WIN32) + target_link_libraries(fanuc + PRIVATE wsock32.lib + PRIVATE Ws2_32.lib + ) +endif() + +AddFocas2Support(fanuc) +AddMsvcXPSupport(fanuc) #This will only apply if an XP compatible toolset has been selected in CMake +AddDateSupport(fanuc) + +# Copy the ini file and devices XML to our output directory +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/adapter.ini DESTINATION ./Debug/) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/adapter.ini DESTINATION ./Release/) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/fanuc.xml DESTINATION ./Debug/) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/fanuc.xml DESTINATION ./Release/) + +SetVisualStudioWorkingDirectory(fanuc "\$\(OutDir\)") # Set the working directory for debugging to the MSBuild property $(OutDir) diff --git a/fanuc/FanucAdapter.cpp b/fanuc/FanucAdapter.cpp index b4f3b03..2f701f8 100755 --- a/fanuc/FanucAdapter.cpp +++ b/fanuc/FanucAdapter.cpp @@ -1,26 +1,28 @@ -/* - * Copyright Copyright 2012, System Insights, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - +// +// Copyright Copyright 2012, System Insights, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + #include "internal.hpp" +#include #include "fanuc_adapter.hpp" #include "server.hpp" #include "string_buffer.hpp" -int main(int aArgc, const char *aArgv[]) -{ - FanucAdapter *adapter = new FanucAdapter(7878); - return adapter->main(aArgc, aArgv); + +int main(int argc, const char *argv[]) +{ + auto adapter = std::make_unique(7878); + return adapter->main(argc, argv); } diff --git a/fanuc/adapter.ini b/fanuc/adapter.ini index 942c92b..3b22ae5 100644 --- a/fanuc/adapter.ini +++ b/fanuc/adapter.ini @@ -3,9 +3,13 @@ port = 7878 service = MTC Focus 1 [focus] -host = 10.211.55.5 +host = HSSB_9 [macros] +Macro500=500 +Macro501=501 +Macro502=502 +#MacroPos=[500 501 502] [pmc] SspeedOvr = 30 diff --git a/fanuc/fanuc.sln b/fanuc/fanuc.sln deleted file mode 100644 index edb0bbc..0000000 --- a/fanuc/fanuc.sln +++ /dev/null @@ -1,38 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fanuc", "fanuc.vcxproj", "{E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - Release0i|Win32 = Release0i|Win32 - Release0id|Win32 = Release0id|Win32 - Release15i|Win32 = Release15i|Win32 - Release16i|Win32 = Release16i|Win32 - Release18i|Win32 = Release18i|Win32 - Release30i|Win32 = Release30i|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Debug|Win32.ActiveCfg = Debug|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Debug|Win32.Build.0 = Debug|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release|Win32.ActiveCfg = Release|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release|Win32.Build.0 = Release|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release0i|Win32.ActiveCfg = Release0i|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release0i|Win32.Build.0 = Release0i|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release0id|Win32.ActiveCfg = Release0id|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release0id|Win32.Build.0 = Release0id|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release15i|Win32.ActiveCfg = Release15i|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release15i|Win32.Build.0 = Release15i|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release16i|Win32.ActiveCfg = Release16i|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release16i|Win32.Build.0 = Release16i|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release18i|Win32.ActiveCfg = Release18i|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release18i|Win32.Build.0 = Release18i|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release30i|Win32.ActiveCfg = Release30i|Win32 - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43}.Release30i|Win32.Build.0 = Release30i|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/fanuc/fanuc.vcproj b/fanuc/fanuc.vcproj deleted file mode 100644 index 322c231..0000000 --- a/fanuc/fanuc.vcproj +++ /dev/null @@ -1,751 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fanuc/fanuc.vcxproj b/fanuc/fanuc.vcxproj deleted file mode 100644 index 21ca7e8..0000000 --- a/fanuc/fanuc.vcxproj +++ /dev/null @@ -1,381 +0,0 @@ - - - - - Debug - Win32 - - - Release0id - Win32 - - - Release0i - Win32 - - - Release15i - Win32 - - - Release16i - Win32 - - - Release18i - Win32 - - - Release30i - Win32 - - - Release - Win32 - - - - {E8B3DF32-37B5-4FDB-9C95-B5F978E61D43} - fanuc - Win32Proj - - - - Application - Unicode - true - - - Application - Unicode - true - - - Application - Unicode - true - - - Application - Unicode - true - - - Application - Unicode - true - - - Application - Unicode - true - - - Application - Unicode - true - - - Application - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - true - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - AllRules.ruleset - - - false - - - - Disabled - ..\src;..\Fwlib;..\Fwlib\e1;..\minIni_07;%(AdditionalIncludeDirectories) - INI_ANSIONLY;DEBUG;FS30D;WIN32 - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - - - ..\Fwlib\Fwlib32.lib;wsock32.lib;..\Fwlib\fwlib30i.lib;%(AdditionalDependencies) - true - Console - MachineX86 - - - - - MaxSpeed - true - ..\src;..\Fwlib;..\Fwlib\e1;..\minIni_07;%(AdditionalIncludeDirectories) - FS0IDD;WIN32;INI_ANSIONLY - MultiThreaded - true - - - Level3 - ProgramDatabase - - - ..\Fwlib\Fwlib32.lib;wsock32.lib;%(AdditionalDependencies) - true - Console - true - true - MachineX86 - - - - - MaxSpeed - true - ..\src;..\Fwlib;..\Fwlib\e1;..\minIni_07;%(AdditionalIncludeDirectories) - FS0ID;WIN32;INI_ANSIONLY - MultiThreaded - true - - - Level3 - ProgramDatabase - - - ..\Fwlib\Fwlib32.lib;wsock32.lib;%(AdditionalDependencies) - $(OutDir)$(ProjectName)_0i.exe - true - Console - true - true - MachineX86 - - - - - MaxSpeed - true - ..\src;..\Fwlib;..\Fwlib\e1;..\minIni_07;%(AdditionalIncludeDirectories) - FS16D;WIN32;INI_ANSIONLY - MultiThreaded - true - - - Level3 - ProgramDatabase - - - ..\Fwlib\Fwlib32.lib;wsock32.lib;%(AdditionalDependencies) - $(OutDir)$(ProjectName)_16i.exe - true - Console - true - true - MachineX86 - - - - - MaxSpeed - true - ..\src;..\Fwlib;..\Fwlib\e1;..\minIni_07;%(AdditionalIncludeDirectories) - FS30D;WIN32;INI_ANSIONLY - MultiThreaded - true - - - Level3 - ProgramDatabase - - - ..\Fwlib\Fwlib32.lib;wsock32.lib;%(AdditionalDependencies) - $(OutDir)$(ProjectName)_30i.exe - true - Console - true - true - MachineX86 - - - - - MaxSpeed - true - ..\src;..\Fwlib;..\Fwlib\e1;..\minIni_07;%(AdditionalIncludeDirectories) - FS15D;WIN32;INI_ANSIONLY - MultiThreaded - true - - - Level3 - ProgramDatabase - - - ..\Fwlib\Fwlib32.lib;wsock32.lib;%(AdditionalDependencies) - $(OutDir)$(ProjectName)_15i.exe - true - Console - true - true - MachineX86 - - - - - MaxSpeed - true - ..\src;..\Fwlib;..\Fwlib\e1;..\minIni_07;%(AdditionalIncludeDirectories) - FS0IDD;WIN32;INI_ANSIONLY - MultiThreaded - true - - - Level3 - ProgramDatabase - - - ..\Fwlib\Fwlib32.lib;wsock32.lib;%(AdditionalDependencies) - $(OutDir)$(ProjectName)_0id.exe - true - Console - true - true - MachineX86 - - - - - MaxSpeed - true - ..\src;..\Fwlib;..\Fwlib\e1;..\minIni_07;%(AdditionalIncludeDirectories) - FS18D;WIN32;INI_ANSIONLY - MultiThreaded - true - - - Level3 - ProgramDatabase - - - ..\Fwlib\Fwlib32.lib;wsock32.lib;%(AdditionalDependencies) - $(OutDir)$(ProjectName)_18i.exe - true - Console - true - true - MachineX86 - - - - - - - - - - INI_ANSIONLY;DEBUG;FS30D;WIN32 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fanuc/fanuc.xml b/fanuc/fanuc.xml index e5143fb..24718da 100644 --- a/fanuc/fanuc.xml +++ b/fanuc/fanuc.xml @@ -7,6 +7,14 @@ + + + + + @@ -36,33 +44,6 @@ - - - - - - - - - - INDEX - - - - - - - - - - - SPINDLE - - - - - - @@ -85,10 +66,15 @@ + + - + + + + diff --git a/fanuc/fanuc_adapter.cpp b/fanuc/fanuc_adapter.cpp index 97ce697..cf75f76 100644 --- a/fanuc/fanuc_adapter.cpp +++ b/fanuc/fanuc_adapter.cpp @@ -1,436 +1,499 @@ -/* - * Copyright Copyright 2012, System Insights, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "internal.hpp" -#include "fanuc_adapter.hpp" -#include "minIni.h" -#include - -FanucAdapter::FanucAdapter(int aPort) - : Adapter(aPort), mAvail("avail"), mMessage("message"), mPartCount("part_count"), - mMacroSampleCount(0), mMacroPathCount(0), mPMCCount(0) -{ - /* Alarms */ - addDatum(mMessage); - - /* Controller */ - addDatum(mAvail); - addDatum(mPartCount); - - mConfigured = mConnected = false; - mAvail.unavailable(); -} - -FanucAdapter::~FanucAdapter() -{ - size_t i; - - for (i = 0; i < mPaths.size(); i++) - delete mPaths[i]; - mPaths.clear(); - - disconnect(); -} - -void FanucAdapter::initialize(int aArgc, const char *aArgv[]) -{ - MTConnectService::initialize(aArgc, aArgv); - - const char *iniFile = "adapter.ini"; - - printf("Arguments: %d\n", aArgc); - if (aArgc > 1) { - strncpy(mDeviceIP, aArgv[0], MAX_HOST_LEN - 1); - mDeviceIP[MAX_HOST_LEN - 1] = '\0'; - mDevicePort = atoi(aArgv[1]); - - mPort = 7878; - if (aArgc > 2) - mPort = atoi(aArgv[2]); - } - else - { - mDevicePort = 8193; - strcpy(mDeviceIP, "localhost"); - mPort = 7878; - if (aArgc > 0) - iniFile = aArgv[0]; - printf("Ini File: %s\n", iniFile); - } - - FILE *fp = fopen(iniFile, "r"); - printf("FP = %d, %x\n", errno, fp); - if (fp != 0) fclose(fp); - - configMacrosAndPMC(iniFile); -} - -void FanucAdapter::start() -{ - startServer(); -} - -void FanucAdapter::stop() -{ - stopServer(); -} - -void FanucAdapter::innerGatherDeviceData() -{ - try - { - if (!mConnected) - connect(); - else - { - getPathData(); - getMessages(); - getMacros(); - getPMC(); - getCounts(); - } - } - catch (...) - { - gLogger->error("Unhandled exception occurred during gathering device data, disconnecting."); - disconnect(); - } -} - -void FanucAdapter::gatherDeviceData() -{ - __try { - innerGatherDeviceData(); - } - - __except(EXCEPTION_EXECUTE_HANDLER) { - gLogger->error("Unhandled structured exception occurred during gathering device data, disconnecting."); - disconnect(); - } -} - -void FanucAdapter::disconnect() -{ - if (mConnected) - { - printf("Machine has disconnected. Releasing Resources\n"); - cnc_freelibhndl(mFlibhndl); - mConnected = false; - unavailable(); - } -} - - -void FanucAdapter::configMacrosAndPMC(const char *aIniFile) -{ - // Read adapter configuration - mPort = ini_getl("adapter", "port", mPort, aIniFile); - ini_gets("adapter", "service", "MTConnect Fanuc Adapter", mName, - SERVICE_NAME_LEN, aIniFile); - mScanDelay = ini_getl("adapter", "scanDelay", mScanDelay, aIniFile); - - ini_gets("focus", "host", mDeviceIP, mDeviceIP, MAX_HOST_LEN, aIniFile); - mDevicePort = ini_getl("focus", "port", mDevicePort, aIniFile); - - char dnc[8]; - ini_gets("focus", "dnc", "yes", dnc, 8, aIniFile); - mAllowDNC = _strnicmp(dnc, "no", 2) != 0; - - if (!mAllowDNC) - printf("Disabling retrieval of program header\n"); - - // Read adapter.ini to get additional macro variables and - // PMC registers - char name[100]; - int idx; - const static char *sDigits = "0123456789"; - - mMacroMin = 99999; - mMacroMax = 0; - - // First look for macro variables - for (idx = 0; - ini_getkey("macros", idx, name, sizeof(name), aIniFile) > 0 && - idx < MAX_MACROS; - idx++) - { - char numbers[256]; - ini_gets("macros", name, "", numbers, 256, aIniFile); - if (numbers[0] == '[') - { - // We have a path macro. - int x, y, z; - char *cp = numbers + 1, *n; - x = strtol(cp, &n, 10); - if (cp == n) - continue; - cp = n; - y = strtol(cp, &n, 10); - if (cp == n) - continue; - cp = n; - z = strtol(cp, &n, 10); - if (cp == n) - continue; - - int i = mMacroPathCount++; - mMacroPath[i] = new MacroPathPosition(name, x, y, z); - addDatum(*mMacroPath[i]); - - printf("Adding path macro '%s' at location %d %d %d\n", name, x, y, z); - - if (x > mMacroMax) mMacroMax = x; - if (x < mMacroMin) mMacroMin = x; - if (y > mMacroMax) mMacroMax = y; - if (y < mMacroMin) mMacroMin = y; - if (z > mMacroMax) mMacroMax = z; - if (z < mMacroMin) mMacroMin = z; - } - else - { - char *cp = numbers, *n; - long v = strtol(cp, &n, 10); - if (cp == n) - continue; - int i = mMacroSampleCount++; - mMacroSample[i] = new MacroSample(name, v); - addDatum(*mMacroSample[i]); - - printf("Adding sample macro '%s' at location %d\n", name, v); - - if (v > mMacroMax) mMacroMax = v; - if (v < mMacroMin) mMacroMin = v; - } - - - } - - for (idx = 0; - ini_getkey("pmc", idx, name, sizeof(name), aIniFile) > 0 && - idx < MAX_PMC; - idx++) - { - long v = ini_getl("pmc", name, 0, aIniFile); - mPMCVariable[idx] = new IntEvent(name); - mPMCAddress[idx] = v; - - addDatum(*mPMCVariable[idx]); - - printf("Adding pmc '%s' at location %d\n", name, v); - } - mPMCCount = idx; -} - -void FanucAdapter::configure() -{ - if (mConfigured || !mConnected) - return; - - int ret; - gLogger->info("Configuring...\n"); - - short path; - ret = cnc_getpath(mFlibhndl, &path, &mMaxPath); - if (ret != EW_OK) - { - gLogger->error("Cannot find number of paths: %d", ret); - mMaxPath = 1; - path = 1; - } - - for (int i = 1; i <= mMaxPath; i++) - { - FanucPath *path = new FanucPath(this, i); - if (!path->configure(mFlibhndl)) - { - gLogger->error("Could not configure path: %d", i); - exit(1); - } - - path->allowDNC(mAllowDNC); - mPaths.push_back(path); - } - - gLogger->info("Current path: %d, maximum paths: %d", path, mMaxPath); - - mConfigured = true; -} - -void FanucAdapter::connect() -{ - if (mConnected) - return; - - printf("Connecting to Machine at %s and port %d\n", mDeviceIP, mDevicePort); - short ret = ::cnc_allclibhndl3(mDeviceIP, mDevicePort, 10, &mFlibhndl); - printf("Result: %d\n", ret); - if (ret == EW_OK) - { - mAvail.available(); - mConnected = true; - if (!mConfigured) configure(); - - // Resets conditions to normal. - initializeDeviceDatum(); - } - else - { - mConnected = false; - unavailable(); - Sleep(5000); - } -} - -void FanucAdapter::reconnect() -{ - if (mConnected) - { - cnc_freelibhndl(mFlibhndl); - mConnected = false; - - connect(); - } -} - -void FanucAdapter::getMacros() -{ - if (!mConnected) - return; - - if (mMacroSampleCount == 0 && mMacroPathCount == 0) - return; - - // For now we assume they are close in range. If this proves to not - // be true, we will have to get more creative. - IODBMR *macros = new IODBMR[mMacroMax - mMacroMin]; - short ret = cnc_rdmacror(mFlibhndl, mMacroMin, mMacroMax, - sizeof(IODBMR) * (mMacroMax - mMacroMin + 1), - macros); - - if (ret == EW_OK) { - for (int i = 0; i < mMacroSampleCount; i++) - { - int off = mMacroSample[i]->getNumber() - mMacroMin; - if (macros->data[off].mcr_val != 0 || macros->data[off].dec_val != -1) - { - mMacroSample[i]->setValue(((double) macros->data[off].mcr_val) / - pow(10.0, macros->data[off].dec_val)); - } else { - mMacroSample[i]->unavailable(); - } - } - for (int i = 0; i < mMacroPathCount; i++) - { - int x = mMacroPath[i]->getX() - mMacroMin; - int y = mMacroPath[i]->getY() - mMacroMin; - int z = mMacroPath[i]->getZ() - mMacroMin; - - if ((macros->data[x].mcr_val != 0 || macros->data[x].dec_val != -1) && - (macros->data[y].mcr_val != 0 || macros->data[y].dec_val != -1) && - (macros->data[z].mcr_val != 0 || macros->data[z].dec_val != -1)) - { - mMacroPath[i]->setValue(((double) macros->data[x].mcr_val) / - pow(10.0, macros->data[x].dec_val), - ((double) macros->data[y].mcr_val) / - pow(10.0, macros->data[y].dec_val), - ((double) macros->data[z].mcr_val) / - pow(10.0, macros->data[z].dec_val)); - } else { - mMacroSample[i]->unavailable(); - } - } - } - else - { - printf("Could not read macro variables: %d\n", ret); - } - - delete[] macros; -} - -void FanucAdapter::getPMC() -{ - if (!mConnected) - return; - - for (int i = 0; i < mPMCCount; i++) - { - IODBPMC buf; - short ret = pmc_rdpmcrng(mFlibhndl, 0 /* G */, 0 /* byte */, - mPMCAddress[i], mPMCAddress[i], 8 + 1, - &buf); - if (ret == EW_OK) - { - if (buf.u.cdata[0] < 0) - mPMCVariable[i]->setValue(-buf.u.cdata[0] - 1); - else - mPMCVariable[i]->setValue(buf.u.cdata[0]); - } - else - { - printf("Could not retrieve PMC data at %d for %s: %d\n", - mPMCAddress[i], mPMCVariable[i]->getName(), ret); - } - } -} - -void FanucAdapter::getMessages() -{ - if (!mConnected) - return; - - OPMSG messages[6]; - int ret = cnc_rdopmsg(mFlibhndl, 0, 6 + 256, messages); - if (ret == EW_OK && messages->datano != -1) - { - char buf[32]; - sprintf(buf, "%04", messages->datano); - mMessage.setValue(messages->data, buf); - } -} - -void FanucAdapter::getCounts() -{ - if (!mConnected) - return; - - // Should just be a parameter read - IODBPSD buf; - short ret = cnc_rdparam(mFlibhndl, 6711, 0, 8, &buf); - if (ret == EW_OK) - { - mPartCount.setValue(buf.u.ldata); - } -} - -void FanucAdapter::getPathData() -{ - if (!mConnected) - return; - - int i; - for (i = mMaxPath - 1; i >= 0; i--) - { - if (!mPaths[i]->gatherData(mFlibhndl)) - { - disconnect(); - break; - } - } - if (mConnected && i > 0) - cnc_setpath(mFlibhndl, 0); -} - +// +// Copyright Copyright 2012, System Insights, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include +#include "fanuc_adapter.hpp" +#include +#include +#include +#include +#include +#include +#include "fanuc_helpers.hpp" + +constexpr int DEF_SERVICE_PORT = 7878; +constexpr int DEF_FOCAS2_PORT = 8193; + +// C++11 helper function for obtaining a statically defined array's item count +template +constexpr std::size_t countof(T const (&)[N]) noexcept +{ + return N; +} + +FanucAdapter::FanucAdapter(int aPort) : + Adapter(aPort), + mMessage("message"), + mAvail("avail"), + mPartCount("part_count"), + mMacroMin(99999), + mMacroMax(0), + mFlibhndl(0), + mConnected(false), + mDevicePort(DEF_FOCAS2_PORT), + mDeviceIP{"localhost"} +{ + // Alarms + addDatum(mMessage); + + // Controller + addDatum(mAvail); + addDatum(mPartCount); + + mConfigured = mConnected = false; + mAvail.unavailable(); +} + + +FanucAdapter::~FanucAdapter() +{ + for (auto &path : mPaths) + path.release(); + mPaths.clear(); + + disconnect(); +} + + +void FanucAdapter::initialize(int argc, const char *argv[]) +{ + MTConnectService::initialize(argc, argv); + + auto iniFile = "adapter.ini"; + std::cout << "Arguments: " << argc << std::endl; + if (argc > 1) + { + strncpy(mDeviceIP, argv[0], countof(mDeviceIP) - 1); + mDevicePort = atoi(argv[1]); + mPort = DEF_SERVICE_PORT; + if (argc > 2) + mPort = atoi(argv[2]); + } + else + { + mDevicePort = DEF_FOCAS2_PORT; + strncpy(mDeviceIP, "localhost", countof(mDeviceIP) - 1); + mPort = DEF_SERVICE_PORT; + if (argc > 0) + iniFile = argv[0]; + std::cout << "Ini File: " << iniFile << std::endl; + } + + auto fp = fopen(iniFile, "r"); + std::cout << "FP = " << errno << ", " << fp << std::endl; + if(fp) + { + fclose(fp); + fp = nullptr; + } + + configMacrosAndPMC(iniFile); +} + + +void FanucAdapter::start() +{ + startServer(); +} + + +void FanucAdapter::stop() +{ + stopServer(); +} + + +void FanucAdapter::innerGatherDeviceData() +{ + try + { + if (!mConnected) + connect(); + else + { + getPathData(); + getMessages(); + getMacros(); + getPMC(); + getCounts(); + } + } + catch (...) + { + gLogger->error("Unhandled exception occurred during gathering device data, disconnecting."); + disconnect(); + } +} + + +void FanucAdapter::gatherDeviceData() +{ + __try + { + innerGatherDeviceData(); + } + + __except(EXCEPTION_EXECUTE_HANDLER) + { + gLogger->error("Unhandled structured exception occurred during gathering device data, disconnecting."); + disconnect(); + } +} + + +void FanucAdapter::disconnect() +{ + if (mConnected) + { + std::cout << "Machine has disconnected. Releasing Resources" << std::endl; + cnc_freelibhndl(mFlibhndl); + mFlibhndl = 0; + mConnected = false; + unavailable(); + } +} + + +void FanucAdapter::configMacrosAndPMC(const char *iniFile) +{ + // Read adapter configuration + mPort = ini_getl("adapter", "port", mPort, iniFile); + ini_gets("adapter", + "service", + "MTConnect Fanuc Adapter", + mName, + SERVICE_NAME_LEN, + iniFile); + mScanDelay = std::chrono::milliseconds{ ini_getl("adapter", "scanDelay", 100, iniFile) }; + + ini_gets("focus", "host", mDeviceIP, mDeviceIP, countof(mDeviceIP), iniFile); + mDevicePort = ini_getl("focus", "port", mDevicePort, iniFile); + + // Read adapter.ini to get additional macro variables and + // PMC registers + char name[100] = {0}; + const static char *sDigits = "0123456789"; + + mMacroMin = 99999; + mMacroMax = 0; + + // First look for macro variables + for (int idx = 0; + ini_getkey("macros", idx, name, countof(name), iniFile) > 0 && idx < MAX_MACROS; + idx++) + { + char numbers[256] = {0}; + ini_gets("macros", name, "", numbers, countof(numbers), iniFile); + if (numbers[0] == '[') + { + // We have a path macro. + int x(0), y(0), z(0); + char *cp = numbers + 1, *n; + x = strtol(cp, &n, 10); + if (cp == n) + continue; + cp = n; + y = strtol(cp, &n, 10); + if (cp == n) + continue; + cp = n; + z = strtol(cp, &n, 10); + if (cp == n) + continue; + + auto macroPathPos = new MacroPathPosition(name, x, y, z); + mMacroPathPositions.push_back(macroPathPos); + addDatum(*macroPathPos); + + std::cout << "Adding path macro '" << name << "' at location " + << x << " " << y << " " << z << std::endl; + + if (x > mMacroMax) + mMacroMax = x; + if (x < mMacroMin) + mMacroMin = x; + if (y > mMacroMax) + mMacroMax = y; + if (y < mMacroMin) + mMacroMin = y; + if (z > mMacroMax) + mMacroMax = z; + if (z < mMacroMin) + mMacroMin = z; + } + else + { + char *cp = numbers, *n(nullptr); + auto v = strtol(cp, &n, 10); + if (cp == n) + continue; + auto macroSample = new MacroSample(name, v); + mMacroSamples.push_back(macroSample); + addDatum(*macroSample); + + std::cout << "Adding sample macro '" << name << "' at location " << v << std::endl; + + if (v > mMacroMax) + mMacroMax = v; + if (v < mMacroMin) + mMacroMin = v; + } + } + + auto pmcIdx = 0; + for (pmcIdx = 0; + ini_getkey("pmc", pmcIdx, name, countof(name), iniFile) > 0 && pmcIdx < MAX_PMC; + pmcIdx++) + { + auto pmcAddress = ini_getl("pmc", name, 0, iniFile); + auto pmcVar = new PmcVariable(name, pmcAddress); + mPMCVariables.push_back(pmcVar); + addDatum(*pmcVar); + + std::cout << "Adding pmc '" << name << "' at location " << pmcAddress << std::endl; + } +} + + +void FanucAdapter::configure() +{ + if (mConfigured || !mConnected) + return; + + gLogger->info("Configuring...\n"); + + short path(0), maxNumPaths(0); + auto ret = cnc_getpath(mFlibhndl, &path, &maxNumPaths); + if (ret != EW_OK) + { + gLogger->error("Cannot find number of paths: %d", ret); + maxNumPaths = 1; + path = 1; + } + + for (auto pathNum = 1; pathNum <= maxNumPaths; pathNum++) + { + auto fanucPath = std::make_unique(this, pathNum); + if (!fanucPath->configure(mFlibhndl)) + { + gLogger->error("Could not configure path: %d", pathNum); + exit(1); + } + + mPaths.push_back(std::move(fanucPath)); + } + + gLogger->info("Current path: %d, maximum paths: %d", path, maxNumPaths); + + mConfigured = true; +} + + +void FanucAdapter::connect() +{ + if (mConnected) + return; + + std::cout << "Connecting to Machine at " << mDeviceIP << " and port " << mDevicePort << std::endl; + + // If the device IP has been passed in the form HSSB_{1-9} then we should + // connect via HSSB + std::regex hssbRegEx("HSSB_([0-9])"); + std::cmatch matches; + short ret = 0; + if(std::regex_search(mDeviceIP, matches, hssbRegEx)) + { + auto res = matches[1].str(); + int hssbAddress = std::strtol(res.c_str(), nullptr, 0); + ret = ::cnc_allclibhndl2(hssbAddress, &mFlibhndl); + } + else + { + ret = ::cnc_allclibhndl3(mDeviceIP, mDevicePort, 10, &mFlibhndl); + } + + std::cout << "Result: " << ret < rawData; + auto count = (mMacroMax - mMacroMin) + 1; + rawData.resize(count, {0}); + + short ret = cnc_rdmacror( + mFlibhndl, + mMacroMin, + mMacroMax, + sizeof(IODBMR) * count, + &rawData[0]); + + if (ret == EW_OK) + { + for (const auto macroSample : mMacroSamples) + { + auto const &variableData = rawData[0].data[macroSample->getNumber() - mMacroMin]; + if (variableData.mcr_val != 0 || variableData.dec_val != -1) + { + macroSample->setValue( + convert_bin_to_dec(variableData.mcr_val, variableData.dec_val)); + } + else + { + macroSample->unavailable(); + } + } + for (const auto macroPathPos : mMacroPathPositions) + { + auto const &xData = rawData[0].data[macroPathPos->getX() - mMacroMin]; + auto const &yData = rawData[0].data[macroPathPos->getY() - mMacroMin]; + auto const &zData = rawData[0].data[macroPathPos->getZ() - mMacroMin]; + + if ((xData.mcr_val != 0 || xData.dec_val != -1) && + (yData.mcr_val != 0 || yData.dec_val != -1) && + (zData.mcr_val != 0 || zData.dec_val != -1)) + { + macroPathPos->setValue( + convert_bin_to_dec(xData.mcr_val, xData.dec_val), + convert_bin_to_dec(yData.mcr_val, yData.dec_val), + convert_bin_to_dec(zData.mcr_val, zData.dec_val) ); + } + else + { + macroPathPos->unavailable(); + } + } + } + else + std::cout << "Could not read macro variables: " << ret << std::endl; +} + + +void FanucAdapter::getPMC() +{ + if (!mConnected) + return; + + IODBPMC buf = {0}; + for(const auto pcmVariable : mPMCVariables) + { + auto ret = pmc_rdpmcrng( + mFlibhndl, + 0, // G + 0, // byte + pcmVariable->getAddress(), + pcmVariable->getAddress(), + 8 + 1, + &buf); + if (ret == EW_OK) + { + if (buf.u.cdata[0] < 0) + pcmVariable->setValue(-buf.u.cdata[0] - 1); + else + pcmVariable->setValue(buf.u.cdata[0]); + } + else + { + std::cout << "Could not retrieve PMC data at " << pcmVariable->getAddress() + << " for " << pcmVariable->getName() + << ": " << ret + << std::endl; + } + } +} + + +void FanucAdapter::getMessages() +{ + if (!mConnected) + return; + + OPMSG messages[6] = {0}; + auto ret = cnc_rdopmsg(mFlibhndl, 0, 6 + 256, messages); + if (ret == EW_OK && messages->datano != -1) + { + char buf[32] = {0}; + sprintf(buf, "%04d", messages->datano); + mMessage.setValue(messages->data, buf); + } +} + + +void FanucAdapter::getCounts() +{ + if (!mConnected) + return; + + // Should just be a parameter read + IODBPSD buf = {0}; + auto ret = cnc_rdparam(mFlibhndl, 6711, 0, 8, &buf); + if (ret == EW_OK) + mPartCount.setValue(buf.u.ldata); +} + + +void FanucAdapter::getPathData() +{ + if (!mConnected) + return; + + for(auto &path : mPaths) + { + if(!path->gatherData(mFlibhndl)) + { + disconnect(); + break; + } + } + + if (mConnected && mPaths.size() > 0) + cnc_setpath(mFlibhndl, 0); +} diff --git a/fanuc/fanuc_adapter.hpp b/fanuc/fanuc_adapter.hpp index 6640e92..96e189a 100644 --- a/fanuc/fanuc_adapter.hpp +++ b/fanuc/fanuc_adapter.hpp @@ -1,126 +1,150 @@ -/* - * Copyright Copyright 2012, System Insights, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FANUC_ADAPTER_HPP -#define FANUC_ADAPTER_HPP - -#include "adapter.hpp" -#include "condition.hpp" -#include "device_datum.hpp" -#include "service.hpp" -#include "fanuc_path.hpp" -#include "Fwlib32.h" -#include - -#define MAX_MACROS 32 -#define MAX_PMC 32 -const int MAX_HOST_LEN = 64; - -class MacroSample : public Sample -{ -protected: - int mNumber; - -public: - MacroSample(const char *aName, int aNum) : - Sample(aName), mNumber(aNum) {} - int getNumber() { return mNumber; } -}; - -class MacroPathPosition : public PathPosition -{ -protected: - int mX; - int mY; - int mZ; - -public: - MacroPathPosition(const char *aName, int aX, int aY, int aZ) : - PathPosition(aName), mX(aX), mY(aY), mZ(aZ) {} - int getX() { return mX; } - int getY() { return mY; } - int getZ() { return mZ; } -}; - -/* - * Provides a connection to the data available from the FANUC Focus library. - */ -class FanucAdapter : public Adapter, public MTConnectService -{ -protected: - /* Define all the data values here */ - short mMaxPath; - std::vector mPaths; - - - /* Conditions */ - - /* Events */ - Message mMessage; - - Availability mAvail; - IntEvent mPartCount; - - /* Macro variables */ - MacroSample *mMacroSample[MAX_MACROS]; - MacroPathPosition *mMacroPath[MAX_MACROS]; - int mMacroMin; - int mMacroMax; - int mMacroSampleCount; - int mMacroPathCount; - - /* Macro variables */ - IntEvent *mPMCVariable[MAX_PMC]; - int mPMCAddress[MAX_PMC]; - int mPMCCount; - - unsigned short mFlibhndl; - bool mConnected, mConfigured; - bool mAllowDNC; - int mDevicePort; - char mDeviceIP[MAX_HOST_LEN]; - -protected: - void connect(); - void configure(); - void configMacrosAndPMC(const char *aIniFile); - - void reconnect(); - void disconnect(); - void getMessages(); - - void getPathData(); - - void getMacros(); - void getPMC(); - - void getCounts(); - - void innerGatherDeviceData(); - -public: - FanucAdapter(int aServerPort); - ~FanucAdapter(); - - // For Service - virtual void initialize(int aArgc, const char *aArgv[]); - virtual void start(); - virtual void stop(); - - virtual void gatherDeviceData(); -}; - -#endif +// +// Copyright Copyright 2012, System Insights, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include "fanuc_path.hpp" + + +constexpr int MAX_MACROS = 256; // Max number of entries in the ini file +constexpr int MAX_PMC = 32; + + +class MacroSample : public Sample +{ +protected: + int mNumber; + +public: + MacroSample(const char *aName, int aNum) : + Sample(aName), + mNumber(aNum) + { + } + + int getNumber() const { + return mNumber; } +}; + + +class MacroPathPosition : public PathPosition +{ +protected: + int m_X; + int m_Y; + int m_Z; + +public: + MacroPathPosition(const char *name, int X, int Y, int Z) : + PathPosition(name), + m_X(X), + m_Y(Y), + m_Z(Z) + { + } + + int getX() const { + return m_X; } + int getY() const { + return m_Y; } + int getZ() const { + return m_Z; } +}; + + +class PmcVariable : public IntEvent +{ +protected: + int mAddress; + +public: + PmcVariable(const char *name, int address) : + IntEvent(name), + mAddress(address) + { + } + + int getAddress() const { + return mAddress; } +}; + + +// +// Provides a connection to the data available from the FANUC Focus library. +// +class FanucAdapter : public Adapter, public MTConnectService +{ +protected: + // Define all the data values here + std::vector> mPaths; + + + // Conditions + + // Events + Message mMessage; + + Availability mAvail; + IntEvent mPartCount; + + // Macro variables + std::vector mMacroSamples; + std::vector mMacroPathPositions; + int mMacroMin; + int mMacroMax; + + // PMC variables + std::vector mPMCVariables; + + unsigned short mFlibhndl; + bool mConnected, mConfigured; + int mDevicePort; + char mDeviceIP[64]; + +protected: + void connect(); + void configure(); + void configMacrosAndPMC(const char *iniFile); + + void reconnect(); + void disconnect(); + void getMessages(); + + void getPathData(); + + void getMacros(); + void getPMC(); + + void getCounts(); + + void innerGatherDeviceData(); + +public: + FanucAdapter(int serverPort); + ~FanucAdapter(); + + // For Service + void initialize(int argc, const char *argv[]) final; + void start() final; + void stop() final; + + void gatherDeviceData() final; +}; diff --git a/fanuc/fanuc_axis.cpp b/fanuc/fanuc_axis.cpp index 3bfe83d..e6e3c54 100644 --- a/fanuc/fanuc_axis.cpp +++ b/fanuc/fanuc_axis.cpp @@ -1,65 +1,67 @@ -/* - * Copyright Copyright 2012, System Insights, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "internal.hpp" -#include "Fwlib32.h" -#include "fanuc_path.hpp" -#include "logger.hpp" - -using namespace std; - -FanucAxis::FanucAxis(Adapter *anAdapter, string aPrefix, int aIndex) - : mIndex(aIndex), mDivisor(1.0) -{ - mActual.setName((aPrefix + "act").c_str()); - anAdapter->addDatum(mActual); - mLoad.setName((aPrefix + "load").c_str()); - anAdapter->addDatum(mLoad); - mTravel.setName((aPrefix + "travel").c_str()); - anAdapter->addDatum(mTravel); - mOverheat.setName((aPrefix + "overheat").c_str()); - anAdapter->addDatum(mOverheat); - mServo.setName((aPrefix + "servo").c_str()); - anAdapter->addDatum(mServo); -} - -bool FanucAxis::gatherData(ODBDY2 *aDynamic, ODBSVLOAD *aLoads) -{ - mActual.setValue(aDynamic->pos.faxis.machine[mIndex] / mDivisor); - mLoad.setValue(aLoads[mIndex].svload.data / - pow((long double) 10.0, (long double) aLoads[mIndex].svload.dec)); - return true; -} - -FanucSpindle::FanucSpindle(Adapter *anAdapter, string aPrefix, int aIndex) - : mIndex(aIndex) -{ - mSpeed.setName((aPrefix + "speed").c_str()); - anAdapter->addDatum(mSpeed); - mLoad.setName((aPrefix + "load").c_str()); - anAdapter->addDatum(mLoad); - mServo.setName((aPrefix + "servo").c_str()); - anAdapter->addDatum(mServo); -} - -bool FanucSpindle::gatherData(ODBSPLOAD *aLoads, ODBACT2 *aSpeeds) -{ - mLoad.setValue(aLoads[mIndex].spload.data / - pow((long double) 10.0, (long double) aLoads[mIndex].spload.dec)); - mSpeed.setValue(aSpeeds->data[mIndex]); - return true; -} - +// +// Copyright Copyright 2012, System Insights, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "internal.hpp" +#include "fanuc_axis.hpp" +#include +#include "fanuc_path.hpp" +#include "fanuc_helpers.hpp" + +using namespace std; + + +FanucAxis::FanucAxis(Adapter *adapter, string const &prefix, int index) : + mIndex(index), + mDivisor(1.0) +{ + mActual.setName((prefix + "act").c_str()); + adapter->addDatum(mActual); + mLoad.setName((prefix + "load").c_str()); + adapter->addDatum(mLoad); + mTravel.setName((prefix + "travel").c_str()); + adapter->addDatum(mTravel); + mOverheat.setName((prefix + "overheat").c_str()); + adapter->addDatum(mOverheat); + mServo.setName((prefix + "servo").c_str()); + adapter->addDatum(mServo); +} + + +bool FanucAxis::gatherData(const ODBDY2 *dynamic, const ODBSVLOAD *loads) +{ + mActual.setValue(dynamic->pos.faxis.machine[mIndex] / mDivisor); + mLoad.setValue( convert_bin_to_dec(loads[mIndex].svload.data, loads[mIndex].svload.dec) ); + return true; +} + + +FanucSpindle::FanucSpindle(Adapter *adapter, string const &prefix, int index) : + mIndex(index) +{ + mSpeed.setName((prefix + "speed").c_str()); + adapter->addDatum(mSpeed); + mLoad.setName((prefix + "load").c_str()); + adapter->addDatum(mLoad); + mServo.setName((prefix + "servo").c_str()); + adapter->addDatum(mServo); +} + + +bool FanucSpindle::gatherData(const ODBSPLOAD *loads, const ODBACT2 *aSpeeds) +{ + mLoad.setValue( convert_bin_to_dec(loads[mIndex].spload.data, loads[mIndex].spload.dec) ); + mSpeed.setValue(aSpeeds->data[mIndex]); + return true; +} diff --git a/fanuc/fanuc_axis.hpp b/fanuc/fanuc_axis.hpp index 49e074d..02cf61f 100644 --- a/fanuc/fanuc_axis.hpp +++ b/fanuc/fanuc_axis.hpp @@ -1,60 +1,57 @@ -/* - * Copyright Copyright 2012, System Insights, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "device_datum.hpp" -#include "condition.hpp" -#include "adapter.hpp" -#include -#include "Fwlib32.h" - -class FanucAxis -{ -public: - FanucAxis(Adapter *anAdapter, std::string aPrefix, int anIndex); - ~FanucAxis() {} - - bool gatherData(ODBDY2 *aDynamic, ODBSVLOAD *aLoads); - -public: - int mIndex; - - Sample mActual; - Sample mLoad; - - double mDivisor; - - Condition mTravel; - Condition mOverheat; - Condition mServo; -}; - -class FanucSpindle -{ -public: - FanucSpindle(Adapter *anAdapter, std::string aPrefix, int anIndex); - ~FanucSpindle() {} - - bool gatherData(ODBSPLOAD *aLoads, ODBACT2 *aSpeeds); - -public: - int mIndex; - - Sample mSpeed; - Sample mLoad; - - Condition mServo; -}; +// +// Copyright Copyright 2012, System Insights, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#pragma once + +#include +#include +#include +#include +#include + + +class FanucAxis +{ +public: + FanucAxis(Adapter *adapter, std::string const &prefix, int index); + ~FanucAxis() {} + + bool gatherData(const ODBDY2 *dynamic, const ODBSVLOAD *loads); + +public: + int mIndex; + Sample mActual; + Sample mLoad; + double mDivisor; + Condition mTravel; + Condition mOverheat; + Condition mServo; +}; + + +class FanucSpindle +{ +public: + FanucSpindle(Adapter *adapter, std::string const &prefix, int index); + ~FanucSpindle() {} + + bool gatherData(const ODBSPLOAD *loads, const ODBACT2 *speeds); + +public: + int mIndex; + Sample mSpeed; + Sample mLoad; + Condition mServo; +}; diff --git a/fanuc/fanuc_helpers.hpp b/fanuc/fanuc_helpers.hpp new file mode 100644 index 0000000..7fe87a1 --- /dev/null +++ b/fanuc/fanuc_helpers.hpp @@ -0,0 +1,24 @@ +// +// Copyright Copyright 2012, System Insights, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#pragma once + +#include + +// The Focas API returns decimal numbers with signed binary format. +inline double convert_bin_to_dec(long numeric, short exponent) +{ + return pow(10.0, -exponent) * numeric; +} \ No newline at end of file diff --git a/fanuc/fanuc_path.cpp b/fanuc/fanuc_path.cpp index 5c3ae1f..685e27b 100644 --- a/fanuc/fanuc_path.cpp +++ b/fanuc/fanuc_path.cpp @@ -1,615 +1,577 @@ -/* - * Copyright Copyright 2012, System Insights, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// +// Copyright Copyright 2012, System Insights, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// #include "internal.hpp" -#include "Fwlib32.h" #include "fanuc_path.hpp" -#include "logger.hpp" - #include +#include +#include using namespace std; -void FanucPath::addDatum(DeviceDatum &aDatum, const char *aName, const char *aSuffix) +// C++11 helper function for obtaining a statically defined array's item count +template +constexpr std::size_t countof(T const (&)[N]) noexcept { - char name[32]; - strcpy(name, aName); strcat(name, aSuffix); - aDatum.setName(name); - mAdapter->addDatum(aDatum); + return N; } -FanucPath::FanucPath(Adapter *anAdapter, short aPathNumber) - : mAdapter(anAdapter), mPathNumber(aPathNumber), mXAxis(NULL), mYAxis(NULL), - mZAxis(NULL), mToolManagementEnabled(true), mUseModalToolData(false), - mAllowDNC(true) + +void FanucPath::addDatum(DeviceDatum &datum, const char *name, const char *suffix) { - char number[2]; - if (aPathNumber > 1) - sprintf(number, "%d", aPathNumber); - else - number[0] = '\0'; - - addDatum(mToolId, "tool_id", number); - addDatum(mToolGroup, "tool_group", number); - addDatum(mProgramName, "program", number); - addDatum(mProgramComment, "program_comment", number); - addDatum(mLine, "line", number); - addDatum(mBlock, "block", number); - addDatum(mPathFeedrate, "path_feedrate", number); - addDatum(mPathPosition, "path_position", number); - addDatum(mActiveAxes, "active_axes", number); - addDatum(mMode, "mode", number); - addDatum(mServo, "servo", number); - addDatum(mComms, "comms", number); - addDatum(mLogic, "logic", number); - addDatum(mMotion, "motion", number); - addDatum(mSystem, "system", number); - addDatum(mExecution, "execution", number); - addDatum(mCommandedFeedrate, "f_command", number); - - // Only track estop on the first path. Should be the same for all - // paths, only one estop per machine. - if (aPathNumber == 1) - addDatum(mEStop, "estop", number); + std::string datumName(name); + datumName.append(suffix); + datum.setName(datumName.c_str()); + mAdapter->addDatum(datum); } -FanucPath::~FanucPath() + +FanucPath::FanucPath(Adapter *adapter, short pathNumber) : + mAdapter(adapter), + mPathNumber(pathNumber), + mProgramNum(-1), + mSpindleCount(0), + mAxisCount(0), + mToolManagementEnabled(true), + mUseModalToolData(false), + mXAxis(nullptr), + mYAxis(nullptr), + mZAxis(nullptr) { - size_t i; - for (i = 0; i < mAxes.size(); i++) - delete mAxes[i]; - mAxes.clear(); - - i; - for (i = 0; i < mSpindles.size(); i++) - delete mSpindles[i]; - mSpindles.clear(); + auto pathNumAsString = std::to_string(pathNumber); + if(pathNumber <= 1) + pathNumAsString.clear(); + + addDatum(mToolId, "tool_id", pathNumAsString.c_str()); + addDatum(mToolGroup, "tool_group", pathNumAsString.c_str()); + addDatum(mProgramName, "program", pathNumAsString.c_str()); + addDatum(mProgramComment, "program_comment", pathNumAsString.c_str()); + addDatum(mLine, "line", pathNumAsString.c_str()); + addDatum(mBlock, "block", pathNumAsString.c_str()); + addDatum(mPathFeedrate, "path_feedrate", pathNumAsString.c_str()); + addDatum(mPathPosition, "path_position", pathNumAsString.c_str()); + addDatum(mActiveAxes, "active_axes", pathNumAsString.c_str()); + addDatum(mMode, "mode", pathNumAsString.c_str()); + addDatum(mServo, "servo", pathNumAsString.c_str()); + addDatum(mComms, "comms", pathNumAsString.c_str()); + addDatum(mLogic, "logic", pathNumAsString.c_str()); + addDatum(mMotion, "motion", pathNumAsString.c_str()); + addDatum(mSystem, "system", pathNumAsString.c_str()); + addDatum(mExecution, "execution", pathNumAsString.c_str()); + addDatum(mCommandedFeedrate, "f_command", pathNumAsString.c_str()); + + // Only track estop on the first path. Should be the same for all + // paths, only one estop per machine. + if (pathNumber == 1) + addDatum(mEStop, "estop", pathNumAsString.c_str()); } -bool FanucPath::configure(unsigned short aFlibhndl) +FanucPath::~FanucPath() { - int ret = cnc_setpath(aFlibhndl, mPathNumber); - if (ret != EW_OK) - { - gLogger->error("Could not cnc_setpath: %d"); - return false; - } - - gLogger->info("Configuration for path %d:", mPathNumber); - - // Get system info for this path: - ODBSYS sysinfo; - ret = cnc_sysinfo(aFlibhndl, &sysinfo); - if (ret == EW_OK) - { - gLogger->info(" Max Axis: %d", sysinfo.max_axis); - gLogger->info(" CNC Type: %c%c", sysinfo.cnc_type[0], sysinfo.cnc_type[1]); - gLogger->info(" MT Type: %c%c", sysinfo.mt_type[0], sysinfo.mt_type[1]); - gLogger->info(" Series: %c%c", sysinfo.series[0], sysinfo.series[1], sysinfo.series[2], sysinfo.series[3]); - gLogger->info(" Version: %c%c", sysinfo.version[0], sysinfo.version[1], sysinfo.version[2], sysinfo.version[3]); - gLogger->info(" Axes: %c%c", sysinfo.axes[0], sysinfo.axes[1]); - } - - - return configureAxes(aFlibhndl) && - configureSpindles(aFlibhndl); + for (auto axis : mAxes) + delete axis; + mAxes.clear(); + + for (auto spindle : mSpindles) + delete spindle; + mSpindles.clear(); } -bool FanucPath::configureSpindles(unsigned short aFlibhndl) + +bool FanucPath::configure(unsigned short flibhndl) { - ODBSPDLNAME spindles[MAX_SPINDLE]; - mSpindleCount = MAX_SPINDLE; - short ret = cnc_rdspdlname(aFlibhndl, &mSpindleCount, spindles); - if (ret == EW_OK) - { - int i = 0; - for (i = 0; i < mSpindleCount; i++) - { - gLogger->info("Spindle %d : %c%c%c", i, spindles[i].name, spindles[i].suff1, spindles[i].suff2); - char name[12]; - int j = 0; - name[j++] = spindles[i].name; - if (spindles[i].suff1 > 0) - name[j++] = spindles[i].suff1; - if (mPathNumber > 1) - name[j++] = mPathNumber + '0'; - name[j] = '\0'; - - mSpindles.push_back(new FanucSpindle(mAdapter, name, i)); - } - - return true; - } - else - { - gLogger->error("Failed to get splindle names: %d", ret); - return false; - } + auto ret = cnc_setpath(flibhndl, mPathNumber); + if (ret != EW_OK) + { + gLogger->error("Could not cnc_setpath: %d"); + return false; + } + + gLogger->info("Configuration for path %d:", mPathNumber); + + // Get system info for this path: + ODBSYS sysinfo = {0}; + ret = cnc_sysinfo(flibhndl, &sysinfo); + if (ret == EW_OK) + { + gLogger->info(" Max Axis: %d", sysinfo.max_axis); + gLogger->info(" CNC Type: %c%c", sysinfo.cnc_type[0], sysinfo.cnc_type[1]); + gLogger->info(" MT Type: %c%c", sysinfo.mt_type[0], sysinfo.mt_type[1]); + gLogger->info(" Series: %c%c%c%c", sysinfo.series[0], sysinfo.series[1], sysinfo.series[2], sysinfo.series[3]); + gLogger->info(" Version: %c%c%c%c", sysinfo.version[0], sysinfo.version[1], sysinfo.version[2], sysinfo.version[3]); + gLogger->info(" Axes: %c%c", sysinfo.axes[0], sysinfo.axes[1]); + } + + + return configureAxes(flibhndl) && configureSpindles(flibhndl); } -bool FanucPath::configureAxes(unsigned short aFlibhndl) + +bool FanucPath::configureSpindles(unsigned short flibhndl) { - const int num = 1; - short types[num] = { 1 /* actual position */ }; - short len = MAX_AXIS; - ODBAXDT axisData[MAX_AXIS * num]; - short ret = cnc_rdaxisdata(aFlibhndl, 1 /* Position Value */, (short*) types, num, &len, axisData); - bool hasAxisData = ret == EW_OK; - if (!hasAxisData) - { - gLogger->error("cnc_rdaxisdata returned %d for path %d", ret, mPathNumber); - } - - ODBAXISNAME axes[MAX_AXIS]; - mAxisCount = MAX_AXIS; - ret = cnc_rdaxisname(aFlibhndl, &mAxisCount, axes); - if (ret == EW_OK) - { - int i = 0; - string activeAxes; - for (i = 0; i < mAxisCount; i++) - { - bool add = true; - gLogger->info("Axis %d : %c%c", i, axes[i].name, axes[i].suff); - if (hasAxisData) - { - gLogger->info("Axis %s #%d - actual (unit %d flag 0x%X)", - axisData[i].name, i, axisData[i].unit, axisData[i].flag); - // Skip this axis if it isn't displayed - if ((axisData[i].flag & 0x01) == 0) - { - gLogger->info(" This is an non-display axis, skipping"); - add = false; - } - - switch (axisData[i].unit) - { - case 0: gLogger->info(" Units: mm"); break; - case 1: gLogger->info(" Units: inch"); break; - case 2: gLogger->info(" Units: degree"); break; - case 3: gLogger->info(" Units: mm/minute"); break; - case 4: gLogger->info(" Units: inch/minute"); break; - case 5: gLogger->info(" Units: rpm"); break; - case 6: gLogger->info(" Units: mm/round"); break; - case 7: gLogger->info(" Units: inch/round"); break; - case 8: gLogger->info(" Units: %%"); break; - case 9: gLogger->info(" Units: Ampere"); break; - } - } - - if (add) - { - if (mAxes.size() > 0) - activeAxes += " "; - - char name[12]; - int j = 0; - name[j++] = axes[i].name; - if (axes[i].suff > 0) - name[j++] = axes[i].suff; - name[j] = '\0'; - - activeAxes += name; - - FanucAxis *axis = new FanucAxis(mAdapter, name, i); - mAxes.push_back(axis); - - if (axes[i].name == 'X' && (axes[i].suff == 0 || mXAxis == NULL)) - mXAxis = axis; - else if (axes[i].name == 'Y' && (axes[i].suff == 0 || mYAxis == NULL)) - mYAxis = axis; - else if (axes[i].name == 'Z' && (axes[i].suff == 0 || mZAxis == NULL)) - mZAxis = axis; - } - } - mActiveAxes.setValue(activeAxes.c_str()); - } - else - { - gLogger->error("Failed to get axis names: %d\n", ret); - exit(999); - } - - short count, inprec[MAX_AXIS], outprec[MAX_AXIS]; - ret = cnc_getfigure(aFlibhndl, 0, &count, inprec, outprec); - if (ret == EW_OK) - { - for (size_t i = 0; i < mAxes.size(); i++) - mAxes[i]->mDivisor = pow((long double) 10.0, (long double) inprec[i]); - } - else - { - gLogger->error("Failed to get axis scale: %d\n", ret); - return false; - } - - return true; + ODBSPDLNAME spindles[MAX_SPINDLE] = {0}; + mSpindleCount = static_cast(countof(spindles)); + short ret = cnc_rdspdlname(flibhndl, &mSpindleCount, spindles); + if (ret != EW_OK) + { + gLogger->error("Failed to get splindle names: %d", ret); + return false; + } + + + for (auto i = 0; i < mSpindleCount; i++) + { + const auto &spindle = spindles[i]; + gLogger->info("Spindle %d : %c%c%c%c", i, spindle.name, spindle.suff1, spindle.suff2, spindle.suff3); + std::string name = {spindle.name, spindle.suff1}; + if (mPathNumber > 1) + name.append(std::to_string(mPathNumber)); + + mSpindles.push_back(new FanucSpindle(mAdapter, name.c_str(), i)); + } + + return true; } -bool FanucPath::gatherData(unsigned short aFlibhndl) + +bool FanucPath::configureAxes(unsigned short flibhndl) { - int ret; - ret = cnc_setpath(aFlibhndl, mPathNumber); - if (ret != EW_OK) - { - gLogger->error("Cannot set path to: %d, %d", ret); - return false; - } - - return getProgramInfo(aFlibhndl) && - getStatus(aFlibhndl) && - getAxisData(aFlibhndl) && - getSpindleData(aFlibhndl) && - getToolData(aFlibhndl); + const int num = 1; + short types[num] = { 1 /* actual position */ }; + short len = MAX_AXIS; + ODBAXDT axisData[MAX_AXIS * num] = {0}; + auto ret = cnc_rdaxisdata( + flibhndl, + 1, // Position Value + types, + num, + &len, + axisData); + + bool hasAxisData = ret == EW_OK; + if (!hasAxisData) + gLogger->error("cnc_rdaxisdata returned %d for path %d", ret, mPathNumber); + + ODBAXISNAME axes[MAX_AXIS] = {0}; + mAxisCount = MAX_AXIS; + ret = cnc_rdaxisname(flibhndl, &mAxisCount, axes); + if (ret != EW_OK) + { + gLogger->error("Failed to get axis names: %d\n", ret); + exit(999); + } + + string activeAxes; + for (auto i = 0; i < mAxisCount; i++) + { + bool add = true; + gLogger->info("Axis %d : %c%c", i, axes[i].name, axes[i].suff); + if (hasAxisData) + { + gLogger->info("Axis %s #%d - actual (unit %d flag 0x%X)", + axisData[i].name, + i, + axisData[i].unit, + axisData[i].flag); + + // Skip this axis if it isn't displayed + if ((axisData[i].flag & 0x01) == 0) + { + gLogger->info(" This is an non-display axis, skipping"); + add = false; + } + + switch (axisData[i].unit) + { + case 0: + gLogger->info(" Units: mm"); + break; + case 1: + gLogger->info(" Units: inch"); + break; + case 2: + gLogger->info(" Units: degree"); + break; + case 3: + gLogger->info(" Units: mm/minute"); + break; + case 4: + gLogger->info(" Units: inch/minute"); + break; + case 5: + gLogger->info(" Units: rpm"); + break; + case 6: + gLogger->info(" Units: mm/round"); + break; + case 7: + gLogger->info(" Units: inch/round"); + break; + case 8: + gLogger->info(" Units: %%"); + break; + case 9: + gLogger->info(" Units: Ampere"); + break; + } + } + + if (!add) + continue; + + if (mAxes.size() > 0) + activeAxes += " "; + + std::string axisName = {axes[i].name, axes[i].suff}; + activeAxes.append(axisName.c_str()); + + auto axis = new FanucAxis(mAdapter, axisName.c_str(), i); + mAxes.push_back(axis); + + if (axes[i].name == 'X' && (!axes[i].suff || mXAxis == nullptr)) + mXAxis = axis; + else if (axes[i].name == 'Y' && (!axes[i].suff || mYAxis == nullptr)) + mYAxis = axis; + else if (axes[i].name == 'Z' && (!axes[i].suff || mZAxis == nullptr)) + mZAxis = axis; + + } + mActiveAxes.setValue(activeAxes.c_str()); + + + short count, inprec[MAX_AXIS] = {0}, outprec[MAX_AXIS] = {0}; + ret = cnc_getfigure(flibhndl, 0, &count, inprec, outprec); + if (ret != EW_OK) + { + gLogger->error("Failed to get axis scale: %d\n", ret); + return false; + } + + for(const auto axis : mAxes) + axis->mDivisor = pow((long double) 10.0, (long double) inprec[axis->mIndex]); + + return true; } -bool FanucPath::getProgramInfo(unsigned short aFlibhndl) + +bool FanucPath::gatherData(unsigned short flibhndl) { - int ret; - char buf[1024]; - unsigned short len = sizeof(buf); - short num; - ret = cnc_rdexecprog(aFlibhndl, (unsigned short*) &len, &num, buf); - if (ret == EW_OK) - { - buf[len] = '\0'; - for (int i = 0; i < len; i++) - { - if (buf[i] == '\n') - { - buf[i] = '\0'; - break; - } - } - - mBlock.setValue(buf); - - return true; - } - else - { - gLogger->error("Cannot cnc_rdexecprog for path %d: %d", mPathNumber, ret); - return false; - } + auto ret = cnc_setpath(flibhndl, mPathNumber); + if (ret != EW_OK) + { + gLogger->error("Cannot set path to: %d, %d", ret); + return false; + } + + return getProgramInfo(flibhndl) && + getStatus(flibhndl) && + getAxisData(flibhndl) && + getSpindleData(flibhndl) && + getToolData(flibhndl); } -bool FanucPath::getStatus(unsigned short aFlibhndl) + +bool FanucPath::getProgramInfo(unsigned short flibhndl) { - ODBST status; - memset(&status, 0, sizeof(status)); - int ret = cnc_statinfo(aFlibhndl, &status); - if (ret == EW_OK) - { - if (status.run == 3 || status.run == 4) // STaRT - mExecution.setValue(Execution::eACTIVE); - else - { - if (status.run == 2 || status.motion == 2 || status.mstb != 0) // HOLD or motion is Wait - mExecution.setValue(Execution::eINTERRUPTED); - else if (status.run == 0) // STOP - mExecution.setValue(Execution::eSTOPPED); - else - mExecution.setValue(Execution::eREADY); - } - - // This will take care of JOG - if (status.aut == 5 || status.aut == 6) - mMode.setValue(ControllerMode::eMANUAL); - else if (status.aut == 0 ||status.aut == 3) // MDI and EDIT - mMode.setValue(ControllerMode::eMANUAL_DATA_INPUT); - else // Otherwise AUTOMATIC - mMode.setValue(ControllerMode::eAUTOMATIC); - - if (mPathNumber == 1) - { - if (status.emergency == 1) - mEStop.setValue(EmergencyStop::eTRIGGERED); - else - mEStop.setValue(EmergencyStop::eARMED); - } - return true; - } - else - { - gLogger->error("Cannot cnc_statinfo for path %d: %d", mPathNumber, ret); - return false; - } + char buf[1024] = {0}; + unsigned short len = sizeof(buf); + short num(0); + auto ret = cnc_rdexecprog(flibhndl, (unsigned short*) &len, &num, buf); + if (ret == EW_OK) + { + for (auto i = 0; i < len; i++) + { + if (buf[i] == '\n') + { + buf[i] = '\0'; + break; + } + } + mBlock.setValue(buf); + return true; + } + else + { + gLogger->error("Cannot cnc_rdexecprog for path %d: %d", mPathNumber, ret); + return false; + } } -bool FanucPath::getToolData(unsigned short aFlibhndl) + +bool FanucPath::getStatus(unsigned short flibhndl) { - if (mToolManagementEnabled) - { - ODBTLIFE4 toolId2; - short ret = cnc_toolnum(aFlibhndl, 0, 0, &toolId2); - - ODBTLIFE3 toolId; - ret = cnc_rdntool(aFlibhndl, 0, &toolId); - if (ret == EW_OK && toolId.data != 0) - { - mToolId.setValue(toolId.data); - mToolGroup.setValue(toolId.datano); - } - else - { - gLogger->warning("Cannot cnc_rdntool for path %d: %d", mPathNumber, ret); - mToolManagementEnabled = false; - gLogger->warning("Trying modal tool number", mPathNumber, ret); - mUseModalToolData = true; - } - } - - if (mUseModalToolData) - { - ODBMDL command; - short ret = cnc_modal(aFlibhndl, 108, 1, &command); - if (ret == EW_OK) - { - //gLogger->debug("cnc_modal returned: datano %d and type %d: %d %X %X", - // command.datano, command.type, command.modal.aux.aux_data, command.modal.aux.flag1, - // command.modal.aux.flag2); - mToolId.setValue(command.modal.aux.aux_data); - } - else - { - gLogger->warning("cnc_modal failed for T on path %d: %d", mPathNumber, ret); - mUseModalToolData = false; - } - } - - return true; + ODBST status = {0}; + auto ret = cnc_statinfo(flibhndl, &status); + if (ret != EW_OK) + { + gLogger->error("Cannot cnc_statinfo for path %d: %d", mPathNumber, ret); + return false; + } + + if (status.run == 3 || status.run == 4) // STaRT + mExecution.setValue(Execution::eACTIVE); + else + { + if (status.run == 2 || status.motion == 2 || status.mstb != 0) // HOLD or motion is Wait + mExecution.setValue(Execution::eINTERRUPTED); + else if (status.run == 0) // STOP + mExecution.setValue(Execution::eSTOPPED); + else + mExecution.setValue(Execution::eREADY); + } + + // This will take care of JOG + if (status.aut == 5 || status.aut == 6) + mMode.setValue(ControllerMode::eMANUAL); + else if (status.aut == 0 ||status.aut == 3) // MDI and EDIT + mMode.setValue(ControllerMode::eMANUAL_DATA_INPUT); + else // Otherwise AUTOMATIC + mMode.setValue(ControllerMode::eAUTOMATIC); + + if (mPathNumber == 1) + { + if (status.emergency == 1) + mEStop.setValue(EmergencyStop::eTRIGGERED); + else + mEStop.setValue(EmergencyStop::eARMED); + } + return true; + } -bool FanucPath::getHeader(unsigned short aFlibhndl, int aProg) + +bool FanucPath::getToolData(unsigned short flibhndl) { - /* This is not needed since we're getting the codes from - macros now. */ - if (!mAllowDNC) - return true; - - char program[2048]; - short ret = cnc_upstart(aFlibhndl, aProg); - if (ret == EW_OK) - { - // One for the \0 terminator - long len = sizeof(program) - 1; - do - { - ret = cnc_upload3(aFlibhndl, &len, program); - if (ret == EW_OK) - { - bool nl = false; - program[len] = '\0'; - int lineCount = 0; - for (char *cp = program; *cp != '\0' && lineCount < 5; ++cp) - { - //printf("%d ", *cp); - // When we get a new line, check for the first empty line - // following with only spaces, ; or carriage returns. If - // a new line follows, then terminate the header and set the - // program comment. - if (*cp == '\n') - { - char f = *(cp + 1); - if (lineCount > 0 && f != '(') - { - *cp = '\0'; - break; - } - *cp = ' '; - lineCount++; - } - } - //printf("\n"); - mProgramComment.setValue(program); - } - } while (ret == EW_BUFFER); - } - cnc_upend3(aFlibhndl); - - return true; + if (mToolManagementEnabled) + { + ODBTLIFE4 toolId2 = {0}; + auto ret = cnc_toolnum(flibhndl, 0, 0, &toolId2); + + ODBTLIFE3 toolId = {0}; + ret = cnc_rdntool(flibhndl, 0, &toolId); + if (ret == EW_OK && toolId.data != 0) + { + mToolId.setValue(toolId.data); + mToolGroup.setValue(toolId.datano); + } + else + { + gLogger->warning("Cannot cnc_rdntool for path %d: %d", mPathNumber, ret); + mToolManagementEnabled = false; + gLogger->warning("Trying modal tool number", mPathNumber, ret); + mUseModalToolData = true; + } + } + + if (mUseModalToolData) + { + ODBMDL command {0}; + auto ret = cnc_modal(flibhndl, 108, 1, &command); + if (ret == EW_OK) + { + //gLogger->debug("cnc_modal returned: datano %d and type %d: %d %X %X", + // command.datano, command.type, command.modal.aux.aux_data, command.modal.aux.flag1, + // command.modal.aux.flag2); + mToolId.setValue(command.modal.aux.aux_data); + } + else + { + gLogger->warning("cnc_modal failed for T on path %d: %d", mPathNumber, ret); + mUseModalToolData = false; + } + } + + return true; } -bool FanucPath::getAxisData(unsigned short aFlibhndl) + +bool FanucPath::getAxisData(unsigned short flibhndl) { - if (mAxisCount <= 0) - return true; - - short ret; - - int maxAxes = MAX_AXIS; - - ODBDY2 dyn; - memset(&dyn, 0xEF, sizeof(dyn)); - ret = cnc_rddynamic2(aFlibhndl, ALL_AXES, sizeof(dyn), &dyn); - if (ret != EW_OK) - { - gLogger->error("Cannot get the rddynamic2 data for path %d: %d", mPathNumber, ret); - return false; - } - - mLine.setValue(dyn.seqnum); - - ODBSVLOAD axLoad[MAX_AXIS]; - short num = MAX_AXIS; - ret = cnc_rdsvmeter(aFlibhndl, &num, axLoad); - if (ret != EW_OK) - { - gLogger->error("cnc_rdsvmeter failed for path %d: %d", mPathNumber, ret); - return false; - } - - char buf[32]; - if (dyn.prgnum != mProgramNum) - getHeader(aFlibhndl, dyn.prgnum); - - mProgramNum = dyn.prgnum; - sprintf(buf, "%d.%d", dyn.prgmnum, dyn.prgnum); - mProgramName.setValue(buf); - - // Update all the axes - vector::iterator axis; - for (axis = mAxes.begin(); axis != mAxes.end(); axis++) - { - (*axis)->gatherData(&dyn, axLoad); - } - - mPathFeedrate.setValue(dyn.actf); - - // Get the modal feed for this path - ODBMDL command; - ret = cnc_modal(aFlibhndl, 103, 1, &command); - if (ret == EW_OK) - { - mCommandedFeedrate.setValue(command.modal.aux.aux_data); - } - - double x = 0.0, y = 0.0, z = 0.0; - if (mXAxis != NULL) - x = dyn.pos.faxis.absolute[mXAxis->mIndex] / mXAxis->mDivisor; - if (mYAxis != NULL) - y = dyn.pos.faxis.absolute[mYAxis->mIndex] / mYAxis->mDivisor; - if (mZAxis != NULL) - z = dyn.pos.faxis.absolute[mZAxis->mIndex] / mZAxis->mDivisor; - - mPathPosition.setValue(x, y, z); - - getCondition(aFlibhndl, dyn.alarm); - - - return true; + if (mAxisCount <= 0) + return true; + + ODBDY2 dyn = {0}; + auto ret = cnc_rddynamic2(flibhndl, ALL_AXES, sizeof(dyn), &dyn); + if (ret != EW_OK) + { + gLogger->error("Cannot get the rddynamic2 data for path %d: %d", mPathNumber, ret); + return false; + } + + mLine.setValue(dyn.seqnum); + + ODBSVLOAD axLoad[MAX_AXIS] = {0}; + short num = MAX_AXIS; + ret = cnc_rdsvmeter(flibhndl, &num, axLoad); + if (ret != EW_OK) + { + gLogger->error("cnc_rdsvmeter failed for path %d: %d", mPathNumber, ret); + return false; + } + + char buf[32] = {0}; + mProgramNum = dyn.prgnum; + sprintf(buf, "%d.%d", dyn.prgmnum, dyn.prgnum); + mProgramName.setValue(buf); + + // Update all the axes + for (auto axis : mAxes) + axis->gatherData(&dyn, axLoad); + + mPathFeedrate.setValue(dyn.actf); + + // Get the modal feed for this path + ODBMDL command = {0}; + ret = cnc_modal(flibhndl, 103, 1, &command); + if (ret == EW_OK) + mCommandedFeedrate.setValue(command.modal.aux.aux_data); + + double x = 0.0, y = 0.0, z = 0.0; + if (mXAxis) + x = dyn.pos.faxis.absolute[mXAxis->mIndex] / mXAxis->mDivisor; + if (mYAxis) + y = dyn.pos.faxis.absolute[mYAxis->mIndex] / mYAxis->mDivisor; + if (mZAxis) + z = dyn.pos.faxis.absolute[mZAxis->mIndex] / mZAxis->mDivisor; + + mPathPosition.setValue(x, y, z); + + getCondition(flibhndl, dyn.alarm); + return true; } -bool FanucPath::getSpindleData(unsigned short aFlibhndl) + +bool FanucPath::getSpindleData(unsigned short flibhndl) { - if (mSpindleCount <= 0) - return true; - - // Handle spindle data... - ODBACT2 speeds; - int ret = cnc_acts2(aFlibhndl, ALL_SPINDLES, &speeds); - if (ret != EW_OK) - { - gLogger->error("cnc_acts2 failed: %d for path number: %d", ret, mPathNumber); - return false; - } - - ODBSPLOAD spLoad[MAX_SPINDLE]; - short num = MAX_SPINDLE; - ret = cnc_rdspmeter(aFlibhndl, 0, &num, spLoad); - if (ret != EW_OK) - { - gLogger->error("cnc_rdspmeter failed: %d", ret); - return false; - } - - if (num > mSpindleCount) - { - gLogger->error("spindle load has more spindles than names: %d > %d\n", - num, mSpindleCount); - return false; - } - - // Update all the axes - vector::iterator spindle; - for (spindle = mSpindles.begin(); spindle != mSpindles.end(); spindle++) - { - (*spindle)->gatherData(spLoad, &speeds); - } - - return true; + if (mSpindleCount <= 0) + return true; + + // Handle spindle data... + ODBACT2 speeds = {0}; + auto ret = cnc_acts2(flibhndl, ALL_SPINDLES, &speeds); + if (ret != EW_OK) + { + gLogger->error("cnc_acts2 failed: %d for path number: %d", ret, mPathNumber); + return false; + } + + ODBSPLOAD spLoad[MAX_SPINDLE] = {0}; + short num = MAX_SPINDLE; + ret = cnc_rdspmeter(flibhndl, 0, &num, spLoad); + if (ret != EW_OK) + { + gLogger->error("cnc_rdspmeter failed: %d", ret); + return false; + } + + if (num > mSpindleCount) + { + gLogger->error("spindle load has more spindles than names: %d > %d\n", + num, mSpindleCount); + return false; + } + + // Update all the axes + for (auto spindle : mSpindles) + spindle->gatherData(spLoad, &speeds); + + return true; } -Condition *FanucPath::translateAlarmNo(long aNum, int aAxis) + +Condition *FanucPath::translateAlarmNo(long num, int axis) { - switch(aNum) - { - case 0: // Parameter Switch Off - return &mLogic; - - case 2: // I/O - case 7: // Data I/O - return &mComms; - - case 4: // Overtravel - if (aAxis > 0) - return &(mAxes[aAxis - 1]->mTravel); - else - return &mSystem; - - case 5: // Overheat - if (aAxis > 0) - return &(mAxes[aAxis - 1]->mOverheat); - else - return &mSystem; - - case 6: // Servo - if (aAxis > 0) - return &(mAxes[aAxis - 1]->mServo); - else - return &mServo; - - case 12: // Background P/S - case 3: // Forground P/S - case 8: // Macro - return &mMotion; - - case 9: // Spindle - return &(mSpindles[0]->mServo); - - case 19: // PMC - return &mLogic; - - default: // 10, 11, 13, 15. - return &mSystem; - } - - return NULL; + switch(num) + { + case 0: // Parameter Switch Off + return &mLogic; + + case 2: // I/O + case 7: // Data I/O + return &mComms; + + case 4: // Overtravel + if (axis > 0) + return &(mAxes[axis - 1]->mTravel); + else + return &mSystem; + + case 5: // Overheat + if (axis > 0) + return &(mAxes[axis - 1]->mOverheat); + else + return &mSystem; + + case 6: // Servo + if (axis > 0) + return &(mAxes[axis - 1]->mServo); + else + return &mServo; + + case 12: // Background P/S + case 3: // Forground P/S + case 8: // Macro + return &mMotion; + + case 9: // Spindle + return &(mSpindles[0]->mServo); + + case 19: // PMC + return &mLogic; + + default: // 10, 11, 13, 15. + return &mSystem; + } + + return nullptr; } -void FanucPath::getCondition(unsigned short aFlibhndl, long aAlarm) + +void FanucPath::getCondition(unsigned short flibhndl, long alarm) { - if (aAlarm != 0) - { - for (int i = 0; i < 31; i++) - { - if (aAlarm & (0x1 << i)) - { - ODBALMMSG2 alarms[MAX_AXIS]; - short num = MAX_AXIS; - - short ret = cnc_rdalmmsg2(aFlibhndl, i, &num, alarms); - if (ret != EW_OK) - continue; - - for (int j = 0; j < num; j++) - { - ODBALMMSG2 &alarm = alarms[j]; - char num[16]; - - Condition *cond = translateAlarmNo(i, alarm.axis); - if (cond == NULL) - continue; - - sprintf(num, "%d", alarm.alm_no); - cond->add(Condition::eFAULT, alarm.alm_msg, num); - } - } - } - } + if (!alarm) + return; + + // Check each bit in turn, if any are set then get the associated error information + // Only the first 20 bits are used. + for (auto i = 0; i < 20; i++) + { + if (alarm & (0x1 << i)) + { + ODBALMMSG2 alarms[MAX_AXIS] = {0}; + short num = MAX_AXIS; + auto ret = cnc_rdalmmsg2(flibhndl, i, &num, alarms); + if (ret != EW_OK) + continue; + + for (auto j = 0; j < num; j++) + { + auto const &focasAlarm = alarms[j]; + auto condition = translateAlarmNo(i, focasAlarm.axis); + if (!condition) + continue; + std::string alarmMessage(focasAlarm.alm_msg, focasAlarm.msg_len); + condition->add( + Condition::eFAULT, + alarmMessage.c_str(), + std::to_string(focasAlarm.alm_no).c_str()); + } + } + } + } - + diff --git a/fanuc/fanuc_path.hpp b/fanuc/fanuc_path.hpp index 971df36..2e664b6 100644 --- a/fanuc/fanuc_path.hpp +++ b/fanuc/fanuc_path.hpp @@ -1,101 +1,101 @@ -/* - * Copyright Copyright 2012, System Insights, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "device_datum.hpp" -#include "condition.hpp" -#include "adapter.hpp" -#include "fanuc_axis.hpp" -#include - -class StaticEvent : public Event -{ -public: - StaticEvent(const char *aName = "") : Event(aName) {} - - virtual bool unavailable() { - return false; - } -}; - -class FanucPath -{ -public: - FanucPath(Adapter *anAdapter, short aPathNumber); - ~FanucPath(); - - void allowDNC(const bool aAllow) { mAllowDNC = aAllow; } - bool configure(unsigned short mFlibhndl); - bool gatherData(unsigned short mFlibhndl); - -protected: - bool configureAxes(unsigned short mFlibhndl); - bool configureSpindles(unsigned short mFlibhndl); - - bool getToolData(unsigned short aFlibhndl); - bool getProgramInfo(unsigned short mFlibhndl); - bool getStatus(unsigned short mFlibhndl); - bool getHeader(unsigned short aFlibhndl, int aProg); - bool getAxisData(unsigned short aFlibhndl); - bool getSpindleData(unsigned short aFlibhndl); - - void getCondition(unsigned short aFlibhndl, long aAlarm); - Condition *translateAlarmNo(long aNum, int aAxis); - - - void addDatum(DeviceDatum &aDatum, const char *aName, const char *aSuffix); - -protected: - bool mConfigured; - Adapter *mAdapter; - - short mPathNumber; - - // Path specific data items - Execution mExecution; - IntEvent mToolId; - IntEvent mToolGroup; - Event mProgramName; - Event mProgramComment; - IntEvent mLine; - Event mBlock; - StaticEvent mActiveAxes; - ControllerMode mMode; - EmergencyStop mEStop; - - Sample mPathFeedrate; - PathPosition mPathPosition; - Sample mCommandedFeedrate; - - int mProgramNum; - short mSpindleCount; - short mAxisCount; - - bool mToolManagementEnabled; - bool mUseModalToolData; - bool mAllowDNC; - - // Path related conditions - Condition mServo; - Condition mComms; - Condition mLogic; - Condition mMotion; - Condition mSystem; - - FanucAxis *mXAxis, *mYAxis, *mZAxis; - - std::vector mAxes; - std::vector mSpindles; -}; +// +// Copyright Copyright 2012, System Insights, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#pragma once + +#include "device_datum.hpp" +#include "condition.hpp" +#include "adapter.hpp" +#include "fanuc_axis.hpp" +#include + + +class StaticEvent : public Event +{ +public: + StaticEvent(const char *name = "") : + Event(name) + { + } + + bool unavailable() override { + return false; } +}; + + +class FanucPath +{ +public: + FanucPath(Adapter *adapter, short pathNumber); + ~FanucPath(); + + bool configure(unsigned short flibhndl); + bool gatherData(unsigned short flibhndl); + +protected: + bool configureAxes(unsigned short flibhndl); + bool configureSpindles(unsigned short flibhndl); + + bool getToolData(unsigned short flibhndl); + bool getProgramInfo(unsigned short flibhndl); + bool getStatus(unsigned short flibhndl); + bool getAxisData(unsigned short flibhndl); + bool getSpindleData(unsigned short flibhndl); + + void getCondition(unsigned short flibhndl, long alarm); + Condition *translateAlarmNo(long num, int axis); + + void addDatum(DeviceDatum &datum, const char *name, const char *suffix); + +protected: + Adapter *mAdapter; + + short mPathNumber; + + // Path specific data items + Execution mExecution; + IntEvent mToolId; + IntEvent mToolGroup; + Event mProgramName; + Event mProgramComment; + IntEvent mLine; + Event mBlock; + StaticEvent mActiveAxes; + ControllerMode mMode; + EmergencyStop mEStop; + + Sample mPathFeedrate; + PathPosition mPathPosition; + Sample mCommandedFeedrate; + + int mProgramNum; + short mSpindleCount; + short mAxisCount; + + bool mToolManagementEnabled; + bool mUseModalToolData; + + // Path related conditions + Condition mServo; + Condition mComms; + Condition mLogic; + Condition mMotion; + Condition mSystem; + + FanucAxis *mXAxis, *mYAxis, *mZAxis; + + std::vector mAxes; + std::vector mSpindles; +}; diff --git a/minIni_07/LICENSE b/minIni_07/LICENSE index 68c771a..cbf8eb4 100644 --- a/minIni_07/LICENSE +++ b/minIni_07/LICENSE @@ -3,6 +3,19 @@ Version 2.0, January 2004 http://www.apache.org/licenses/ + + EXCEPTION TO THE APACHE 2.0 LICENSE + + As a special exception to the Apache License 2.0 (and referring to the + definitions in Section 1 of this license), you may link, statically or + dynamically, the "Work" to other modules to produce an executable file + containing portions of the "Work", and distribute that executable file + in "Object" form under the terms of your choice, without any of the + additional requirements listed in Section 4 of the Apache License 2.0. + This exception applies only to redistributions in "Object" form (not + "Source" form) and only if no modifications have been made to the "Work". + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. diff --git a/minIni_07/README.md b/minIni_07/README.md new file mode 100644 index 0000000..9f30a01 --- /dev/null +++ b/minIni_07/README.md @@ -0,0 +1,170 @@ +# minIni +minIni is a portable and configurable library for reading and writing ".INI" files. At 830 lines of commented source +code +(version 1.2), minIni truly is a "mini" INI file parser, especially considering its features. + +The library does not require the file I/O functions from the standard C/C++ library, but instead lets you configure +the file I/O interface to use via macros. minIni uses limited stack space and does not use dynamic memory (malloc and +friends) at all. + +Some minor variations on standard INI files are supported too, notably minIni supports INI files that lack sections. + + +# Acknowledgement + +minIni is derived from an earlier INI file parser (which I wrote) for desktop systems. + +In turn, that earlier parser was a re-write of the code from the article "Multiplatform .INI Files" by Joseph J. Graf +in the March 1994 issue of Dr. Dobb's Journal. In other words, minIni has its roots in the work of Joseph Graf (even +though the code has been almost completely re-written). + + +# Features + +minIni is a programmer's library to read and write "INI" files in embedded systems. minIni takes little resources, +can be configured for various kinds of file I/O libraries and provides functionality for reading, writing and +deleting keys from an INI file. + +Although the main feature of minIni is that it is small and minimal, it has a few other features: + + * minIni supports reading keys that are outside a section, and it thereby supports configuration files that do not use sections (but that are otherwise compatible with INI files). + * You may use a colon to separate key and value; the colon is equivalent to the equal sign. That is, the strings "Name: Value" and "Name=Value" have the same meaning. + * The hash character ("#") is an alternative for the semicolon to start a comment. Trailing comments (i.e. behind a key/value pair on a line) are allowed. + * Leading and trailing white space around key names and values is ignored. + * When writing a value that contains a comment character (";" or "#"), that value will automatically be put between double quotes; when reading the value, these quotes are removed. When a double-quote itself appears in the setting, these characters are escaped. + * Section and key enumeration are supported. + * You can optionally set the line termination (for text files) that minIni will use. (This is a compile-time setting, not a run-time setting.) + * Since writing speed is much lower than reading speed in Flash memory (SD/MMC cards, USB memory sticks), minIni minimizes "file writes" at the expense of double "file reads". + * The memory footprint is deterministic. There is no dynamic memory allocation. + +## INI file reading paradigms + +There are two approaches to reading settings from an INI file. One way is to call a function, such as +GetProfileString() for every section and key that you need. This is especially convenient if there is a large +INI file, but you only need a few settings from that file at any time —especially if the INI file can also +change while your program runs. This is the approach that the Microsoft Windows API uses. + +The above procedure is quite inefficient, however, when you need to retrieve quite a few settings in a row from +the INI file —especially if the INI file is not cached in memory (which it isn't, in minIni). A different approach +to getting settings from an INI file is to call a "parsing" function and let that function call the application +back with the section and key names plus the associated data. XML parsing libraries often use this approach; see +for example the Expat library. + +minIni supports both approaches. For reading a single setting, use functions like ini_gets(). For the callback +approach, implement a callback and call ini_browse(). See the minIni manual for details. + + +# INI file syntax + +INI files are best known from Microsoft Windows, but they are also used with applications that run on other +platforms (although their file extension is sometimes ".cfg" instead of ".ini"). + +INI files have a simple syntax with name/value pairs in a plain text file. The name must be unique (per section) +and the value must fit on a single line. INI files are commonly separated into sections —in minIni, this is +optional. A section is a name between square brackets, like "[Network]" in the example below. + +``` +[Network] +hostname=My Computer +address=dhcp +dns = 192.168.1.1 +``` + +In the API and in this documentation, the "name" for a setting is denoted as the key for the setting. The key +and the value are separated by an equal sign ("="). minIni supports the colon (":") as an alternative to the +equal sign for the key/value delimiter. + +Leading a trailing spaces around values or key names are removed. If you need to include leading and/or trailing +spaces in a value, put the value between double quotes. The ini_gets() function (from the minIni library, see the +minIni manual) strips off the double quotes from the returned value. Function ini_puts() adds double quotes if +the value to write contains trailing white space (or special characters). + +minIni ignores spaces around the "=" or ":" delimiters, but it does not ignore spaces between the brackets in a +section name. In other words, it is best not to put spaces behind the opening bracket "[" or before the closing +bracket "]" of a section name. + +Comments in the INI must start with a semicolon (";") or a hash character ("#"), and run to the end of the line. +A comment can be a line of its own, or it may follow a key/value pair (the "#" character and trailing comments +are extensions of minIni). + +For more details on the format, please see http://en.wikipedia.org/wiki/INI_file. + + +# Adapting minIni to a file system + +The minIni library must be configured for a platform with the help of a so- called "glue file". This glue file +contains macros (and possibly functions) that map file reading and writing functions used by the minIni library +to those provided by the operating system. The glue file must be called "minGlue.h". + +To get you started, the minIni distribution comes with the following example glue files: + + * a glue file that maps to the standard C/C++ library (specifically the file I/O functions from the "stdio" package), + * a glue file for Microchip's "Memory Disk Drive File System Library" (see http://www.microchip.com/), + * a glue file for the FAT library provided with the CCS PIC compiler (see http://www.ccsinfo.com/) + * a glue file for the EFS Library (EFSL, http://www.efsl.be/), + * and a glue file for the FatFs and Petit-FatFs libraries (http://elm-chan.org/fsw/ff/00index_e.html). + +The minIni library does not rely on the availability of a standard C library, because embedded operating systems +may have limited support for file I/O. Even on full operating systems, separating the file I/O from the INI format +parsing carries advantages, because it allows you to cache the INI file and thereby enhance performance. + +The glue file must specify the type that identifies a file, whether it is a handle or a pointer. For the standard +C/C++ file I/O library, this would be: + +```C +#define INI_FILETYPE FILE* +``` + +If you are not using the standard C/C++ file I/O library, chances are that you need a different handle or +"structure" to identify the storage than the ubiquitous "FILE*" type. For example, the glue file for the FatFs +library uses the following declaration: + +```C +#define INI_FILETYPE FIL +``` + +The minIni functions declare variables of this INI_FILETYPE type and pass these variables to sub-functions +(including the glue interface functions) by reference. + +For "write support", another type that must be defined is for variables that hold the "current position" in a +file. For the standard C/C++ I/O library, this is "fpos_t". + +Another item that needs to be configured is the buffer size. The functions in the minIni library allocate this +buffer on the stack, so the buffer size is directly related to the stack usage. In addition, the buffer size +determines the maximum line length that is supported in the INI file and the maximum path name length for the +temporary file. For example, minGlue.h could contain the definition: + +```C +#define INI_BUFFERSIZE 512 +``` + +The above macro limits the line length of the INI files supported by minIni to 512 characters. + +The temporary file is only used when writing to INI files. The minIni routines copy/change the INI file to a +temporary file and then rename that temporary file to the original file. This approach uses the least amount of +memory. The path name of the temporary file is the same as the input file, but with the last character set to a +tilde ("~"). + +Below is an example of a glue file (this is the one that maps to the C/C++ "stdio" library). + +```C +#include + +#define INI_FILETYPE FILE* +#define ini_openread(filename,file) ((*(file) = fopen((filename),"r")) != NULL) +#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"w")) != NULL) +#define ini_close(file) (fclose(*(file)) == 0) +#define ini_read(buffer,size,file) (fgets((buffer),(size),*(file)) != NULL) +#define ini_write(buffer,file) (fputs((buffer),*(file)) >= 0) +#define ini_rename(source,dest) (rename((source), (dest)) == 0) +#define ini_remove(filename) (remove(filename) == 0) + +#define INI_FILEPOS fpos_t +#define ini_tell(file,pos) (fgetpos(*(file), (pos)) == 0) +#define ini_seek(file,pos) (fsetpos(*(file), (pos)) == 0) +``` + +As you can see, a glue file is mostly a set of macros that wraps one function definition around another. + +The glue file may contain more settings, for support of rational numbers, to explicitly set the line termination +character(s), or to disable write support (for example). See the manual that comes with the archive for the details. diff --git a/minIni_07/minGlue-FatFs.h b/minIni_07/minGlue-FatFs.h index 3c14e4e..250ed59 100644 --- a/minIni_07/minGlue-FatFs.h +++ b/minIni_07/minGlue-FatFs.h @@ -1,19 +1,12 @@ -/* Glue functions for the minIni library, based on the FatFs and Tiny-FatFs +/* Glue functions for the minIni library, based on the FatFs and Petit-FatFs * libraries, see http://elm-chan.org/fsw/ff/00index_e.html * - * Copyright (c) ITB CompuPhase, 2008-2009 + * By CompuPhase, 2008-2012 + * This "glue file" is in the public domain. It is distributed without + * warranties or conditions of any kind, either express or implied. * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * (The FatFs and Petit-FatFs libraries are copyright by ChaN and licensed at + * its own terms.) */ #define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */ @@ -22,13 +15,23 @@ * to enable the "string functions" fgets() and fputs(). */ #include "ff.h" /* include tff.h for Tiny-FatFs */ + #define INI_FILETYPE FIL +#define ini_openread(filename,file) (f_open((file), (filename), FA_READ+FA_OPEN_EXISTING) == FR_OK) +#define ini_openwrite(filename,file) (f_open((file), (filename), FA_WRITE+FA_CREATE_ALWAYS) == FR_OK) +#define ini_close(file) (f_close(file) == FR_OK) +#define ini_read(buffer,size,file) f_gets((buffer), (size),(file)) +#define ini_write(buffer,file) f_puts((buffer), (file)) +#define ini_remove(filename) (f_unlink(filename) == FR_OK) + +#define INI_FILEPOS DWORD +#define ini_tell(file,pos) (*(pos) = f_tell((file))) +#define ini_seek(file,pos) (f_lseek((file), *(pos)) == FR_OK) -#define ini_openread(filename,file) (f_open((file),(filename),FA_READ+FA_OPEN_EXISTING) == 0) -#define ini_openwrite(filename,file) (f_open((file),(filename),FA_WRITE+FA_CREATE_ALWAYS) == 0) -#define ini_close(file) f_close(file) -#define ini_read(buffer,size,file) fgets((buffer),(size),(file)) -#define ini_write(buffer,file) fputs((buffer),(file)) -#define ini_rename(source,dest) f_rename((source),(dest)) -#define ini_remove(filename) f_unlink(filename) -#define ini_rewind(file) f_lseek((file),0) +static int ini_rename(TCHAR *source, const TCHAR *dest) +{ + /* Function f_rename() does not allow drive letters in the destination file */ + char *drive = strchr(dest, ':'); + drive = (drive == NULL) ? dest : drive + 1; + return (f_rename(source, drive) == FR_OK); +} diff --git a/minIni_07/minGlue-ccs.h b/minIni_07/minGlue-ccs.h new file mode 100644 index 0000000..a8e19f1 --- /dev/null +++ b/minIni_07/minGlue-ccs.h @@ -0,0 +1,64 @@ +/* minIni glue functions for FAT library by CCS, Inc. (as provided with their + * PIC MCU compiler) + * + * By CompuPhase, 2011-2012 + * This "glue file" is in the public domain. It is distributed without + * warranties or conditions of any kind, either express or implied. + * + * (The FAT library is copyright (c) 2007 Custom Computer Services, and + * licensed at its own terms.) + */ + +#define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */ + +#ifndef FAT_PIC_C + #error FAT library must be included before this module +#endif +#define const /* keyword not supported by CCS */ + +#define INI_FILETYPE FILE +#define ini_openread(filename,file) (fatopen((filename), "r", (file)) == GOODEC) +#define ini_openwrite(filename,file) (fatopen((filename), "w", (file)) == GOODEC) +#define ini_close(file) (fatclose((file)) == 0) +#define ini_read(buffer,size,file) (fatgets((buffer), (size), (file)) != NULL) +#define ini_write(buffer,file) (fatputs((buffer), (file)) == GOODEC) +#define ini_remove(filename) (rm_file((filename)) == 0) + +#define INI_FILEPOS fatpos_t +#define ini_tell(file,pos) (fatgetpos((file), (pos)) == 0) +#define ini_seek(file,pos) (fatsetpos((file), (pos)) == 0) + +#ifndef INI_READONLY +/* CCS FAT library lacks a rename function, so instead we copy the file to the + * new name and delete the old file + */ +static int ini_rename(char *source, char *dest) +{ + FILE fr, fw; + int n; + + if (fatopen(source, "r", &fr) != GOODEC) + return 0; + if (rm_file(dest) != 0) + return 0; + if (fatopen(dest, "w", &fw) != GOODEC) + return 0; + + /* With some "insider knowledge", we can save some memory: the "source" + * parameter holds a filename that was built from the "dest" parameter. It + * was built in a local buffer with the size INI_BUFFERSIZE. We can reuse + * this buffer for copying the file. + */ + while (n=fatread(source, 1, INI_BUFFERSIZE, &fr)) + fatwrite(source, 1, n, &fw); + + fatclose(&fr); + fatclose(&fw); + + /* Now we need to delete the source file. However, we have garbled the buffer + * that held the filename of the source. So we need to build it again. + */ + ini_tempname(source, dest, INI_BUFFERSIZE); + return rm_file(source) == 0; +} +#endif diff --git a/minIni_07/minGlue-efsl.h b/minIni_07/minGlue-efsl.h index ebb587a..69d598d 100644 --- a/minIni_07/minGlue-efsl.h +++ b/minIni_07/minGlue-efsl.h @@ -1,38 +1,33 @@ /* Glue functions for the minIni library, based on the EFS Library, see * http://www.efsl.be/ * - * Copyright (c) ITB CompuPhase, 2008-2009 + * By CompuPhase, 2008-2012 + * This "glue file" is in the public domain. It is distributed without + * warranties or conditions of any kind, either express or implied. * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * (EFSL is copyright 2005-2006 Lennart Ysboodt and Michael De Nil, and + * licensed under the GPL with an exception clause for static linking.) */ #define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */ - -#include "efs.h" -#define INI_FILETYPE EmbeddedFile #define INI_LINETERM "\r\n" /* set line termination explicitly */ - +#include "efs.h" extern EmbeddedFileSystem g_efs; -#define ini_openread(filename,file) (file_fopen((file),&g_efs.myFs,(char*)(filename),'r') == 0) -#define ini_openwrite(filename,file) (file_fopen((file),&g_efs.myFs,(char*)(filename),'w') == 0) +#define INI_FILETYPE EmbeddedFile +#define ini_openread(filename,file) (file_fopen((file), &g_efs.myFs, (char*)(filename), 'r') == 0) +#define ini_openwrite(filename,file) (file_fopen((file), &g_efs.myFs, (char*)(filename), 'w') == 0) #define ini_close(file) file_fclose(file) -#define ini_read(buffer,size,file) (file_read((file),(size),(buffer)) > 0) -#define ini_write(buffer,file) file_write((file),strlen(buffer),(char*)(buffer)) -#define ini_remove(filename) rmfile(&g_efs.myFs,(char*)(filename)) -#define ini_rewind(file) file_setpos(*(file),0) +#define ini_read(buffer,size,file) (file_read((file), (size), (buffer)) > 0) +#define ini_write(buffer,file) (file_write((file), strlen(buffer), (char*)(buffer)) > 0) +#define ini_remove(filename) rmfile(&g_efs.myFs, (char*)(filename)) + +#define INI_FILEPOS euint32 +#define ini_tell(file,pos) (*(pos) = (file)->FilePtr)) +#define ini_seek(file,pos) file_setpos((file), (*pos)) +#if ! defined INI_READONLY /* EFSL lacks a rename function, so instead we copy the file to the new name * and delete the old file */ @@ -65,3 +60,4 @@ static int ini_rename(char *source, const char *dest) ini_tempname(source, dest, INI_BUFFERSIZE); return rmfile(&g_efs.myFs, source) == 0; } +#endif diff --git a/minIni_07/minGlue-ffs.h b/minIni_07/minGlue-ffs.h new file mode 100644 index 0000000..5dadace --- /dev/null +++ b/minIni_07/minGlue-ffs.h @@ -0,0 +1,26 @@ +/* Glue functions for the minIni library, based on the "FAT Filing System" + * library by embedded-code.com + * + * By CompuPhase, 2008-2012 + * This "glue file" is in the public domain. It is distributed without + * warranties or conditions of any kind, either express or implied. + * + * (The "FAT Filing System" library itself is copyright embedded-code.com, and + * licensed at its own terms.) + */ + +#define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */ +#include + +#define INI_FILETYPE FFS_FILE* +#define ini_openread(filename,file) ((*(file) = ffs_fopen((filename),"r")) != NULL) +#define ini_openwrite(filename,file) ((*(file) = ffs_fopen((filename),"w")) != NULL) +#define ini_close(file) (ffs_fclose(*(file)) == 0) +#define ini_read(buffer,size,file) (ffs_fgets((buffer),(size),*(file)) != NULL) +#define ini_write(buffer,file) (ffs_fputs((buffer),*(file)) >= 0) +#define ini_rename(source,dest) (ffs_rename((source), (dest)) == 0) +#define ini_remove(filename) (ffs_remove(filename) == 0) + +#define INI_FILEPOS long +#define ini_tell(file,pos) (ffs_fgetpos(*(file), (pos)) == 0) +#define ini_seek(file,pos) (ffs_fsetpos(*(file), (pos)) == 0) diff --git a/minIni_07/minGlue-mdd.h b/minIni_07/minGlue-mdd.h new file mode 100644 index 0000000..2f75d6f --- /dev/null +++ b/minIni_07/minGlue-mdd.h @@ -0,0 +1,58 @@ +/* minIni glue functions for Microchip's "Memory Disk Drive" file system + * library, as presented in Microchip application note AN1045. + * + * By CompuPhase, 2011-2014 + * This "glue file" is in the public domain. It is distributed without + * warranties or conditions of any kind, either express or implied. + * + * (The "Microchip Memory Disk Drive File System" is copyright (c) Microchip + * Technology Incorporated, and licensed at its own terms.) + */ + +#define INI_BUFFERSIZE 256 /* maximum line length, maximum path length */ + +#include "MDD File System\fsio.h" +#include + +#define INI_FILETYPE FSFILE* +#define ini_openread(filename,file) ((*(file) = FSfopen((filename),FS_READ)) != NULL) +#define ini_openwrite(filename,file) ((*(file) = FSfopen((filename),FS_WRITE)) != NULL) +#define ini_openrewrite(filename,file) ((*(file) = fopen((filename),FS_READPLUS)) != NULL) +#define ini_close(file) (FSfclose(*(file)) == 0) +#define ini_write(buffer,file) (FSfwrite((buffer), 1, strlen(buffer), (*file)) > 0) +#define ini_remove(filename) (FSremove((filename)) == 0) + +#define INI_FILEPOS long int +#define ini_tell(file,pos) (*(pos) = FSftell(*(file))) +#define ini_seek(file,pos) (FSfseek(*(file), *(pos), SEEK_SET) == 0) + +/* Since the Memory Disk Drive file system library reads only blocks of files, + * the function to read a text line does so by "over-reading" a block of the + * of the maximum size and truncating it behind the end-of-line. + */ +static int ini_read(char *buffer, int size, INI_FILETYPE *file) +{ + size_t numread = size; + char *eol; + + if ((numread = FSfread(buffer, 1, size, *file)) == 0) + return 0; /* at EOF */ + if ((eol = strchr(buffer, '\n')) == NULL) + eol = strchr(buffer, '\r'); + if (eol != NULL) { + /* terminate the buffer */ + *++eol = '\0'; + /* "unread" the data that was read too much */ + FSfseek(*file, - (int)(numread - (size_t)(eol - buffer)), SEEK_CUR); + } /* if */ + return 1; +} + +#ifndef INI_READONLY +static int ini_rename(const char *source, const char *dest) +{ + FSFILE* ftmp = FSfopen((source), FS_READ); + FSrename((dest), ftmp); + return FSfclose(ftmp) == 0; +} +#endif diff --git a/minIni_07/minGlue-stdio.h b/minIni_07/minGlue-stdio.h index 8388564..735635b 100644 --- a/minIni_07/minGlue-stdio.h +++ b/minIni_07/minGlue-stdio.h @@ -3,28 +3,29 @@ * Or better said: this file contains macros that maps the function interface * used by minIni to the standard C/C++ file I/O functions. * - * Copyright (c) ITB CompuPhase, 2008-2009 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. + * By CompuPhase, 2008-2014 + * This "glue file" is in the public domain. It is distributed without + * warranties or conditions of any kind, either express or implied. */ -/* map required file I/O to the standard C library */ +/* map required file I/O types and functions to the standard C library */ #include -#define ini_openread(filename,file) ((*(file) = fopen((filename),"rt")) != NULL) -#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"wt")) != NULL) -#define ini_close(file) fclose(*(file)) -#define ini_read(buffer,size,file) fgets((buffer),(size),*(file)) -#define ini_write(buffer,file) fputs((buffer),*(file)) -#define ini_rename(source,dest) rename((source),(dest)) -#define ini_remove(filename) remove(filename) -#define ini_rewind(file) rewind(*(file)) + +#define INI_FILETYPE FILE* +#define ini_openread(filename,file) ((*(file) = fopen((filename),"rb")) != NULL) +#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"wb")) != NULL) +#define ini_openrewrite(filename,file) ((*(file) = fopen((filename),"r+b")) != NULL) +#define ini_close(file) (fclose(*(file)) == 0) +#define ini_read(buffer,size,file) (fgets((buffer),(size),*(file)) != NULL) +#define ini_write(buffer,file) (fputs((buffer),*(file)) >= 0) +#define ini_rename(source,dest) (rename((source), (dest)) == 0) +#define ini_remove(filename) (remove(filename) == 0) + +#define INI_FILEPOS long int +#define ini_tell(file,pos) (*(pos) = ftell(*(file))) +#define ini_seek(file,pos) (fseek(*(file), *(pos), SEEK_SET) == 0) + +/* for floating-point support, define additional types and functions */ +#define INI_REAL float +#define ini_ftoa(string,value) sprintf((string),"%f",(value)) +#define ini_atof(string) (INI_REAL)strtod((string),NULL) diff --git a/minIni_07/minGlue.h b/minIni_07/minGlue.h index 8b86b8c..2d47d90 100644 --- a/minIni_07/minGlue.h +++ b/minIni_07/minGlue.h @@ -3,30 +3,29 @@ * Or better said: this file contains macros that maps the function interface * used by minIni to the standard C/C++ file I/O functions. * - * Copyright (c) ITB CompuPhase, 2008-2009 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - * Version: $Id: minGlue.h 24 2009-05-06 08:01:53Z thiadmer.riemersma $ + * By CompuPhase, 2008-2014 + * This "glue file" is in the public domain. It is distributed without + * warranties or conditions of any kind, either express or implied. */ -/* map required file I/O to the standard C library */ +/* map required file I/O types and functions to the standard C library */ #include -#define ini_openread(filename,file) ((*(file) = fopen((filename),"rt")) != NULL) -#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"wt")) != NULL) -#define ini_close(file) fclose(*(file)) -#define ini_read(buffer,size,file) fgets((buffer),(size),*(file)) -#define ini_write(buffer,file) fputs((buffer),*(file)) -#define ini_rename(source,dest) rename((source),(dest)) -#define ini_remove(filename) remove(filename) -#define ini_rewind(file) rewind(*(file)) + +#define INI_FILETYPE FILE* +#define ini_openread(filename,file) ((*(file) = fopen((filename),"rb")) != NULL) +#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"wb")) != NULL) +#define ini_openrewrite(filename,file) ((*(file) = fopen((filename),"r+b")) != NULL) +#define ini_close(file) (fclose(*(file)) == 0) +#define ini_read(buffer,size,file) (fgets((buffer),(size),*(file)) != NULL) +#define ini_write(buffer,file) (fputs((buffer),*(file)) >= 0) +#define ini_rename(source,dest) (rename((source), (dest)) == 0) +#define ini_remove(filename) (remove(filename) == 0) + +#define INI_FILEPOS long int +#define ini_tell(file,pos) (*(pos) = ftell(*(file))) +#define ini_seek(file,pos) (fseek(*(file), *(pos), SEEK_SET) == 0) + +/* for floating-point support, define additional types and functions */ +#define INI_REAL float +#define ini_ftoa(string,value) sprintf((string),"%f",(value)) +#define ini_atof(string) (INI_REAL)strtod((string),NULL) diff --git a/minIni_07/minIni.c b/minIni_07/minIni.c index bdf2ae6..fd199cb 100644 --- a/minIni_07/minIni.c +++ b/minIni_07/minIni.c @@ -3,7 +3,7 @@ * These routines are in part based on the article "Multiplatform .INI Files" * by Joseph J. Graf in the March 1994 issue of Dr. Dobb's Journal. * - * Copyright (c) ITB CompuPhase, 2008-2009 + * Copyright (c) CompuPhase, 2008-2017 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -17,10 +17,10 @@ * License for the specific language governing permissions and limitations * under the License. * - * Version: $Id: minIni.c 24 2009-05-06 08:01:53Z thiadmer.riemersma $ + * Version: $Id: minIni.c 53 2015-01-18 13:35:11Z thiadmer.riemersma@gmail.com $ */ -#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined MININI_ANSI +#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY # if !defined UNICODE /* for Windows */ # define UNICODE # endif @@ -29,6 +29,7 @@ # endif #endif +#define MININI_IMPLEMENTATION #include "minIni.h" #if defined NDEBUG #define assert(e) @@ -36,10 +37,11 @@ #include #endif -#if !defined __T +#if !defined __T || defined INI_ANSIONLY + #include #include #include - /* definition of TCHAR already in minIni.h */ + #define TCHAR char #define __T(s) s #define _tcscat strcat #define _tcschr strchr @@ -47,10 +49,13 @@ #define _tcscpy strcpy #define _tcsicmp stricmp #define _tcslen strlen - #define _tcsncpy strncpy + #define _tcsncmp strncmp #define _tcsnicmp strnicmp #define _tcsrchr strrchr #define _tcstol strtol + #define _tcstod strtod + #define _totupper toupper + #define _stprintf sprintf #define _tfgets fgets #define _tfputs fputs #define _tfopen fopen @@ -60,32 +65,63 @@ #if defined __linux || defined __linux__ #define __LINUX__ -#endif -#if defined FREEBSD && !defined __FreeBSD__ +#elif defined FREEBSD && !defined __FreeBSD__ #define __FreeBSD__ +#elif defined(_MSC_VER) + #pragma warning(disable: 4996) /* for Microsoft Visual C/C++ */ #endif -#if !defined strnicmp - #if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ +#if !defined strnicmp && !defined PORTABLE_STRNICMP + #if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ #define strnicmp strncasecmp #endif #endif +#if !defined _totupper + #define _totupper toupper +#endif #if !defined INI_LINETERM - #define INI_LINETERM __T("\n") + #if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ + #define INI_LINETERM __T("\n") + #else + #define INI_LINETERM __T("\r\n") + #endif #endif #if !defined INI_FILETYPE - #define INI_FILETYPE FILE* + #error Missing definition for INI_FILETYPE. #endif #if !defined sizearray #define sizearray(a) (sizeof(a) / sizeof((a)[0])) #endif +enum quote_option { + QUOTE_NONE, + QUOTE_ENQUOTE, + QUOTE_DEQUOTE, +}; + +#if defined PORTABLE_STRNICMP +int strnicmp(const TCHAR *s1, const TCHAR *s2, size_t n) +{ + while (n-- != 0 && (*s1 || *s2)) { + register int c1, c2; + c1 = *s1++; + if ('a' <= c1 && c1 <= 'z') + c1 += ('A' - 'a'); + c2 = *s2++; + if ('a' <= c2 && c2 <= 'z') + c2 += ('A' - 'a'); + if (c1 != c2) + return c1 - c2; + } /* while */ + return 0; +} +#endif /* PORTABLE_STRNICMP */ static TCHAR *skipleading(const TCHAR *str) { assert(str != NULL); - while (*str != '\0' && *str <= ' ') + while ('\0' < *str && *str <= ' ') str++; return (TCHAR *)str; } @@ -94,7 +130,7 @@ static TCHAR *skiptrailing(const TCHAR *str, const TCHAR *base) { assert(str != NULL); assert(base != NULL); - while (str > base && *(str-1) <= ' ') + while (str > base && '\0' < *(str-1) && *(str-1) <= ' ') str--; return (TCHAR *)str; } @@ -103,45 +139,120 @@ static TCHAR *striptrailing(TCHAR *str) { TCHAR *ptr = skiptrailing(_tcschr(str, '\0'), str); assert(ptr != NULL); - *ptr='\0'; + *ptr = '\0'; return str; } -static TCHAR *save_strncpy(TCHAR *dest, const TCHAR *source, size_t maxlen) +static TCHAR *ini_strncpy(TCHAR *dest, const TCHAR *source, size_t maxlen, enum quote_option option) { + size_t d, s; + assert(maxlen>0); - _tcsncpy(dest,source,maxlen); - dest[maxlen-1]='\0'; + assert(source != NULL && dest != NULL); + assert((dest < source || (dest == source && option != QUOTE_ENQUOTE)) || dest > source + strlen(source)); + if (option == QUOTE_ENQUOTE && maxlen < 3) + option = QUOTE_NONE; /* cannot store two quotes and a terminating zero in less than 3 characters */ + + switch (option) { + case QUOTE_NONE: + for (d = 0; d < maxlen - 1 && source[d] != '\0'; d++) + dest[d] = source[d]; + assert(d < maxlen); + dest[d] = '\0'; + break; + case QUOTE_ENQUOTE: + d = 0; + dest[d++] = '"'; + for (s = 0; source[s] != '\0' && d < maxlen - 2; s++, d++) { + if (source[s] == '"') { + if (d >= maxlen - 3) + break; /* no space to store the escape character plus the one that follows it */ + dest[d++] = '\\'; + } /* if */ + dest[d] = source[s]; + } /* for */ + dest[d++] = '"'; + dest[d] = '\0'; + break; + case QUOTE_DEQUOTE: + for (d = s = 0; source[s] != '\0' && d < maxlen - 1; s++, d++) { + if ((source[s] == '"' || source[s] == '\\') && source[s + 1] == '"') + s++; + dest[d] = source[s]; + } /* for */ + dest[d] = '\0'; + break; + default: + assert(0); + } /* switch */ + return dest; } +static TCHAR *cleanstring(TCHAR *string, enum quote_option *quotes) +{ + int isstring; + TCHAR *ep; + + assert(string != NULL); + assert(quotes != NULL); + + /* Remove a trailing comment */ + isstring = 0; + for (ep = string; *ep != '\0' && ((*ep != ';' && *ep != '#') || isstring); ep++) { + if (*ep == '"') { + if (*(ep + 1) == '"') + ep++; /* skip "" (both quotes) */ + else + isstring = !isstring; /* single quote, toggle isstring */ + } else if (*ep == '\\' && *(ep + 1) == '"') { + ep++; /* skip \" (both quotes */ + } /* if */ + } /* for */ + assert(ep != NULL && (*ep == '\0' || *ep == ';' || *ep == '#')); + *ep = '\0'; /* terminate at a comment */ + striptrailing(string); + /* Remove double quotes surrounding a value */ + *quotes = QUOTE_NONE; + if (*string == '"' && (ep = _tcschr(string, '\0')) != NULL && *(ep - 1) == '"') { + string++; + *--ep = '\0'; + *quotes = QUOTE_DEQUOTE; /* this is a string, so remove escaped characters */ + } /* if */ + return string; +} + static int getkeystring(INI_FILETYPE *fp, const TCHAR *Section, const TCHAR *Key, - int idxSection, int idxKey, TCHAR *Buffer, int BufferSize) + int idxSection, int idxKey, TCHAR *Buffer, int BufferSize, + INI_FILEPOS *mark) { TCHAR *sp, *ep; int len, idx; + enum quote_option quotes; TCHAR LocalBuffer[INI_BUFFERSIZE]; assert(fp != NULL); /* Move through file 1 line at a time until a section is matched or EOF. If * parameter Section is NULL, only look at keys above the first section. If - * idxSection is postive, copy the relevant section name. + * idxSection is positive, copy the relevant section name. */ - len = (Section != NULL) ? _tcslen(Section) : 0; + len = (Section != NULL) ? (int)_tcslen(Section) : 0; if (len > 0 || idxSection >= 0) { + assert(idxSection >= 0 || Section != NULL); idx = -1; do { if (!ini_read(LocalBuffer, INI_BUFFERSIZE, fp)) return 0; sp = skipleading(LocalBuffer); - ep = _tcschr(sp, ']'); - } while (*sp != '[' || ep == NULL || (((int)(ep-sp-1) != len || _tcsnicmp(sp+1,Section,len) != 0) && ++idx != idxSection)); + ep = _tcsrchr(sp, ']'); + } while (*sp != '[' || ep == NULL || + (((int)(ep-sp-1) != len || Section == NULL || _tcsnicmp(sp+1,Section,len) != 0) && ++idx != idxSection)); if (idxSection >= 0) { if (idx == idxSection) { assert(ep != NULL); assert(*ep == ']'); *ep = '\0'; - save_strncpy(Buffer, sp + 1, BufferSize); + ini_strncpy(Buffer, sp + 1, BufferSize, QUOTE_NONE); return 1; } /* if */ return 0; /* no more section found */ @@ -155,20 +266,23 @@ static int getkeystring(INI_FILETYPE *fp, const TCHAR *Section, const TCHAR *Key len = (Key != NULL) ? (int)_tcslen(Key) : 0; idx = -1; do { + if (mark != NULL) + ini_tell(fp, mark); /* optionally keep the mark to the start of the line */ if (!ini_read(LocalBuffer,INI_BUFFERSIZE,fp) || *(sp = skipleading(LocalBuffer)) == '[') return 0; sp = skipleading(LocalBuffer); - ep = _tcschr(sp, '='); /* Parse out the equal sign */ + ep = _tcschr(sp, '='); /* Parse out the equal sign */ if (ep == NULL) ep = _tcschr(sp, ':'); - } while (*sp == ';' || *sp == '#' || ep == NULL || (((int)(skiptrailing(ep,sp)-sp) != len || _tcsnicmp(sp,Key,len) != 0) && ++idx != idxKey)); + } while (*sp == ';' || *sp == '#' || ep == NULL + || ((len == 0 || (int)(skiptrailing(ep,sp)-sp) != len || _tcsnicmp(sp,Key,len) != 0) && ++idx != idxKey)); if (idxKey >= 0) { if (idx == idxKey) { assert(ep != NULL); assert(*ep == '=' || *ep == ':'); *ep = '\0'; striptrailing(sp); - save_strncpy(Buffer, sp, BufferSize); + ini_strncpy(Buffer, sp, BufferSize, QUOTE_NONE); return 1; } /* if */ return 0; /* no more key found (in this section) */ @@ -178,13 +292,8 @@ static int getkeystring(INI_FILETYPE *fp, const TCHAR *Section, const TCHAR *Key assert(ep != NULL); assert(*ep == '=' || *ep == ':'); sp = skipleading(ep + 1); - striptrailing(sp); - /* Remove double quotes surrounding a value */ - if (*sp == '"' && (ep = _tcschr(sp, '\0')) != NULL && *(ep - 1) == '"') { - sp++; - *--ep = '\0'; - } /* if */ - save_strncpy(Buffer, sp, BufferSize); + sp = cleanstring(sp, "es); /* Remove a trailing comment */ + ini_strncpy(Buffer, sp, BufferSize, quotes); return 1; } @@ -207,12 +316,12 @@ int ini_gets(const TCHAR *Section, const TCHAR *Key, const TCHAR *DefValue, if (Buffer == NULL || BufferSize <= 0 || Key == NULL) return 0; if (ini_openread(Filename, &fp)) { - ok = getkeystring(&fp, Section, Key, -1, -1, Buffer, BufferSize); - ini_close(&fp); + ok = getkeystring(&fp, Section, Key, -1, -1, Buffer, BufferSize, NULL); + (void)ini_close(&fp); } /* if */ if (!ok) - save_strncpy(Buffer, DefValue, BufferSize); - return _tcslen(Buffer); + ini_strncpy(Buffer, (DefValue != NULL) ? DefValue : __T(""), BufferSize, QUOTE_NONE); + return (int)_tcslen(Buffer); } /** ini_getl() @@ -225,9 +334,64 @@ int ini_gets(const TCHAR *Section, const TCHAR *Key, const TCHAR *DefValue, */ long ini_getl(const TCHAR *Section, const TCHAR *Key, long DefValue, const TCHAR *Filename) { - TCHAR buff[64]; - int len = ini_gets(Section, Key, __T(""), buff, sizearray(buff), Filename); - return (len == 0) ? DefValue : _tcstol(buff,NULL,10); + TCHAR LocalBuffer[64]; + int len = ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename); + return (len == 0) ? DefValue + : ((len >= 2 && _totupper((int)LocalBuffer[1]) == 'X') ? _tcstol(LocalBuffer, NULL, 16) + : _tcstol(LocalBuffer, NULL, 10)); +} + +#if defined INI_REAL +/** ini_getf() + * \param Section the name of the section to search for + * \param Key the name of the entry to find the value of + * \param DefValue the default value in the event of a failed read + * \param Filename the name of the .ini file to read from + * + * \return the value located at Key + */ +INI_REAL ini_getf(const TCHAR *Section, const TCHAR *Key, INI_REAL DefValue, const TCHAR *Filename) +{ + TCHAR LocalBuffer[64]; + int len = ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename); + return (len == 0) ? DefValue : ini_atof(LocalBuffer); +} +#endif + +/** ini_getbool() + * \param Section the name of the section to search for + * \param Key the name of the entry to find the value of + * \param DefValue default value in the event of a failed read; it should + * zero (0) or one (1). + * \param Filename the name and full path of the .ini file to read from + * + * A true boolean is found if one of the following is matched: + * - A string starting with 'y' or 'Y' + * - A string starting with 't' or 'T' + * - A string starting with '1' + * + * A false boolean is found if one of the following is matched: + * - A string starting with 'n' or 'N' + * - A string starting with 'f' or 'F' + * - A string starting with '0' + * + * \return the true/false flag as interpreted at Key + */ +int ini_getbool(const TCHAR *Section, const TCHAR *Key, int DefValue, const TCHAR *Filename) +{ + TCHAR LocalBuffer[2] = __T(""); + int ret; + + ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename); + LocalBuffer[0] = (TCHAR)_totupper((int)LocalBuffer[0]); + if (LocalBuffer[0] == 'Y' || LocalBuffer[0] == '1' || LocalBuffer[0] == 'T') + ret = 1; + else if (LocalBuffer[0] == 'N' || LocalBuffer[0] == '0' || LocalBuffer[0] == 'F') + ret = 0; + else + ret = DefValue; + + return(ret); } /** ini_getsection() @@ -246,12 +410,12 @@ int ini_getsection(int idx, TCHAR *Buffer, int BufferSize, const TCHAR *Filenam if (Buffer == NULL || BufferSize <= 0 || idx < 0) return 0; if (ini_openread(Filename, &fp)) { - ok = getkeystring(&fp, NULL, NULL, idx, -1, Buffer, BufferSize); - ini_close(&fp); + ok = getkeystring(&fp, NULL, NULL, idx, -1, Buffer, BufferSize, NULL); + (void)ini_close(&fp); } /* if */ if (!ok) *Buffer = '\0'; - return _tcslen(Buffer); + return (int)_tcslen(Buffer); } /** ini_getkey() @@ -272,54 +436,185 @@ int ini_getkey(const TCHAR *Section, int idx, TCHAR *Buffer, int BufferSize, co if (Buffer == NULL || BufferSize <= 0 || idx < 0) return 0; if (ini_openread(Filename, &fp)) { - ok = getkeystring(&fp, Section, NULL, -1, idx, Buffer, BufferSize); - ini_close(&fp); + ok = getkeystring(&fp, Section, NULL, -1, idx, Buffer, BufferSize, NULL); + (void)ini_close(&fp); } /* if */ if (!ok) *Buffer = '\0'; - return _tcslen(Buffer); + return (int)_tcslen(Buffer); } +#if !defined INI_NOBROWSE +/** ini_browse() + * \param Callback a pointer to a function that will be called for every + * setting in the INI file. + * \param UserData arbitrary data, which the function passes on the + * \c Callback function + * \param Filename the name and full path of the .ini file to read from + * + * \return 1 on success, 0 on failure (INI file not found) + * + * \note The \c Callback function must return 1 to continue + * browsing through the INI file, or 0 to stop. Even when the + * callback stops the browsing, this function will return 1 + * (for success). + */ +int ini_browse(INI_CALLBACK Callback, void *UserData, const TCHAR *Filename) +{ + TCHAR LocalBuffer[INI_BUFFERSIZE]; + int lenSec, lenKey; + enum quote_option quotes; + INI_FILETYPE fp; + + if (Callback == NULL) + return 0; + if (!ini_openread(Filename, &fp)) + return 0; + + LocalBuffer[0] = '\0'; /* copy an empty section in the buffer */ + lenSec = (int)_tcslen(LocalBuffer) + 1; + for ( ;; ) { + TCHAR *sp, *ep; + if (!ini_read(LocalBuffer + lenSec, INI_BUFFERSIZE - lenSec, &fp)) + break; + sp = skipleading(LocalBuffer + lenSec); + /* ignore empty strings and comments */ + if (*sp == '\0' || *sp == ';' || *sp == '#') + continue; + /* see whether we reached a new section */ + ep = _tcsrchr(sp, ']'); + if (*sp == '[' && ep != NULL) { + *ep = '\0'; + ini_strncpy(LocalBuffer, sp + 1, INI_BUFFERSIZE, QUOTE_NONE); + lenSec = (int)_tcslen(LocalBuffer) + 1; + continue; + } /* if */ + /* not a new section, test for a key/value pair */ + ep = _tcschr(sp, '='); /* test for the equal sign or colon */ + if (ep == NULL) + ep = _tcschr(sp, ':'); + if (ep == NULL) + continue; /* invalid line, ignore */ + *ep++ = '\0'; /* split the key from the value */ + striptrailing(sp); + ini_strncpy(LocalBuffer + lenSec, sp, INI_BUFFERSIZE - lenSec, QUOTE_NONE); + lenKey = (int)_tcslen(LocalBuffer + lenSec) + 1; + /* clean up the value */ + sp = skipleading(ep); + sp = cleanstring(sp, "es); /* Remove a trailing comment */ + ini_strncpy(LocalBuffer + lenSec + lenKey, sp, INI_BUFFERSIZE - lenSec - lenKey, quotes); + /* call the callback */ + if (!Callback(LocalBuffer, LocalBuffer + lenSec, LocalBuffer + lenSec + lenKey, UserData)) + break; + } /* for */ + + (void)ini_close(&fp); + return 1; +} +#endif /* INI_NOBROWSE */ + #if ! defined INI_READONLY static void ini_tempname(TCHAR *dest, const TCHAR *source, int maxlength) { TCHAR *p; - save_strncpy(dest, source, maxlength); + ini_strncpy(dest, source, maxlength, QUOTE_NONE); p = _tcsrchr(dest, '\0'); assert(p != NULL); *(p - 1) = '~'; } -static void writesection(TCHAR *LocalBuffer, const TCHAR *Section, INI_FILETYPE *fp) +static enum quote_option check_enquote(const TCHAR *Value) { - TCHAR *p; + const TCHAR *p; + + /* run through the value, if it has trailing spaces, or '"', ';' or '#' + * characters, enquote it + */ + assert(Value != NULL); + for (p = Value; *p != '\0' && *p != '"' && *p != ';' && *p != '#'; p++) + /* nothing */; + return (*p != '\0' || (p > Value && *(p - 1) == ' ')) ? QUOTE_ENQUOTE : QUOTE_NONE; +} +static void writesection(TCHAR *LocalBuffer, const TCHAR *Section, INI_FILETYPE *fp) +{ if (Section != NULL && _tcslen(Section) > 0) { + TCHAR *p; LocalBuffer[0] = '['; - save_strncpy(LocalBuffer + 1, Section, INI_BUFFERSIZE - 4); /* -1 for '[', -1 for ']', -2 for '\r\n' */ + ini_strncpy(LocalBuffer + 1, Section, INI_BUFFERSIZE - 4, QUOTE_NONE); /* -1 for '[', -1 for ']', -2 for '\r\n' */ p = _tcsrchr(LocalBuffer, '\0'); assert(p != NULL); *p++ = ']'; _tcscpy(p, INI_LINETERM); /* copy line terminator (typically "\n") */ - ini_write(LocalBuffer, fp); + if (fp != NULL) + (void)ini_write(LocalBuffer, fp); } /* if */ } static void writekey(TCHAR *LocalBuffer, const TCHAR *Key, const TCHAR *Value, INI_FILETYPE *fp) { TCHAR *p; - - save_strncpy(LocalBuffer, Key, INI_BUFFERSIZE - 3); /* -1 for '=', -2 for '\r\n' */ + enum quote_option option = check_enquote(Value); + ini_strncpy(LocalBuffer, Key, INI_BUFFERSIZE - 3, QUOTE_NONE); /* -1 for '=', -2 for '\r\n' */ p = _tcsrchr(LocalBuffer, '\0'); assert(p != NULL); *p++ = '='; - save_strncpy(p, Value, INI_BUFFERSIZE - (p - LocalBuffer) - 2); /* -2 for '\r\n' */ + ini_strncpy(p, Value, INI_BUFFERSIZE - (p - LocalBuffer) - 2, option); /* -2 for '\r\n' */ p = _tcsrchr(LocalBuffer, '\0'); assert(p != NULL); _tcscpy(p, INI_LINETERM); /* copy line terminator (typically "\n") */ - ini_write(LocalBuffer, fp); + if (fp != NULL) + (void)ini_write(LocalBuffer, fp); +} + +static int cache_accum(const TCHAR *string, int *size, int max) +{ + int len = (int)_tcslen(string); + if (*size + len >= max) + return 0; + *size += len; + return 1; +} + +static int cache_flush(TCHAR *buffer, int *size, + INI_FILETYPE *rfp, INI_FILETYPE *wfp, INI_FILEPOS *mark) +{ + int terminator_len = (int)_tcslen(INI_LINETERM); + int pos = 0; + + (void)ini_seek(rfp, mark); + assert(buffer != NULL); + buffer[0] = '\0'; + assert(size != NULL); + assert(*size <= INI_BUFFERSIZE); + while (pos < *size) { + (void)ini_read(buffer + pos, INI_BUFFERSIZE - pos, rfp); + while (pos < *size && buffer[pos] != '\0') + pos++; /* cannot use _tcslen() because buffer may not be zero-terminated */ + } /* while */ + if (buffer[0] != '\0') { + assert(pos > 0 && pos <= INI_BUFFERSIZE); + if (pos == INI_BUFFERSIZE) + pos--; + buffer[pos] = '\0'; /* force zero-termination (may be left unterminated in the above while loop) */ + (void)ini_write(buffer, wfp); + } + ini_tell(rfp, mark); /* update mark */ + *size = 0; + /* return whether the buffer ended with a line termination */ + return (pos > terminator_len) && (_tcscmp(buffer + pos - terminator_len, INI_LINETERM) == 0); +} + +static int close_rename(INI_FILETYPE *rfp, INI_FILETYPE *wfp, const TCHAR *filename, TCHAR *buffer) +{ + (void)ini_close(rfp); + (void)ini_close(wfp); + (void)ini_remove(filename); + (void)ini_tempname(buffer, filename, INI_BUFFERSIZE); + (void)ini_rename(buffer, filename); + return 1; } /** ini_puts() @@ -334,35 +629,66 @@ int ini_puts(const TCHAR *Section, const TCHAR *Key, const TCHAR *Value, const T { INI_FILETYPE rfp; INI_FILETYPE wfp; + INI_FILEPOS mark; + INI_FILEPOS head, tail; TCHAR *sp, *ep; TCHAR LocalBuffer[INI_BUFFERSIZE]; - int len, match, count; + int len, match, flag, cachelen; - assert(Filename!=NULL); + assert(Filename != NULL); if (!ini_openread(Filename, &rfp)) { /* If the .ini file doesn't exist, make a new file */ - if (Key!=NULL && Value!=NULL) { + if (Key != NULL && Value != NULL) { if (!ini_openwrite(Filename, &wfp)) return 0; writesection(LocalBuffer, Section, &wfp); writekey(LocalBuffer, Key, Value, &wfp); - ini_close(&wfp); + (void)ini_close(&wfp); } /* if */ return 1; } /* if */ /* If parameters Key and Value are valid (so this is not an "erase" request) - * and the setting already exists and it already has the correct value, do - * nothing. This early bail-out avoids rewriting the INI file for no reason. + * and the setting already exists, there are two short-cuts to avoid rewriting + * the INI file. */ - if (Key!=NULL && Value!=NULL) { - match = getkeystring(&rfp, Section, Key, -1, -1, LocalBuffer, sizearray(LocalBuffer)); - if (match && _tcscmp(LocalBuffer,Value)==0) { - ini_close(&rfp); - return 1; + if (Key != NULL && Value != NULL) { + ini_tell(&rfp, &mark); + match = getkeystring(&rfp, Section, Key, -1, -1, LocalBuffer, sizearray(LocalBuffer), &head); + if (match) { + /* if the current setting is identical to the one to write, there is + * nothing to do. + */ + if (_tcscmp(LocalBuffer,Value) == 0) { + (void)ini_close(&rfp); + return 1; + } /* if */ + /* if the new setting has the same length as the current setting, and the + * glue file permits file read/write access, we can modify in place. + */ + #if defined ini_openrewrite + /* we already have the start of the (raw) line, get the end too */ + ini_tell(&rfp, &tail); + /* create new buffer (without writing it to file) */ + writekey(LocalBuffer, Key, Value, NULL); + if (_tcslen(LocalBuffer) == (size_t)(tail - head)) { + /* length matches, close the file & re-open for read/write, then + * write at the correct position + */ + (void)ini_close(&rfp); + if (!ini_openrewrite(Filename, &wfp)) + return 0; + (void)ini_seek(&wfp, &head); + (void)ini_write(LocalBuffer, &wfp); + (void)ini_close(&wfp); + return 1; + } /* if */ + #endif } /* if */ - /* key not found, or different value -> proceed (but rewind the input file first) */ - ini_rewind(&rfp); + /* key not found, or different value & length -> proceed (but rewind the + * input file first) + */ + (void)ini_seek(&rfp, &mark); } /* if */ /* Get a temporary file name to copy to. Use the existing name, but with @@ -370,122 +696,120 @@ int ini_puts(const TCHAR *Section, const TCHAR *Key, const TCHAR *Value, const T */ ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE); if (!ini_openwrite(LocalBuffer, &wfp)) { - ini_close(&rfp); + (void)ini_close(&rfp); return 0; } /* if */ + (void)ini_tell(&rfp, &mark); + cachelen = 0; /* Move through the file one line at a time until a section is * matched or until EOF. Copy to temp file as it is read. */ - count = 0; - len = (Section != NULL) ? _tcslen(Section) : 0; + len = (Section != NULL) ? (int)_tcslen(Section) : 0; if (len > 0) { do { if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) { /* Failed to find section, so add one to the end */ + flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); if (Key!=NULL && Value!=NULL) { - ini_write(INI_LINETERM, &wfp); /* force a new line (there may not have been one) behind the last line of the INI file */ - writesection(LocalBuffer, Section, &wfp); - writekey(LocalBuffer, Key, Value, &wfp); + if (!flag) + (void)ini_write(INI_LINETERM, &wfp); /* force a new line behind the last line of the INI file */ + writesection(LocalBuffer, Section, &wfp); + writekey(LocalBuffer, Key, Value, &wfp); } /* if */ - /* Clean up and rename */ - ini_close(&rfp); - ini_close(&wfp); - ini_remove(Filename); - ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE); - ini_rename(LocalBuffer, Filename); - return 1; + return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */ } /* if */ /* Copy the line from source to dest, but not if this is the section that * we are looking for and this section must be removed */ sp = skipleading(LocalBuffer); - ep = _tcschr(sp, ']'); + ep = _tcsrchr(sp, ']'); match = (*sp == '[' && ep != NULL && (int)(ep-sp-1) == len && _tcsnicmp(sp + 1,Section,len) == 0); - if (!match || Key!=NULL) { - /* Remove blank lines, but insert a blank line (possibly one that was - * removed on the previous iteration) before a new section. This creates - * "neat" INI files. - */ - if (_tcslen(sp) > 0) { - if (*sp == '[' && count > 0) - ini_write(INI_LINETERM, &wfp); - ini_write(sp, &wfp); - count++; + if (!match || Key != NULL) { + if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) { + cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); + cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE); } /* if */ } /* if */ } while (!match); } /* if */ + cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + /* when deleting a section, the section head that was just found has not been + * copied to the output file, but because this line was not "accumulated" in + * the cache, the position in the input file was reset to the point just + * before the section; this must now be skipped (again) + */ + if (Key == NULL) { + (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); + (void)ini_tell(&rfp, &mark); + } /* if */ /* Now that the section has been found, find the entry. Stop searching * upon leaving the section's area. Copy the file as it is read * and create an entry if one is not found. */ - len = (Key!=NULL) ? _tcslen(Key) : 0; + len = (Key != NULL) ? (int)_tcslen(Key) : 0; for( ;; ) { if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) { /* EOF without an entry so make one */ + flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); if (Key!=NULL && Value!=NULL) { - ini_write(INI_LINETERM, &wfp); /* force a new line (there may not have been one) behind the last line of the INI file */ - writekey(LocalBuffer, Key, Value, &wfp); + if (!flag) + (void)ini_write(INI_LINETERM, &wfp); /* force a new line behind the last line of the INI file */ + writekey(LocalBuffer, Key, Value, &wfp); } /* if */ - /* Clean up and rename */ - ini_close(&rfp); - ini_close(&wfp); - ini_remove(Filename); - ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE); - ini_rename(LocalBuffer, Filename); - return 1; + return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */ } /* if */ sp = skipleading(LocalBuffer); ep = _tcschr(sp, '='); /* Parse out the equal sign */ if (ep == NULL) ep = _tcschr(sp, ':'); - match = (ep != NULL && (int)(ep-sp) == len && _tcsnicmp(sp,Key,len) == 0); - if ((Key!=NULL && match) || *sp == '[') + match = (ep != NULL && len > 0 && (int)(skiptrailing(ep,sp)-sp) == len && _tcsnicmp(sp,Key,len) == 0); + if ((Key != NULL && match) || *sp == '[') break; /* found the key, or found a new section */ - /* in the section that we re-write, do not copy empty lines */ - if (Key!=NULL && _tcslen(sp) > 0) - ini_write(sp, &wfp); - } /* for */ - if (*sp == '[') { - /* found start of new section, the key was not in the specified - * section, so we add it just before the new section - */ - if (Key!=NULL && Value!=NULL) { - /* We cannot use "writekey()" here, because we need to preserve the - * contents of LocalBuffer. - */ - ini_write(Key, &wfp); - ini_write("=", &wfp); - ini_write(Value, &wfp); - ini_write(INI_LINETERM INI_LINETERM, &wfp); /* put a blank line between the current and the next section */ + /* copy other keys in the section */ + if (Key == NULL) { + (void)ini_tell(&rfp, &mark); /* we are deleting the entire section, so update the read position */ + } else { + if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) { + cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); + cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE); + } /* if */ } /* if */ - /* write the new section header that we read previously */ - ini_write(sp, &wfp); + } /* for */ + /* the key was found, or we just dropped on the next section (meaning that it + * wasn't found); in both cases we need to write the key, but in the latter + * case, we also need to write the line starting the new section after writing + * the key + */ + flag = (*sp == '['); + cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + if (Key != NULL && Value != NULL) + writekey(LocalBuffer, Key, Value, &wfp); + /* cache_flush() reset the "read pointer" to the start of the line with the + * previous key or the new section; read it again (because writekey() destroyed + * the buffer) + */ + (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); + if (flag) { + /* the new section heading needs to be copied to the output file */ + cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE); } else { - /* We found the key; ignore the line just read (with the key and - * the current value) and write the key with the new value. - */ - if (Key!=NULL && Value!=NULL) - writekey(LocalBuffer, Key, Value, &wfp); + /* forget the old key line */ + (void)ini_tell(&rfp, &mark); } /* if */ - /* Copy the rest of the INI file (removing empty lines, except before a section) */ + /* Copy the rest of the INI file */ while (ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) { - sp = skipleading(LocalBuffer); - if (_tcslen(sp) > 0) { - if (*sp == '[') - ini_write(INI_LINETERM, &wfp); - ini_write(sp, &wfp); + if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) { + cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); + cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE); } /* if */ } /* while */ - /* Clean up and rename */ - ini_close(&rfp); - ini_close(&wfp); - ini_remove(Filename); - ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE); - ini_rename(LocalBuffer, Filename); - return 1; + cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); + return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */ } /* Ansi C "itoa" based on Kernighan & Ritchie's "Ansi C" book. */ @@ -493,11 +817,9 @@ int ini_puts(const TCHAR *Section, const TCHAR *Key, const TCHAR *Value, const T static void strreverse(TCHAR *str) { - TCHAR t; int i, j; - - for (i = 0, j = _tcslen(str) - 1; i < j; i++, j--) { - t = str[i]; + for (i = 0, j = (int)_tcslen(str) - 1; i < j; i++, j--) { + TCHAR t = str[i]; str[i] = str[j]; str[j] = t; } /* for */ @@ -507,11 +829,10 @@ static void long2str(long value, TCHAR *str) { int i = 0; long sign = value; - int n; /* generate digits in reverse order */ do { - n = (int)(value % 10); /* get next lowest digit */ + int n = (int)(value % 10); /* get next lowest digit */ str[i++] = (TCHAR)(ABS(n) + '0'); /* handle case of negative digit */ } while (value /= 10); /* delete the lowest digit */ if (sign < 0) @@ -523,7 +844,7 @@ static void long2str(long value, TCHAR *str) /** ini_putl() * \param Section the name of the section to write the value in - * \param Key the name of the entry to write, or NULL to erase all keys in the section + * \param Key the name of the entry to write * \param Value the value to write * \param Filename the name and full path of the .ini file to write to * @@ -531,28 +852,25 @@ static void long2str(long value, TCHAR *str) */ int ini_putl(const TCHAR *Section, const TCHAR *Key, long Value, const TCHAR *Filename) { - TCHAR str[32]; - long2str(Value, str); - return ini_puts(Section, Key, str, Filename); + TCHAR LocalBuffer[32]; + long2str(Value, LocalBuffer); + return ini_puts(Section, Key, LocalBuffer, Filename); } -#endif /* !INI_READONLY */ - -#if defined PORTABLE_STRNICMP -int strnicmp(const TCHAR *s1, const TCHAR *s2, size_t n) +#if defined INI_REAL +/** ini_putf() + * \param Section the name of the section to write the value in + * \param Key the name of the entry to write + * \param Value the value to write + * \param Filename the name and full path of the .ini file to write to + * + * \return 1 if successful, otherwise 0 + */ +int ini_putf(const TCHAR *Section, const TCHAR *Key, INI_REAL Value, const TCHAR *Filename) { - register unsigned TCHAR c1, c2; - - while (n-- != 0 && (*s1 || *s2)) { - c1 = *(const unsigned TCHAR *)s1++; - if ('a' <= c1 && c1 <= 'z') - c1 += ('A' - 'a'); - c2 = *(const unsigned TCHAR *)s2++; - if ('a' <= c2 && c2 <= 'z') - c2 += ('A' - 'a'); - if (c1 != c2) - return c1 - c2; - } /* while */ - return 0; + TCHAR LocalBuffer[64]; + ini_ftoa(LocalBuffer, Value); + return ini_puts(Section, Key, LocalBuffer, Filename); } -#endif /* PORTABLE_STRNICMP */ +#endif /* INI_REAL */ +#endif /* !INI_READONLY */ diff --git a/minIni_07/minIni.h b/minIni_07/minIni.h index 7ad254d..ff0753c 100644 --- a/minIni_07/minIni.h +++ b/minIni_07/minIni.h @@ -1,6 +1,6 @@ /* minIni - Multi-Platform INI file parser, suitable for embedded systems * - * Copyright (c) ITB CompuPhase, 2008-2009 + * Copyright (c) CompuPhase, 2008-2017 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy @@ -14,7 +14,7 @@ * License for the specific language governing permissions and limitations * under the License. * - * Version: $Id: minIni.h 24 2009-05-06 08:01:53Z thiadmer.riemersma $ + * Version: $Id: minIni.h 53 2015-01-18 13:35:11Z thiadmer.riemersma@gmail.com $ */ #ifndef MININI_H #define MININI_H @@ -23,8 +23,10 @@ #if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY #include -#elif !defined __T - typedef char TCHAR; + #define mTCHAR TCHAR +#else + /* force TCHAR to be "char", but only for minIni */ + #define mTCHAR char #endif #if !defined INI_BUFFERSIZE @@ -35,52 +37,121 @@ extern "C" { #endif -long ini_getl(const TCHAR *Section, const TCHAR *Key, long DefValue, const TCHAR *Filename); -int ini_gets(const TCHAR *Section, const TCHAR *Key, const TCHAR *DefValue, TCHAR *Buffer, int BufferSize, const TCHAR *Filename); -int ini_putl(const TCHAR *Section, const TCHAR *Key, long Value, const TCHAR *Filename); -int ini_puts(const TCHAR *Section, const TCHAR *Key, const TCHAR *Value, const TCHAR *Filename); -int ini_getsection(int idx, TCHAR *Buffer, int BufferSize, const TCHAR *Filename); -int ini_getkey(const TCHAR *Section, int idx, TCHAR *Buffer, int BufferSize, const TCHAR *Filename); +int ini_getbool(const mTCHAR *Section, const mTCHAR *Key, int DefValue, const mTCHAR *Filename); +long ini_getl(const mTCHAR *Section, const mTCHAR *Key, long DefValue, const mTCHAR *Filename); +int ini_gets(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *DefValue, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); +int ini_getsection(int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); +int ini_getkey(const mTCHAR *Section, int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); + +#if defined INI_REAL +INI_REAL ini_getf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL DefValue, const mTCHAR *Filename); +#endif + +#if !defined INI_READONLY +int ini_putl(const mTCHAR *Section, const mTCHAR *Key, long Value, const mTCHAR *Filename); +int ini_puts(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, const mTCHAR *Filename); +#if defined INI_REAL +int ini_putf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL Value, const mTCHAR *Filename); +#endif +#endif /* INI_READONLY */ + +#if !defined INI_NOBROWSE +typedef int (*INI_CALLBACK)(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, void *UserData); +int ini_browse(INI_CALLBACK Callback, void *UserData, const mTCHAR *Filename); +#endif /* INI_NOBROWSE */ #if defined __cplusplus } #endif -#ifdef NOT_DEF + #if defined __cplusplus -#include -/* The C++ class in minIni.h was contributed by Steven Van Ingelgem. */ -class minIni -{ -public: - minIni(const std::string& filename) : iniFilename(filename) - { } +#if defined __WXWINDOWS__ + #include "wxMinIni.h" +#else + #include + + /* The C++ class in minIni.h was contributed by Steven Van Ingelgem. */ + class minIni + { + public: + minIni(const std::string& filename) : iniFilename(filename) + { } + + bool getbool(const std::string& Section, const std::string& Key, bool DefValue=false) const + { return ini_getbool(Section.c_str(), Key.c_str(), int(DefValue), iniFilename.c_str()) != 0; } + + long getl(const std::string& Section, const std::string& Key, long DefValue=0) const + { return ini_getl(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); } + + int geti(const std::string& Section, const std::string& Key, int DefValue=0) const + { return static_cast(this->getl(Section, Key, long(DefValue))); } + + std::string gets(const std::string& Section, const std::string& Key, const std::string& DefValue="") const + { + char buffer[INI_BUFFERSIZE]; + ini_gets(Section.c_str(), Key.c_str(), DefValue.c_str(), buffer, INI_BUFFERSIZE, iniFilename.c_str()); + return buffer; + } + + std::string getsection(int idx) const + { + char buffer[INI_BUFFERSIZE]; + ini_getsection(idx, buffer, INI_BUFFERSIZE, iniFilename.c_str()); + return buffer; + } + + std::string getkey(const std::string& Section, int idx) const + { + char buffer[INI_BUFFERSIZE]; + ini_getkey(Section.c_str(), idx, buffer, INI_BUFFERSIZE, iniFilename.c_str()); + return buffer; + } + +#if defined INI_REAL + INI_REAL getf(const std::string& Section, const std::string& Key, INI_REAL DefValue=0) const + { return ini_getf(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); } +#endif + +#if ! defined INI_READONLY + bool put(const std::string& Section, const std::string& Key, long Value) + { return ini_putl(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; } + + bool put(const std::string& Section, const std::string& Key, int Value) + { return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; } - long getl(const std::string& Section, const std::string& Key, long DefValue=0) const - { return ini_getl(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); } + bool put(const std::string& Section, const std::string& Key, bool Value) + { return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; } - long geti(const std::string& Section, const std::string& Key, int DefValue=0) const - { return reinterpret_cast( this->getl(Section, Key, DefValue) ); } + bool put(const std::string& Section, const std::string& Key, const std::string& Value) + { return ini_puts(Section.c_str(), Key.c_str(), Value.c_str(), iniFilename.c_str()) != 0; } - std::string gets(const std::string& Section, const std::string& Key, const std::string& DefValue="") const - { - char buffer[INI_BUFFERSIZE]; - ini_gets(Section.c_str(), Key.c_str(), DefValue.c_str(), buffer, INI_BUFFERSIZE, iniFilename.c_str()); - return buffer; - } + bool put(const std::string& Section, const std::string& Key, const char* Value) + { return ini_puts(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; } + +#if defined INI_REAL + bool put(const std::string& Section, const std::string& Key, INI_REAL Value) + { return ini_putf(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; } +#endif - bool put(const std::string& Section, const std::string& Key, long Value) const - { return ini_putl(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()); } + bool del(const std::string& Section, const std::string& Key) + { return ini_puts(Section.c_str(), Key.c_str(), 0, iniFilename.c_str()) != 0; } - bool put(const std::string& Section, const std::string& Key, const std::string& Value) const - { return ini_puts(Section.c_str(), Key.c_str(), Value.c_str(), iniFilename.c_str()); } + bool del(const std::string& Section) + { return ini_puts(Section.c_str(), 0, 0, iniFilename.c_str()) != 0; } +#endif + +#if !defined INI_NOBROWSE + bool browse(INI_CALLBACK Callback, void *UserData) const + { return ini_browse(Callback, UserData, iniFilename.c_str()) != 0; } +#endif -private: + private: std::string iniFilename; -}; + }; +#endif /* __WXWINDOWS__ */ #endif /* __cplusplus */ -#endif /* NOT_DEF */ #endif /* MININI_H */ diff --git a/minIni_07/test.c b/minIni_07/test.c index 5e2001b..7722efd 100644 --- a/minIni_07/test.c +++ b/minIni_07/test.c @@ -1,6 +1,6 @@ /* Simple test program * - * wcl386 -wx -d2 -q test.c minini.c + * gcc -o test test.c minIni.c */ #include #include @@ -10,6 +10,14 @@ #define sizearray(a) (sizeof(a) / sizeof((a)[0])) const char inifile[] = "test.ini"; +const char inifile2[] = "testplain.ini"; + +int Callback(const char *section, const char *key, const char *value, void *userdata) +{ + (void)userdata; /* this parameter is not used in this example */ + printf(" [%s]\t%s=%s\n", section, key, value); + return 1; +} int main(void) { @@ -19,12 +27,18 @@ int main(void) char section[50]; /* string reading */ - n = ini_gets("first", "string", "aap", str, sizearray(str), inifile); + n = ini_gets("first", "string", "dummy", str, sizearray(str), inifile); assert(n==4 && strcmp(str,"noot")==0); - n = ini_gets("second", "string", "aap", str, sizearray(str), inifile); + n = ini_gets("second", "string", "dummy", str, sizearray(str), inifile); assert(n==4 && strcmp(str,"mies")==0); - n = ini_gets("first", "dummy", "aap", str, sizearray(str), inifile); - assert(n==3 && strcmp(str,"aap")==0); + n = ini_gets("first", "undefined", "dummy", str, sizearray(str), inifile); + assert(n==5 && strcmp(str,"dummy")==0); + /* ----- */ + n = ini_gets("", "string", "dummy", str, sizearray(str), inifile2); + assert(n==4 && strcmp(str,"noot")==0); + n = ini_gets(NULL, "string", "dummy", str, sizearray(str), inifile2); + assert(n==4 && strcmp(str,"noot")==0); + /* ----- */ printf("1. String reading tests passed\n"); /* value reading */ @@ -32,36 +46,60 @@ int main(void) assert(n==1); n = ini_getl("second", "val", -1, inifile); assert(n==2); - n = ini_getl("first", "dummy", -1, inifile); + n = ini_getl("first", "undefined", -1, inifile); assert(n==-1); + /* ----- */ + n = ini_getl(NULL, "val", -1, inifile2); + assert(n==1); + /* ----- */ printf("2. Value reading tests passed\n"); /* string writing */ - n = ini_puts("first", "alt", "correct", inifile); + n = ini_puts("first", "alt", "flagged as \"correct\"", inifile); assert(n==1); - n = ini_gets("first", "alt", "aap", str, sizearray(str), inifile); - assert(n==7 && strcmp(str,"correct")==0); + n = ini_gets("first", "alt", "dummy", str, sizearray(str), inifile); + assert(n==20 && strcmp(str,"flagged as \"correct\"")==0); /* ----- */ n = ini_puts("second", "alt", "correct", inifile); assert(n==1); - n = ini_gets("second", "alt", "aap", str, sizearray(str), inifile); + n = ini_gets("second", "alt", "dummy", str, sizearray(str), inifile); assert(n==7 && strcmp(str,"correct")==0); /* ----- */ - n = ini_puts("third", "alt", "correct", inifile); + n = ini_puts("third", "test", "correct", inifile); assert(n==1); - n = ini_gets("third", "alt", "aap", str, sizearray(str), inifile); + n = ini_gets("third", "test", "dummy", str, sizearray(str), inifile); + assert(n==7 && strcmp(str,"correct")==0); + /* ----- */ + n = ini_puts("second", "alt", "overwrite", inifile); + assert(n==1); + n = ini_gets("second", "alt", "dummy", str, sizearray(str), inifile); + assert(n==9 && strcmp(str,"overwrite")==0); + /* ----- */ + n = ini_puts("second", "alt", "123456789", inifile); + assert(n==1); + n = ini_gets("second", "alt", "dummy", str, sizearray(str), inifile); + assert(n==9 && strcmp(str,"123456789")==0); + /* ----- */ + n = ini_puts(NULL, "alt", "correct", inifile2); + assert(n==1); + n = ini_gets(NULL, "alt", "dummy", str, sizearray(str), inifile2); assert(n==7 && strcmp(str,"correct")==0); /* ----- */ printf("3. String writing tests passed\n"); /* section/key enumeration */ + printf("4. Section/key enumeration, file structure follows\n"); for (s = 0; ini_getsection(s, section, sizearray(section), inifile) > 0; s++) { - printf("[%s]\n", section); + printf(" [%s]\n", section); for (k = 0; ini_getkey(section, k, str, sizearray(str), inifile) > 0; k++) { printf("\t%s\n", str); } /* for */ } /* for */ - + + /* browsing through the file */ + printf("5. browse through all settings, file field list follows\n"); + ini_browse(Callback, NULL, inifile); + /* string deletion */ n = ini_puts("first", "alt", NULL, inifile); assert(n==1); @@ -69,6 +107,10 @@ int main(void) assert(n==1); n = ini_puts("third", NULL, NULL, inifile); assert(n==1); + /* ----- */ + n = ini_puts(NULL, "alt", NULL, inifile2); + assert(n==1); + printf("6. String deletion tests passed\n"); return 0; } diff --git a/minIni_07/test.ini b/minIni_07/test.ini index b215a0a..3c22632 100644 --- a/minIni_07/test.ini +++ b/minIni_07/test.ini @@ -1,8 +1,8 @@ [First] -String=noot +String=noot # trailing commment Val=1 [Second] Val = 2 -String = mies #comment=3 +String = mies diff --git a/minIni_07/test2.cc b/minIni_07/test2.cc new file mode 100644 index 0000000..4e19b31 --- /dev/null +++ b/minIni_07/test2.cc @@ -0,0 +1,80 @@ +/* + gcc -o minIni.o -c minIni.c + g++ -o test2.o -c test2.cc + g++ -o test2 test2.o minIni.o + ./test2 +*/ + + +#include +#include +#include +using namespace std ; + +#include "minIni.h" + +int main(void) +{ + minIni ini("test.ini"); + string s; + + /* string reading */ + s = ini.gets( "first", "string" , "aap" ); + assert(s == "noot"); + s = ini.gets( "second", "string" , "aap" ); + assert(s == "mies"); + s = ini.gets( "first", "dummy" , "aap" ); + assert(s == "aap"); + cout << "1. String reading tests passed" << endl ; + + + /* value reading */ + long n; + n = ini.getl("first", "val", -1 ); + assert(n==1); + n = ini.getl("second", "val", -1); + assert(n==2); + n = ini.getl("first", "dummy", -1); + assert(n==-1); + cout << "2. Value reading tests passed" << endl ; + + + /* string writing */ + bool b; + b = ini.put("first", "alt", "flagged as \"correct\""); + assert(b); + s = ini.gets("first", "alt", "aap"); + assert(s=="flagged as \"correct\""); + + b = ini.put("second", "alt", "correct"); + assert(b); + s = ini.gets("second", "alt", "aap"); + assert(s=="correct"); + + b = ini.put("third", "alt", "correct"); + assert(b); + s = ini.gets("third", "alt", "aap" ); + assert(s=="correct"); + cout << "3. String writing tests passed" << endl; + + /* section/key enumeration */ + cout << "4. section/key enumeration; file contents follows" << endl; + string section; + for (int is = 0; section = ini.getsection(is), section.length() > 0; is++) { + cout << " [" << section.c_str() << "]" << endl; + for (int ik = 0; s = ini.getkey(section, ik), s.length() > 0; ik++) { + cout << "\t" << s.c_str() << endl; + } + } + + /* string deletion */ + b = ini.del("first", "alt"); + assert(b); + b = ini.del("second", "alt"); + assert(b); + b = ini.del("third"); + assert(b); + cout << "5. string deletion passed " << endl; + + return 0; +} diff --git a/minIni_07/testplain.ini b/minIni_07/testplain.ini new file mode 100644 index 0000000..53df5ca --- /dev/null +++ b/minIni_07/testplain.ini @@ -0,0 +1,3 @@ +String=noot # trailing commment +#comment=3 +Val=1 diff --git a/minIni_07/wxMinIni.h b/minIni_07/wxMinIni.h index 51609f9..e59a74e 100644 --- a/minIni_07/wxMinIni.h +++ b/minIni_07/wxMinIni.h @@ -1,73 +1,101 @@ +/* minIni - Multi-Platform INI file parser, wxWidgets interface + * + * Copyright (c) CompuPhase, 2008-2012 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Version: $Id: wxMinIni.h 44 2012-01-04 15:52:56Z thiadmer.riemersma@gmail.com $ + */ #ifndef WXMININI_H #define WXMININI_H #include -#include "minini.h" - -#if defined __linux || defined __linux__ || defined __LINUX__ \ - || defined FREEBSD || defined __FreeBSD__ || defined __OpenBSD__ - #define DIRSEP_CHAR '/' - #define DIRSEP_STR "/" -#else - #define DIRSEP_CHAR '\\' - #define DIRSEP_STR "\\" -#endif +#include "minIni.h" -class minIni { +class minIni +{ public: - minIni(const wxString& name, const wxString& path=wxT("")) - { - if (path.Len() > 0) - iniFilename = path; - else - iniFilename = wxGetCwd(); - int len = iniFilename.Len(); - if (len > 0 && iniFilename[len] != DIRSEP_CHAR) - iniFilename += wxT(DIRSEP_STR); - iniFilename += name; - } - - long getl(const wxString& Section, const wxString& Key, long DefValue=0, const wxString& Filename=wxT("")) - { - wxString name = Filename.Len() > 0 ? Filename : iniFilename; - return ini_getl(Section.utf8_str(), Key.utf8_str(), DefValue, name.utf8_str()); - } - - int geti(const wxString& Section, const wxString& Key, int DefValue=0, const wxString& Filename=wxT("")) - { - wxString name = Filename.Len() > 0 ? Filename : iniFilename; - return (int)ini_getl(Section.utf8_str(), Key.utf8_str(), DefValue, name.utf8_str()); - } - - wxString gets(const wxString& Section, const wxString& Key, const wxString& DefValue=wxT(""), const wxString& Filename=wxT("")) - { - wxString name = Filename.Len() > 0 ? Filename : iniFilename; - char buffer[INI_BUFFERSIZE]; - ini_gets(Section.utf8_str(), Key.utf8_str(), DefValue.utf8_str(), buffer, INI_BUFFERSIZE, name.utf8_str()); - wxString result = wxString::FromUTF8(buffer); - return result; - } - - bool put(const wxString& Section, const wxString& Key, long Value, const wxString& Filename=wxT("")) - { - wxString name = Filename.Len() > 0 ? Filename : iniFilename; - return ini_putl(Section.utf8_str(), Key.utf8_str(), Value, name.utf8_str()); - } - - bool put(const wxString& Section, const wxString& Key, int Value, const wxString& Filename=wxT("")) - { - wxString name = Filename.Len() > 0 ? Filename : iniFilename; - return ini_putl(Section.utf8_str(), Key.utf8_str(), Value, name.utf8_str()); - } - - bool put(const wxString& Section, const wxString& Key, const wxString& Value, const wxString& Filename=wxT("")) - { - wxString name = Filename.Len() > 0 ? Filename : iniFilename; - return ini_puts(Section.utf8_str(), Key.utf8_str(), Value.utf8_str(), name.utf8_str()); - } + minIni(const wxString& filename) : iniFilename(filename) + { } + + bool getbool(const wxString& Section, const wxString& Key, bool DefValue=false) const + { return ini_getbool(Section.utf8_str(), Key.utf8_str(), int(DefValue), iniFilename.utf8_str()) != 0; } + + long getl(const wxString& Section, const wxString& Key, long DefValue=0) const + { return ini_getl(Section.utf8_str(), Key.utf8_str(), DefValue, iniFilename.utf8_str()); } + + int geti(const wxString& Section, const wxString& Key, int DefValue=0) const + { return static_cast(ini_getl(Section.utf8_str(), Key.utf8_str(), (long)DefValue, iniFilename.utf8_str())); } + + wxString gets(const wxString& Section, const wxString& Key, const wxString& DefValue=wxT("")) const + { + char buffer[INI_BUFFERSIZE]; + ini_gets(Section.utf8_str(), Key.utf8_str(), DefValue.utf8_str(), buffer, INI_BUFFERSIZE, iniFilename.utf8_str()); + wxString result = wxString::FromUTF8(buffer); + return result; + } + + wxString getsection(int idx) const + { + char buffer[INI_BUFFERSIZE]; + ini_getsection(idx, buffer, INI_BUFFERSIZE, iniFilename.utf8_str()); + wxString result = wxString::FromUTF8(buffer); + return result; + } + + wxString getkey(const wxString& Section, int idx) const + { + char buffer[INI_BUFFERSIZE]; + ini_getkey(Section.utf8_str(), idx, buffer, INI_BUFFERSIZE, iniFilename.utf8_str()); + wxString result = wxString::FromUTF8(buffer); + return result; + } + +#if defined INI_REAL + INI_REAL getf(const wxString& Section, wxString& Key, INI_REAL DefValue=0) const + { return ini_getf(Section.utf8_str(), Key.utf8_str(), DefValue, iniFilename.utf8_str()); } +#endif + +#if ! defined INI_READONLY + bool put(const wxString& Section, const wxString& Key, long Value) const + { return ini_putl(Section.utf8_str(), Key.utf8_str(), Value, iniFilename.utf8_str()) != 0; } + + bool put(const wxString& Section, const wxString& Key, int Value) const + { return ini_putl(Section.utf8_str(), Key.utf8_str(), (long)Value, iniFilename.utf8_str()) != 0; } + + bool put(const wxString& Section, const wxString& Key, bool Value) const + { return ini_putl(Section.utf8_str(), Key.utf8_str(), (long)Value, iniFilename.utf8_str()) != 0; } + + bool put(const wxString& Section, const wxString& Key, const wxString& Value) const + { return ini_puts(Section.utf8_str(), Key.utf8_str(), Value.utf8_str(), iniFilename.utf8_str()) != 0; } + + bool put(const wxString& Section, const wxString& Key, const char* Value) const + { return ini_puts(Section.utf8_str(), Key.utf8_str(), Value, iniFilename.utf8_str()) != 0; } + +#if defined INI_REAL + bool put(const wxString& Section, const wxString& Key, INI_REAL Value) const + { return ini_putf(Section.utf8_str(), Key.utf8_str(), Value, iniFilename.utf8_str()) != 0; } +#endif + + bool del(const wxString& Section, const wxString& Key) const + { return ini_puts(Section.utf8_str(), Key.utf8_str(), 0, iniFilename.utf8_str()) != 0; } + + bool del(const wxString& Section) const + { return ini_puts(Section.utf8_str(), 0, 0, iniFilename.utf8_str()) != 0; } +#endif private: - wxString iniFilename; + wxString iniFilename; }; #endif /* WXMININI_H */ diff --git a/src/adapter.cpp b/src/adapter.cpp index f729a46..9d5e0a7 100755 --- a/src/adapter.cpp +++ b/src/adapter.cpp @@ -1,456 +1,470 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// #include "internal.hpp" #include "adapter.hpp" +#include +#include #include "device_datum.hpp" #include "cutting_tool.hpp" #include "logger.hpp" -Adapter::Adapter(int aPort, int aScanDelay) - : mNumDeviceData(0), mInitializeClient(NULL) + +Adapter::Adapter(int port, int scanDelayMs) : + mServer(nullptr), + mScanDelay{scanDelayMs}, + mPort(port), + mDisableFlush(false), + mHeartbeatFrequency{10000}, + mRunning(false), + mInitializeClient(nullptr) { - mScanDelay = aScanDelay; - mServer = 0; - mPort = aPort; - mHeartbeatFrequency = 10000; - mMaxDatum = INITIAL_MAX_DEVICE_DATA; - mRunning = false; - mDeviceData = new DeviceDatum*[mMaxDatum]; + #ifdef THREADED - mServerThread = 0; + mServerThread = nullptr; #endif + + mDeviceData.reserve(INITIAL_MAX_DEVICE_DATA); } + Adapter::~Adapter() { - mRunning = false; - if (mServer) - delete mServer; + mRunning = false; + mServer.reset(); - delete[] mDeviceData; + for(auto value : mDeviceData) + delete value; + mDeviceData.clear(); } -/* Add a data value to the list of data values */ -void Adapter::addDatum(DeviceDatum &aValue) + +// Add a data value to the list of data values +void Adapter::addDatum(DeviceDatum &value) { - if (mNumDeviceData >= mMaxDatum - 1) - { - DeviceDatum** devData = new DeviceDatum*[mMaxDatum * 2]; - memcpy(devData, mDeviceData, sizeof(DeviceDatum*) * mMaxDatum); - delete[] mDeviceData; - - mDeviceData = devData; - mMaxDatum *= 2; - } - - mDeviceData[mNumDeviceData++] = &aValue; - mDeviceData[mNumDeviceData] = 0; + // If we are approaching our capacity then resize + if(mDeviceData.size() == mDeviceData.capacity()) + mDeviceData.reserve(mDeviceData.capacity() * 2u); + + mDeviceData.push_back(&value); } -void Adapter::sleepMs(int aMs) + +void Adapter::sleepMs(std::chrono::milliseconds ms) { -#ifndef WIN32 - usleep(aMs * 1000); -#else - Sleep(aMs); -#endif - + std::this_thread::sleep_for(ms); } #if THREADED #ifdef WIN32 -static int ServerThread(void *aArg) +static int ServerThread(void *arg) { - Adapter *adapter = (Adapter*) aArg; - adapter->serverThread(); - return 0; + auto adapter = (Adapter*)arg; + adapter->serverThread(); + return 0; } -bool Adapter::startServerThread() +bool Adapter::startServerThread() { - if (gLogger == NULL) gLogger = new Logger(); - - mServer = new Server(mPort, mHeartbeatFrequency); - mRunning = true; + if (!gLogger) + gLogger = new Logger(); + + mServer = std::make_unique(mPort, mHeartbeatFrequency); + mRunning = true; - mServerThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) &ServerThread, this, 0, 0); - if (mServerThread == NULL) { - fprintf(stderr, "Cannot create server thread"); - delete mServer; - return false; - } else { - Sleep(10); - } - - return true; + mServerThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) &ServerThread, this, 0, 0); + if (!mServerThread) + { + fprintf(stderr, "Cannot create server thread"); + mServer.reset(); + return false; + } + else + { + sleepMs(std::chrono::milliseconds(10)); + } + + return true; } + int Adapter::waitUntilDone() { - int ret = 1; - if (mServerThread != 0) { - DWORD res = WaitForSingleObject(mServerThread, INFINITE); - if (res == WAIT_OBJECT_0) - { - if (GetExitCodeThread(mServerThread, &res)) - ret = res; - } - } - return ret; + int ret = 1; + if (mServerThread != 0) + { + auto res = WaitForSingleObject(mServerThread, INFINITE); + if (res == WAIT_OBJECT_0) + { + if (GetExitCodeThread(mServerThread, &res)) + ret = res; + } + } + return ret; } #else -static void *ServerThread(void *aArg) +static void *ServerThread(void *arg) { - Adapter *adapter = (Adapter*) aArg; - adapter->serverThread(); + auto adapter = (Adapter*)arg; + adapter->serverThread(); - static int res = 0; - return &res; + static int res = 0; + return &res; } -bool Adapter::startServerThread() +bool Adapter::startServerThread() { - if (gLogger == NULL) gLogger = new Logger(); - - mServer = new Server(mPort, mHeartbeatFrequency); - mRunning = true; + if (!gLogger) + gLogger = new Logger(); + + mServer = std::make_unique(mPort, mHeartbeatFrequency); + mRunning = true; - int res = pthread_create(&mServerThread, NULL, ::ServerThread, this); - if (res != 0) { - fprintf(stderr, "Cannot create server thread"); - delete mServer; - return false; - } - - return true; + auto res = pthread_create(&mServerThread, nullptr, ::ServerThread, this); + if (res != 0) + { + fprintf(stderr, "Cannot create server thread"); + mServer.reset(); + return false; + } + + return true; } + int Adapter::waitUntilDone() { - int ret = 1; - if (mServerThread != 0) { - int *value; - int res = pthread_join(mServerThread, (void**) &value); - if (res != 0) ret = *value; - } - return ret; + int ret = 1; + if (mServerThread != 0) + { + int *value(nullptr); + auto res = pthread_join(mServerThread, (void**) &value); + if (res != 0) + ret = *value; + } + return ret; } #endif -/* Poll every second for activity. We could do blocking but it complicates - * list management and locking. May refactor this when we have more time. - */ +// Poll every second for activity. We could do blocking but it complicates +// list management and locking. May refactor this when we have more time. +// void Adapter::serverThread() { - while (mRunning) { - connectToClients(); - readFromClients(); + while (mRunning) + { + connectToClients(); + readFromClients(); - periodicWork(); - - sleepMs(mScanDelay); - } + periodicWork(); + + sleepMs(mScanDelay); + } } #endif -/* - * Reads from clients, either blocking or polling. - */ -void Adapter::readFromClients() + +// +// Reads from clients, either blocking or polling. +// +void Adapter::readFromClients() { - mServer->readFromClients(); + mServer->readFromClients(); } -/* - * Checks for new client connections, either blocking or polling. - */ +// +// Checks for new client connections, either blocking or polling. +// void Adapter::connectToClients() { - /* Check if we have any new clients */ - Client *client = mServer->connectToClients(); - if (client != NULL) - sendInitialData(client); -} - -/* - * This is the main loop of the application. Once the server is started and - * the application runs forever until it is killed. The process follows this flow: - * See if any new clients have arrived. - * If new clients are present, sent the initial values to them. - * Read from the clients any data that is currently in the socket to keep anyone from - * blocking. - * If we have at least one client: - * Timestamp the buffer - * gather data from the API - * send the data values that have changed to the clients - * Sleep for a few millies and repeat. - */ + // Check if we have any new clients + auto client = mServer->connectToClients(); + if (client) + sendInitialData(client); +} + + +// +// This is the main loop of the application. Once the server is started and +// the application runs forever until it is killed. The process follows this flow: +// See if any new clients have arrived. +// If new clients are present, sent the initial values to them. +// Read from the clients any data that is currently in the socket to keep anyone from +// blocking. +// If we have at least one client: +// Timestamp the buffer +// gather data from the API +// send the data values that have changed to the clients +// Sleep for a few millies and repeat. +// void Adapter::startServer() -{ - if (gLogger == NULL) gLogger = new Logger(); - - mServer = new Server(mPort, mHeartbeatFrequency); - mRunning = true; - - /* Process untill stopped */ - while (mRunning) - { - /* Check if we have any new clients */ - connectToClients(); - - /* Read and all data from the clients */ - readFromClients(); - - /* Don't bother getting data if we don't have anyone to read it */ - if (mServer->numClients() > 0) - { - MTCAutoLock lock(mGatherLock); - - begin(); - mBuffer.timestamp(); - gatherDeviceData(); - prepare(); - sendChangedData(); - mBuffer.reset(); - cleanup(); - } - else if (mServer->hasClients()) - { - clientsDisconnected(); - } - - sleepMs(mScanDelay); - } - - delete mServer; - mServer = NULL; +{ + if (!gLogger) + gLogger = new Logger(); + + mServer = std::make_unique(mPort, mHeartbeatFrequency); + mRunning = true; + + // Process untill stopped + while (mRunning) + { + // Check if we have any new clients + connectToClients(); + + // Read and all data from the clients + readFromClients(); + + // Don't bother getting data if we don't have anyone to read it + if (mServer->numClients() > 0) + { + std::lock_guard lock(mGatherLock); + + begin(); + mBuffer.timestamp(); + gatherDeviceData(); + prepare(); + sendChangedData(); + mBuffer.reset(); + cleanup(); + } + else if (mServer->hasClients()) + clientsDisconnected(); + + sleepMs(mScanDelay); + } + + mServer.reset(); } + void Adapter::begin() { - for (int i = 0; i < mNumDeviceData; i++) - { - DeviceDatum *value = mDeviceData[i]; - value->begin(); - } + for(auto value : mDeviceData) + value->begin(); } + void Adapter::prepare() { - for (int i = 0; i < mNumDeviceData; i++) - { - DeviceDatum *value = mDeviceData[i]; - value->prepare(); - } + for(auto value : mDeviceData) + value->prepare(); } + void Adapter::cleanup() { - for (int i = 0; i < mNumDeviceData; i++) - { - DeviceDatum *value = mDeviceData[i]; - value->cleanup(); - } + for(auto value : mDeviceData) + value->cleanup(); } -void Adapter::beginGather(const char *aTs, bool aSweep) + +void Adapter::beginGather(const char *timestamp, bool sweep) { - mGatherLock.lock(); + mGatherLock.lock(); + + if (sweep) + begin(); - if (aSweep) begin(); - - mBuffer.reset(); - if (aTs != NULL) - mBuffer.setTimestamp(aTs); - else - mBuffer.timestamp(); + mBuffer.reset(); + if (timestamp) + mBuffer.setTimestamp(timestamp); + else + mBuffer.timestamp(); } + void Adapter::completeGather() { - prepare(); - sendChangedData(); - cleanup(); - - mGatherLock.unlock(); + prepare(); + sendChangedData(); + cleanup(); + + mGatherLock.unlock(); } + void Adapter::stopServer() -{ - mRunning = false; +{ + mRunning = false; } -/* Send a single value to the buffer. */ -void Adapter::sendDatum(DeviceDatum *aValue) + +// Send a single value to the buffer. +void Adapter::sendDatum(DeviceDatum *value) { - if (aValue->requiresFlush()) - sendBuffer(); - aValue->append(mBuffer); - if (aValue->requiresFlush()) - sendBuffer(); + if (value->requiresFlush()) + sendBuffer(); + value->append(mBuffer); + if (value->requiresFlush()) + sendBuffer(); } -/* Send the buffer to the clients. Only sends if there is something in the buffer. */ + +// Send the buffer to the clients. Only sends if there is something in the buffer. void Adapter::sendBuffer() { - if (mServer != 0 && mBuffer.length() > 0) - { - mBuffer.append("\n"); - if (mInitializeClient != NULL) - mServer->sendToClient(mInitializeClient, mBuffer); - else - mServer->sendToClients(mBuffer); - mBuffer.reset(); - } + if (mServer && mBuffer.length()) + { + mBuffer.append("\n"); + if (mInitializeClient) + mServer->sendToClient(mInitializeClient, mBuffer); + else + mServer->sendToClients(mBuffer); + mBuffer.reset(); + } } -/* Send the initial values to a client */ -void Adapter::sendInitialData(Client *aClient) + +// Send the initial values to a client +void Adapter::sendInitialData(Client *client) { - MTCAutoLock lock(mGatherLock); + std::lock_guard lock(mGatherLock); - mInitializeClient = aClient; - mDisableFlush = true; - mBuffer.timestamp(); - gatherDeviceData(); - - for (int i = 0; i < mNumDeviceData; i++) - { - DeviceDatum *value = mDeviceData[i]; - if (value->hasInitialValue()) - sendDatum(value); - } - sendBuffer(); + mInitializeClient = client; + mDisableFlush = true; + mBuffer.timestamp(); + gatherDeviceData(); - mDisableFlush = false; - mInitializeClient = NULL; + for(auto value : mDeviceData) + { + if(value->hasInitialValue()) + sendDatum(value); + } + + sendBuffer(); + + mDisableFlush = false; + mInitializeClient = nullptr; } -/* Send the values that have changed to the clients */ + +// Send the values that have changed to the clients void Adapter::sendChangedData() { - for (int i = 0; i < mNumDeviceData; i++) - { - DeviceDatum *value = mDeviceData[i]; - if (value->changed()) - sendDatum(value); - } - sendBuffer(); + for(auto value : mDeviceData) + { + if(value->changed()) + sendDatum(value); + } + + sendBuffer(); } + void Adapter::flush() { - if (!mDisableFlush) - { - sendChangedData(); - mBuffer.reset(); - mBuffer.timestamp(); - } + if (mDisableFlush) + return; + + sendChangedData(); + mBuffer.reset(); + mBuffer.timestamp(); } + void Adapter::clientsDisconnected() { - /* Do nothing for now ... */ - gLogger->info("All clients have disconnected"); + // Do nothing for now ... + gLogger->info("All clients have disconnected"); } + void Adapter::unavailable() { - for (int i = 0; i < mNumDeviceData; i++) - { - DeviceDatum *value = mDeviceData[i]; - value->unavailable(); - } - flush(); + for(auto value : mDeviceData) + value->unavailable(); + + flush(); } + void Adapter::initializeDeviceDatum() { - for (int i = 0; i < mNumDeviceData; i++) - { - DeviceDatum *value = mDeviceData[i]; - value->initialize(); - } - flush(); + for(auto value : mDeviceData) + value->initialize(); + + flush(); } -void Adapter::addAsset(const char *aId, const char *aType, const char *aData) + +void Adapter::addAsset(const char *id, const char *type, const char *data) { - sendBuffer(); - mBuffer.timestamp(); + sendBuffer(); + mBuffer.timestamp(); + + mBuffer.append("|@ASSET@|"); + mBuffer.append(id); + mBuffer.append("|"); + mBuffer.append(type); + mBuffer.append("|--multiline--ABCD\n"); + mBuffer.append(data); + mBuffer.append("\n--multiline--ABCD"); - mBuffer.append("|@ASSET@|"); - mBuffer.append(aId); - mBuffer.append("|"); - mBuffer.append(aType); - mBuffer.append("|--multiline--ABCD\n"); - mBuffer.append(aData); - mBuffer.append("\n--multiline--ABCD"); - - sendBuffer(); - mBuffer.timestamp(); + sendBuffer(); + mBuffer.timestamp(); } -void Adapter::updateAsset(const char *aId, const char *aData) + +void Adapter::updateAsset(const char *id, const char *data) { - sendBuffer(); - mBuffer.timestamp(); + sendBuffer(); + mBuffer.timestamp(); - mBuffer.append("|@UPDATE_ASSET@|"); - mBuffer.append(aId); - mBuffer.append("|"); - mBuffer.append(aData); + mBuffer.append("|@UPDATE_ASSET@|"); + mBuffer.append(id); + mBuffer.append("|"); + mBuffer.append(data); - sendBuffer(); - mBuffer.timestamp(); + sendBuffer(); + mBuffer.timestamp(); } -void Adapter::addAsset(CuttingTool *aTool) + +void Adapter::addAsset(CuttingTool *tool) { - addAsset(aTool->getAssetId().c_str(), "CuttingTool", aTool->toString().c_str()); + addAsset(tool->getAssetId().c_str(), "CuttingTool", tool->toString().c_str()); } -void Adapter::updateAsset(CuttingTool *aTool) + +void Adapter::updateAsset(CuttingTool *tool) { - updateAsset(aTool->getAssetId().c_str(), aTool->toString().c_str()); + updateAsset(tool->getAssetId().c_str(), tool->toString().c_str()); } diff --git a/src/adapter.hpp b/src/adapter.hpp index 700a416..34c331b 100644 --- a/src/adapter.hpp +++ b/src/adapter.hpp @@ -1,163 +1,166 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef ADAPTER_HPP -#define ADAPTER_HPP - -#include "server.hpp" -#include "string_buffer.hpp" -#include "threading.hpp" - -class DeviceDatum; -class CuttingTool; - -const int INITIAL_MAX_DEVICE_DATA = 128; - -/* - * Abstract adapter that manages all the data values and writing them - * to the clients. - * - * Subclasses of this class will add the data values and interact with the - * vendor specifc API. This class provides all the common functionality. - */ -class Adapter -{ -protected: - Server *mServer; /* The socket server */ - StringBuffer mBuffer; /* A string buffer to hold the string we - * write to the streams */ - int mMaxDatum; /* The max number of device datums */ - DeviceDatum **mDeviceData; /* A 0 terminated array of data value objects */ - int mScanDelay; /* How long to sleep (in ms) between scans */ - int mNumDeviceData; /* The number of data values */ - int mPort; /* The server port we bind to */ - bool mDisableFlush; /* Used for initial data collection */ - int mHeartbeatFrequency; /* The frequency (ms) to heartbeat - * server. Responds to Ping. Default 10 sec */ - bool mRunning; - Client *mInitializeClient; /* If we are sending initial data to a client */ - -#ifdef THREADED -#ifdef WIN32 - HANDLE mServerThread; -#else - pthread_t mServerThread; -#endif -#endif - MTCMutex mGatherLock; - -protected: - void sleepMs(int aMs); - - /* Internal buffer sending methods */ - void sendBuffer(); - void sendDatum(DeviceDatum *aValue); - virtual void sendInitialData(Client *aClient); - virtual void sendChangedData(); - virtual void flush(); - void timestamp() { mBuffer.timestamp(); } - virtual void unavailable(); - virtual void initializeDeviceDatum(); - - virtual void addAsset(const char *aId, const char *aType, const char *aData); - virtual void updateAsset(const char *aId, const char *aData); - virtual void addAsset(CuttingTool *aTool); - virtual void updateAsset(CuttingTool *aTool); - -public: - Adapter(int aPort, int aScanDelay = 100); - ~Adapter(); - - void readFromClients(); - void connectToClients(); - - /* Start the server and never return */ -#ifdef THREADED - bool startServerThread(); - void serverThread(); - int waitUntilDone(); - - // allow for subclasses to do some work when threaded - virtual void periodicWork() {} -#endif - - void startServer(); - void addDatum(DeviceDatum &aValue); - - /* Stop server */ - virtual void stopServer(); - - /* Pure virtual method to get the data from the device. */ - virtual void gatherDeviceData() = 0; - virtual void begin(); - virtual void prepare(); - virtual void cleanup(); - - /* For multithreaded async gathering */ - virtual void beginGather(const char *aTs = NULL, bool aSweep = true); - virtual void completeGather(); - - /* Overload this method to handle situation when all clients disconnect */ - virtual void clientsDisconnected(); -}; - -class AutoGather { -public: - AutoGather(Adapter *anAdapter = NULL, const char *aTs = NULL, bool aSweep = true) - : mAdapter(anAdapter) { - if (mAdapter != NULL) - mAdapter->beginGather(aTs, aSweep); - } - - void begin(Adapter *anAdapter, const char *aTs = NULL, bool aSweep = true) { - mAdapter = anAdapter; - if (mAdapter != NULL) - mAdapter->beginGather(aTs, aSweep); - } - - void complete() { - if (mAdapter != NULL) - mAdapter->completeGather(); - mAdapter = NULL; - } - - ~AutoGather() { - if (mAdapter != NULL) - mAdapter->completeGather(); - } - -protected: - Adapter *mAdapter; -}; - -#endif +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include +#include +#include +#include +#include +#include "server.hpp" +#include "string_buffer.hpp" + + +class DeviceDatum; +class CuttingTool; + +constexpr size_t INITIAL_MAX_DEVICE_DATA = 128u; + +// +// Abstract adapter that manages all the data values and writing them +// to the clients. +// +// Subclasses of this class will add the data values and interact with the +// vendor specifc API. This class provides all the common functionality. +// +class Adapter +{ +protected: + std::unique_ptr mServer; // The socket server + StringBuffer mBuffer; // A string buffer to hold the string we write to the streams + std::vector mDeviceData; + std::chrono::milliseconds mScanDelay; // How long to sleep (in ms) between scans + int mPort; // The server port we bind to + bool mDisableFlush; // Used for initial data collection + std::chrono::milliseconds mHeartbeatFrequency; // The frequency (ms) to heartbeat server. Responds to Ping. Default 10 sec + bool mRunning; + Client *mInitializeClient; // If we are sending initial data to a client + +#ifdef THREADED + #ifdef WIN32 + HANDLE mServerThread; + #else + pthread_t mServerThread; + #endif +#endif + std::mutex mGatherLock; + +protected: + void sleepMs(std::chrono::milliseconds ms); + + // Internal buffer sending methods + void sendBuffer(); + void sendDatum(DeviceDatum *value); + virtual void sendInitialData(Client *client); + virtual void sendChangedData(); + virtual void flush(); + void timestamp() { mBuffer.timestamp(); } + virtual void unavailable(); + virtual void initializeDeviceDatum(); + + virtual void addAsset(const char *id, const char *type, const char *data); + virtual void updateAsset(const char *id, const char *data); + virtual void addAsset(CuttingTool *tool); + virtual void updateAsset(CuttingTool *tool); + +public: + Adapter(int port, int scanDelayMs = 100); + ~Adapter(); + + void readFromClients(); + void connectToClients(); + + // Start the server and never return +#ifdef THREADED + bool startServerThread(); + void serverThread(); + int waitUntilDone(); + + // allow for subclasses to do some work when threaded + virtual void periodicWork() {} +#endif + + void startServer(); + void addDatum(DeviceDatum &value); + + // Stop server + virtual void stopServer(); + + // Pure virtual method to get the data from the device. + virtual void gatherDeviceData() = 0; + virtual void begin(); + virtual void prepare(); + virtual void cleanup(); + + // For multithreaded async gathering + virtual void beginGather(const char *timestamp = nullptr, bool sweep = true); + virtual void completeGather(); + + // Overload this method to handle situation when all clients disconnect + virtual void clientsDisconnected(); +}; + + +class AutoGather +{ +public: + AutoGather(Adapter *adapter = nullptr, const char *timestamp = nullptr, bool sweep = true) + : mAdapter(adapter) + { + if (mAdapter) + mAdapter->beginGather(timestamp, sweep); + } + + void begin(Adapter *adapter, const char *timestamp = nullptr, bool sweep = true) + { + mAdapter = adapter; + if (mAdapter) + mAdapter->beginGather(timestamp, sweep); + } + + void complete() + { + if (mAdapter) + mAdapter->completeGather(); + mAdapter = nullptr; + } + + ~AutoGather() + { + if (mAdapter) + mAdapter->completeGather(); + } + +protected: + Adapter *mAdapter; +}; diff --git a/src/axis.hpp b/src/axis.hpp index 57dc904..6e725e7 100644 --- a/src/axis.hpp +++ b/src/axis.hpp @@ -1,92 +1,107 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef AXIS_HPP -#define AXIS_HPP - -#include "component.hpp" -#include "device_datum.hpp" -#include - -// An abstract axis type. -class Axis : public Component -{ -public: - enum Type { - LINEAR, - ROTARY - }; - - enum Units { - INCH, - MM - }; - - enum Mode { - INDEX, - SPINDLE, - CONTOUR - }; - -protected: - Sample mLoad; - int mNumber; - - Mode mMode; - Type mType; - Units mUnits; - - string mName; - -public: - Axis(Adapter *anAdapter, std::string aName, Component *aParent = NULL); - - Mode getMode() const { return mMode; } - Type getType() const { return mType; } - Units getUnits() const { return mUnits; } - const std::string &getName() { return mName; } - - virtual bool gatherData(void *aArg) = 0; -}; - -class Linear : public Axis -{ -protected: - Sample mActualPosition; - Sample mCommandedPosition; - -public: - Linear(Adapter *anAdapter, std::string aName, Component *aParent = NULL); -}; - -#endif // AXIS_HPP +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include "component.hpp" +#include "device_datum.hpp" +#include + +// An abstract axis type. +class Axis : public Component +{ +public: + enum Type + { + LINEAR, + ROTARY + }; + + enum Units + { + INCH, + MM + }; + + enum Mode + { + INDEX, + SPINDLE, + CONTOUR + }; + +protected: + Sample mLoad; + int mNumber; + + Mode mMode; + Type mType; + Units mUnits; + +public: + Axis(Adapter *adapter, const std::string &name, Component *parent = nullptr) : + Component(adapter, name, parent), + mNumber(0), + mMode(INDEX), + mType(LINEAR), + mUnits(MM) + { + } + + Mode getMode() const { + return mMode; } + Type getType() const { + return mType; } + Units getUnits() const { + return mUnits; } + + virtual void gatherData(void *context) = 0; +}; + + +class Linear : public Axis +{ +protected: + Sample mActualPosition; + Sample mCommandedPosition; + +public: + Linear(Adapter *adapter, const std::string &name, Component *parent = nullptr) : + Axis(adapter, name, parent) + { + mType = LINEAR; + } + + void gatherData(void *) override + { + } +}; diff --git a/src/client.cpp b/src/client.cpp index 8189a77..8dacabd 100755 --- a/src/client.cpp +++ b/src/client.cpp @@ -1,74 +1,78 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#include "internal.hpp" -#include "client.hpp" -#include "server.hpp" - -/* Instance methods */ -Client::Client(SOCKET aSocket) -{ - mSocket = aSocket; - mHeartbeats = false; -} - -Client::~Client() -{ - ::shutdown(mSocket, SHUT_RDWR); - ::closesocket(mSocket); -} - -int Client::write(const char *aString) -{ - int res; - MTCAutoLock lock(mWriteLock); - - try { - res = ::send(mSocket, aString, (int) strlen(aString), 0); - } - - catch(...) { - res = -1; - } - - return res; -} - -int Client::read(char *aBuffer, int aMaxLen) -{ - int len = recv(mSocket, aBuffer, aMaxLen, 0); - if (len >= 0) - aBuffer[len] = 0; - - return len; -} +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#include "internal.hpp" +#include "client.hpp" +#include "server.hpp" + + + +Client::Client(SOCKET socket) +{ + mSocket = socket; + mHeartbeats = false; +} + + +Client::~Client() +{ + ::shutdown(mSocket, SHUT_RDWR); + ::closesocket(mSocket); +} + + +int Client::write(const char *string) +{ + int res; + std::lock_guard lock(mWriteLock); + + try + { + res = ::send(mSocket, string, (int) strlen(string), 0); + } + catch(...) + { + res = -1; + } + + return res; +} + + +int Client::read(char *buffer, int maxLen) +{ + int len = recv(mSocket, buffer, maxLen, 0); + if (len >= 0) + buffer[len] = 0; + + return len; +} diff --git a/src/client.hpp b/src/client.hpp index 4217047..8d7bc7a 100755 --- a/src/client.hpp +++ b/src/client.hpp @@ -1,63 +1,64 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef CLIENT_HPP -#define CLIENT_HPP - -#include "threading.hpp" -/* - * A wrapper around a client socket. An adapter is capable of managing - * multiple sockets. - */ -class Client -{ - /* Instance Variables */ -protected: - SOCKET mSocket; - MTCMutex mWriteLock; - - /* class methods */ -public: - bool mHeartbeats; - unsigned int mLastHeartbeat; - - /* Instance methods */ -public: - Client(SOCKET aSocket); - ~Client(); - int write(const char *aString); - int read(char *aBuffer, int aLen); - SOCKET socket() { return mSocket; } -}; - -#endif +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include +#include + + +// +// A wrapper around a client socket. An adapter is capable of managing +// multiple sockets. +// +class Client +{ +// Instance Variables +protected: + SOCKET mSocket; + std::mutex mWriteLock; + +// class methods +public: + bool mHeartbeats; + std::chrono::time_point mLastHeartbeat; + +// Instance methods +public: + Client(SOCKET aSocket); + ~Client(); + + int write(const char *string); + int read(char *buffer, int len); + SOCKET socket() { + return mSocket; } +}; diff --git a/src/component.hpp b/src/component.hpp index 1f8f9f1..7a991e5 100644 --- a/src/component.hpp +++ b/src/component.hpp @@ -1,61 +1,66 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef COMPONENT_HPP -#define COMPONENT_HPP - -#include "internal.hpp" -#include - -class Adapter; - -// An abstract class representing an MTConnect Component. Subclasses -// of Component will create the most common data items and conditions -// for that component. Additional data items can be added for each -// specific implementation -class Component -{ -protected: - Adapter *mAdapter; - std::string mName; - Component *aParent; - -public: - Component(Adapter *anAdapter, std::string aName, Component *aParent = NULL); - virtual ~Component(); - virtual void initialize(); - virtual void gatherData(void *aContext) = 0; -}; - -#endif // COMPONENT_HPP - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include "internal.hpp" +#include + +class Adapter; + +// An abstract class representing an MTConnect Component. Subclasses +// of Component will create the most common data items and conditions +// for that component. Additional data items can be added for each +// specific implementation +class Component +{ +protected: + Adapter *mAdapter; + std::string mName; + Component *mParent; + +public: + Component(Adapter *adapter, const std::string &name, Component *parent = nullptr) : + mAdapter(adapter), + mName(name), + mParent(parent) + { + } + + const std::string &getName() const { + return mName; } + + virtual ~Component(){} + virtual void initialize(){} + virtual void gatherData(void *context) = 0; +}; + diff --git a/src/condition.cpp b/src/condition.cpp index dd85beb..9de3f56 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -1,320 +1,399 @@ - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// #include "internal.hpp" #include "condition.hpp" +#include #include "string_buffer.hpp" // Condition -Condition::Condition(const char *aName, bool aSimple) : - DeviceDatum(aName), mBegun(false), mSimple(aSimple) + +Condition::Condition(const char *name, bool simple) : + DeviceDatum(name), + mBegun(false), + mPrepared(false), + mSimple(simple) { - mActiveSize = mInitialActiveListSize; - mActiveCount = 0; - mActiveList = new ActiveCondition*[mActiveSize]; - mHasValue = true; - unavailable(); + mActiveList.reserve(mInitialActiveListSize); + mHasValue = true; + unavailable(); } + Condition::~Condition() { - removeAll(); - delete[] mActiveList; + removeAll(); } + void Condition::removeAll() { - for (int i = 0; i < mActiveCount; i++) - delete mActiveList[i]; - mActiveCount = 0; + for(auto condition : mActiveList) + delete condition; + mActiveList.clear(); } -bool Condition::requiresFlush() + +bool Condition::requiresFlush() const { - return true; + return true; } + bool Condition::unavailable() { - return add(eUNAVAILABLE); + return add(eUNAVAILABLE); } -char *Condition::toString(char *aBuffer, int aMaxLen) + +char *Condition::toString(char *, int ) { - return NULL; + return nullptr; } + void Condition::begin() { - if (!mSimple) { - for (int i = 0; i < mActiveCount; i++) { - mActiveList[i]->clear(); - } - } - mPrepared = false; - mBegun = true; - mChanged = false; + if (!mSimple) + { + for(auto condition : mActiveList) + condition->clear(); + } + + mPrepared = false; + mBegun = true; + mChanged = false; } + void Condition::cleanup() { - mBegun = false; - mPrepared = false; + mBegun = false; + mPrepared = false; } + void Condition::initialize() { - normal(); + normal(); } -void Condition::append(StringBuffer &aStringBuffer, char *aBuffer, - ActiveCondition *aCond, bool &aFirst, int aMaxLen) + +void Condition::append( + StringBuffer &stringBuffer, + char *buffer, + ActiveCondition *condition, + bool &first, + int maxLen) { - if (!aFirst) - aStringBuffer.newline(); - else - aFirst = false; - - char *cp = aBuffer + strlen(aBuffer); - - aCond->toString(cp, aMaxLen); - appendText(aBuffer, (char*) aCond->getText(), aMaxLen); - aStringBuffer.append(aBuffer); + if (!first) + stringBuffer.newline(); + else + first = false; + + auto cp = buffer + strlen(buffer); + condition->toString(cp, maxLen); + + appendText(buffer, const_cast(condition->getText()), maxLen); + stringBuffer.append(buffer); } + void Condition::prepare() { - if (mBegun) - { - bool marked = false; - - // Check to see if we have no marked conditions - for (int i = 0; !marked && i < mActiveCount; i++) - { - if (mActiveList[i]->isPlaceHolder() || mActiveList[i]->isMarked()) - marked = true; - } - - if (!marked) - normal(); - - // Sweep old conditions - for (int i = mActiveCount - 1; i >= 0; i--) - { - ActiveCondition *cond = mActiveList[i]; - if (!cond->isPlaceHolder() && !cond->isMarked()) - { - cond->setValue(eNORMAL, "", cond->getNativeCode()); - } - - if (cond->hasChanged()) { - mChanged = true; - } - } - mPrepared = true; - } -} + if (!mBegun) + return; -bool Condition::append(StringBuffer &aBuffer) -{ - if (!mBegun) - { - char buffer[1024]; - bool first = true; - buffer[0] = '|'; - strcpy(buffer + 1, mName); - char *cp = buffer + strlen(buffer); - int max = 1024 - strlen(buffer); - for (int i = 0; i < mActiveCount; i++) - { - *cp = '\0'; - append(aBuffer, buffer, mActiveList[i], first, max); - } - } else if (mBegun && mPrepared) { - char buffer[1024]; - bool first = true; - buffer[0] = '|'; - strcpy(buffer + 1, mName); - char *cp = buffer + strlen(buffer); - int max = 1024 - strlen(buffer); - - // Sweep old conditions - for (int i = mActiveCount - 1; i >= 0; i--) - { - ActiveCondition *cond = mActiveList[i]; - if (cond->hasChanged()) { - *cp = '\0'; - append(aBuffer, buffer, cond, first, max); - } - - // Remove stale conditions since they have now been generated. - if (!cond->isPlaceHolder() && !cond->isMarked()) - removeAt(i); - } - } - - return mChanged; + bool marked = false; + + // Check to see if we have no marked conditions + for(auto condition : mActiveList) + { + if (condition->isPlaceHolder() || condition->isMarked()) + { + marked = true; + break; + } + } + + if (!marked) + normal(); + + // Sweep old conditions + for(auto conditionIter = mActiveList.crbegin();conditionIter != mActiveList.crend(); conditionIter++) + { + auto condition = *conditionIter; + if (!condition->isPlaceHolder() && !condition->isMarked()) + condition->setValue(eNORMAL, "", condition->getNativeCode()); + + if (condition->hasChanged()) + mChanged = true; + } + + mPrepared = true; } -bool Condition::isActive(const char *aNativeCode) + +bool Condition::append(StringBuffer &stringBuffer) { - for (int i = 0; i < mActiveCount; i++) { - if (strcmp(aNativeCode, mActiveList[i]->getNativeCode()) == 0) - return true; - } + if (!mBegun) + { + char buffer[1024] = {0}; + bool first = true; + buffer[0] = '|'; + strcpy(buffer + 1, mName); + auto cp = buffer + strlen(buffer); + auto max = 1024u - strlen(buffer); + + for(auto condition : mActiveList) + { + *cp = '\0'; + append(stringBuffer, buffer, condition, first, max); + } + } + else if (mBegun && mPrepared) + { + char buffer[1024] {0}; + bool first = true; + buffer[0] = '|'; + strcpy(buffer + 1, mName); + auto cp = buffer + strlen(buffer); + auto max = 1024u - strlen(buffer); + + // Sweep old conditions + // Update any that have changed + for(auto conditionIter = mActiveList.crbegin(); conditionIter != mActiveList.crend(); conditionIter++) + { + auto condition = *conditionIter; + if(condition->hasChanged()) + { + *cp = '\0'; + append(stringBuffer, buffer, condition, first, max); + } + } + + // Update our container to move items to be deleted to the end + auto removeRange = std::remove_if(mActiveList.begin(), mActiveList.end(), [](ActiveCondition *condition) + { + if( !condition->isPlaceHolder() && !condition->isMarked() ) + { + delete condition; condition = nullptr; + return true; + } + else + return false; + }); + + // Remove items from the container if required + if(removeRange != mActiveList.end()) + mActiveList.erase(removeRange); + } - return false; + return mChanged; } -bool Condition::add(ELevels aLevel, const char *aText, const char *aCode, - const char *aQualifier, const char *aSeverity) + +bool Condition::isActive(const char *nativeCode) const { - ActiveCondition *cond = NULL; - bool res; - // First check for a unassociated normal or a unavailable. - if ((aLevel == eNORMAL || aLevel == eUNAVAILABLE) && - aCode[0] == '\0') - { - // See if we are already in this state. - if (mActiveCount == 1 && mActiveList[0]->getNativeCode()[0] == '\0' && - mActiveList[0]->getLevel() == aLevel) - { - mActiveList[0]->mark(); - res = false; - } - else - { - // Clear all existing conditions and add one with this state. - removeAll(); - cond = new ActiveCondition(aLevel); - add(cond); - res = mChanged = true; - } - } - else - { - if (mActiveCount == 1 && - (mActiveList[0]->getLevel() == eNORMAL || - mActiveList[0]->getLevel() == eUNAVAILABLE)) - { - removeAll(); - } - - // We have a code specific condition or a ab-normal - int i; - for (i = 0; i < mActiveCount; i++) - if (strcmp(aCode, mActiveList[i]->getNativeCode()) == 0) - break; - - if (i < mActiveCount) - { - res = mChanged = mActiveList[i]->setValue(aLevel, aText, aCode, aQualifier, aSeverity); - mActiveList[i]->mark(); - } - else - { - // New condition - cond = new ActiveCondition(aLevel, aText, aCode, aQualifier, aSeverity); - add(cond); - res = mChanged = true; - } - } - - return res; + auto findPos = std::find_if(mActiveList.cbegin(), mActiveList.cend(), [nativeCode](const ActiveCondition *condition) + { + return !strcmp(nativeCode, condition->getNativeCode()); + }); + + return findPos != mActiveList.cend(); } -void Condition::remove(const char *aCode) + +bool Condition::add( + ELevels level, + const char *text, + const char *code, + const char *qualifier, + const char *severity) { - // We have a code specific condition or a ab-normal - int i; - for (i = 0; i < mActiveCount; i++) { - if (strcmp(aCode, mActiveList[i]->getNativeCode()) == 0) { - if (mActiveCount == 1) - normal(); - else { - mActiveList[i]->setValue(eNORMAL, "", aCode); - mActiveList[i]->clear(); - } - mChanged = true; - break; - } - } + bool res(false); + + // First check for a unassociated normal or a unavailable. + if ((level == eNORMAL || level == eUNAVAILABLE) && + code[0] == '\0') + { + // See if we are already in this state. + if (mActiveList.size() == 1u && + mActiveList[0]->getNativeCode()[0] == '\0' && + mActiveList[0]->getLevel() == level) + { + mActiveList[0]->mark(); + res = false; + } + else + { + // Clear all existing conditions and add one with this state. + removeAll(); + add( new ActiveCondition(level) ); + res = mChanged = true; + } + } + else + { + if (mActiveList.size() == 1u && + (mActiveList[0]->getLevel() == eNORMAL || + mActiveList[0]->getLevel() == eUNAVAILABLE)) + { + removeAll(); + } + + // We have a code specific condition or a ab-normal + auto conditionPos = std::find_if(mActiveList.cbegin(), mActiveList.cend(), [code](ActiveCondition* condition) + { + return !strcmp(code, condition->getNativeCode()); + }); + + if(conditionPos != mActiveList.cend()) + { + auto condition = *conditionPos; + res = mChanged = condition->setValue(level, text, code, qualifier, severity); + condition->mark(); + } + else + { + // New condition + add( new ActiveCondition(level, text, code, qualifier, severity) ); + res = mChanged = true; + } + } + + return res; } -void Condition::add(ActiveCondition *aCond) +void Condition::remove(const char *code) { - if (mActiveCount >= mActiveSize) - { - ActiveCondition **newList = new ActiveCondition*[mActiveSize * 2]; - memcpy(newList, mActiveList, sizeof(ActiveCondition*) * mActiveSize); - delete mActiveList; - mActiveList = newList; - mActiveSize *= 2; - } - - mActiveList[mActiveCount++] = aCond; + // We have a code specific condition or a ab-normal + auto conditionPos = std::find_if(mActiveList.cbegin(), mActiveList.cend(), [code](ActiveCondition* condition) + { + return !strcmp(code, condition->getNativeCode()); + }); + + if(conditionPos != mActiveList.cend()) + { + if(mActiveList.size() == 1u) + normal(); + else + { + (*conditionPos)->setValue(eNORMAL, "", code); + (*conditionPos)->clear(); + } + } } -bool Condition::removeAt(int i) + +void Condition::add(ActiveCondition *condition) { - if (i < 0 || i >= mActiveCount) - return false; - - delete mActiveList[i]; - mActiveCount--; - memmove(mActiveList + i, mActiveList + i + 1, - sizeof(ActiveCondition*) * (mActiveCount - i)); - - return true; + // If we are approaching our capacity then resize + if(mActiveList.size() == mActiveList.capacity()) + mActiveList.reserve(mActiveList.capacity() * 2u); + + mActiveList.push_back(condition); } -char *Condition::ActiveCondition::toString(char *aBuffer, int aMaxLen) + +char *Condition::ActiveCondition::toString(char *buffer, int aMaxLen) { - const char *text; - switch(mLevel) - { - case eUNAVAILABLE: text = "UNAVAILABLE"; break; - case eNORMAL: text = "NORMAL"; break; - case eWARNING: text = "WARNING"; break; - case eFAULT: text = "FAULT"; break; - default: text = ""; break; - } - snprintf(aBuffer, aMaxLen, "|%s|%s|%s|%s|", text, mNativeCode, mNativeSeverity, - mQualifier); - - mChanged = false; - return aBuffer; + const char *text = nullptr; + + switch (mLevel) + { + case eUNAVAILABLE: + text = "UNAVAILABLE"; + break; + + case eNORMAL: + text = "NORMAL"; + break; + + case eWARNING: + text = "WARNING"; + break; + + case eFAULT: + text = "FAULT"; + break; + + default: + text = ""; + break; + } + + snprintf(buffer, aMaxLen, "|%s|%s|%s|%s|", text, mNativeCode, mNativeSeverity, mQualifier); + + mChanged = false; + return buffer; } -bool Condition::ActiveCondition::setValue(ELevels aLevel, const char *aText, const char *aCode, - const char *aQualifier, const char *aSeverity) + +bool Condition::ActiveCondition::setValue( + ELevels level, + const char *text, + const char *code, + const char *qualifier, + const char *severity) { - if ((aLevel == eNORMAL || aLevel == eUNAVAILABLE) && aCode[0] == '\0') - mPlaceHolder = true; - - if (mLevel != aLevel || - strncmp(aCode, mNativeCode, EVENT_VALUE_LEN) != 0 || - strncmp(aQualifier, mQualifier, EVENT_VALUE_LEN) != 0 || - strncmp(aSeverity, mNativeSeverity, EVENT_VALUE_LEN) != 0 || - strncmp(aText, mText, EVENT_VALUE_LEN) != 0) - { - mLevel = aLevel; - - strncpy(mNativeCode, aCode, EVENT_VALUE_LEN); - mNativeCode[EVENT_VALUE_LEN - 1] = '\0'; - - strncpy(mQualifier, aQualifier, EVENT_VALUE_LEN); - mQualifier[EVENT_VALUE_LEN - 1] = '\0'; - - strncpy(mNativeSeverity, aSeverity, EVENT_VALUE_LEN); - mNativeSeverity[EVENT_VALUE_LEN - 1] = '\0'; - - strncpy(mText, aText, EVENT_VALUE_LEN); - mText[EVENT_VALUE_LEN - 1] = '\0'; - - mChanged = true; - } - - return mChanged; + if ((level == eNORMAL || level == eUNAVAILABLE) && code[0] == '\0') + mPlaceHolder = true; + + if (mLevel != level || + strncmp(code, mNativeCode, EVENT_VALUE_LEN) || + strncmp(qualifier, mQualifier, EVENT_VALUE_LEN) || + strncmp(severity, mNativeSeverity, EVENT_VALUE_LEN) || + strncmp(text, mText, EVENT_VALUE_LEN)) + { + mLevel = level; + + strncpy(mNativeCode, code, EVENT_VALUE_LEN); + mNativeCode[EVENT_VALUE_LEN - 1] = '\0'; + + strncpy(mQualifier, qualifier, EVENT_VALUE_LEN); + mQualifier[EVENT_VALUE_LEN - 1] = '\0'; + + strncpy(mNativeSeverity, severity, EVENT_VALUE_LEN); + mNativeSeverity[EVENT_VALUE_LEN - 1] = '\0'; + + strncpy(mText, text, EVENT_VALUE_LEN); + mText[EVENT_VALUE_LEN - 1] = '\0'; + + mChanged = true; + } + + return mChanged; } diff --git a/src/condition.hpp b/src/condition.hpp index 04faa4d..b56db6e 100644 --- a/src/condition.hpp +++ b/src/condition.hpp @@ -1,135 +1,180 @@ -/* - * Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the AMT nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED - * BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" - * AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR - * RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS - * (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR - * WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT - * LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, - * MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - - * LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT - * PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS - * OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, - * CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, - * WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF - * THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT - * SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef CONDITION_LIST -#define CONDITION_LIST - -// The conditon items -#include "device_datum.hpp" - - -class Condition : public DeviceDatum -{ -public: - enum ELevels { - eUNAVAILABLE, - eNORMAL, - eWARNING, - eFAULT - }; - -protected: - class ActiveCondition - { - protected: - ELevels mLevel; - char mText[EVENT_VALUE_LEN]; - char mNativeCode[EVENT_VALUE_LEN]; - char mNativeSeverity[EVENT_VALUE_LEN]; - char mQualifier[EVENT_VALUE_LEN]; - - bool mChanged; - bool mMarked; - bool mPlaceHolder; - - public: - ActiveCondition() : mChanged(true), mMarked(true), mPlaceHolder(false) { - mNativeCode[0] = mNativeSeverity[0] = mText[0] = - mQualifier[0] = 0; - } - ActiveCondition(ELevels aLevel, const char *aText = "", const char *aCode = "", - const char *aQualifier = "", const char *aSeverity = "") - : mChanged(true), mMarked(true), mPlaceHolder(false) - { - setValue(aLevel, aText, aCode, aQualifier, aSeverity); - } - - bool setValue(ELevels aLevel, const char *aText = "", const char *aCode = "", - const char *aQualifier = "", const char *aSeverity = ""); - - char *toString(char *aBuffer, int aMaxLen); - bool hasChanged() { return mChanged; } - - ELevels getLevel() { return mLevel; } - const char *getText() { return mText; } - const char *getNativeCode() { return mNativeCode; } - const char *getNativeSeverity() { return mNativeSeverity; } - const char *getQualifier() { return mQualifier; } - - void clear() { mMarked = false; } - void mark() { mMarked = true; } - bool isMarked() { return mMarked; } - bool isPlaceHolder() { return mPlaceHolder; } - }; - -protected: - ActiveCondition **mActiveList; - int mActiveSize; - int mActiveCount; - static const int mInitialActiveListSize = 16; - - bool mBegun; - bool mPrepared; - bool mSimple; - - void add(ActiveCondition *aCondition); - bool removeAt(int i); - - void append(StringBuffer &aStringBuffer, char *aBuffer, ActiveCondition *aCond, - bool &aFirst, int aMaxLen); - -public: - Condition(const char *aName = "", bool aSimple = false); - virtual ~Condition(); - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool requiresFlush(); - virtual bool unavailable(); - virtual bool append(StringBuffer &aBuffer); - - bool add(ELevels aLevel, const char *aText = "", const char *aCode = "", - const char *aQualifier = "", const char *aSeverity = ""); - void remove(const char *aCode); - - void removeAll(); - bool normal() { return add(eNORMAL); } - bool isActive(const char *aNativeCode); - void setSimple() { mSimple = true; } - - virtual void begin(); - virtual void prepare(); - virtual void cleanup(); - virtual void initialize(); -}; - -#endif +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include + +// The conditon items +#include "device_datum.hpp" + + +class Condition : public DeviceDatum +{ +public: + enum ELevels + { + eUNAVAILABLE, + eNORMAL, + eWARNING, + eFAULT + }; + +protected: + class ActiveCondition + { + protected: + ELevels mLevel; + char mText[EVENT_VALUE_LEN]; + char mNativeCode[EVENT_VALUE_LEN]; + char mNativeSeverity[EVENT_VALUE_LEN]; + char mQualifier[EVENT_VALUE_LEN]; + + bool mChanged; + bool mMarked; + bool mPlaceHolder; + + public: + ActiveCondition() : + mLevel(eUNAVAILABLE), + mText{0}, + mNativeCode{0}, + mNativeSeverity{0}, + mQualifier{0}, + mChanged(true), + mMarked(true), + mPlaceHolder(false) + { + } + + ActiveCondition( + ELevels level, + const char *text = "", + const char *code = "", + const char *qualifier = "", + const char *severity = "") + : + mText{0}, + mNativeCode{0}, + mNativeSeverity{0}, + mQualifier{0}, + mChanged(true), + mMarked(true), + mPlaceHolder(false) + { + setValue(level, text, code, qualifier, severity); + } + + ~ActiveCondition() + { + } + + bool setValue( + ELevels level, + const char *text = "", + const char *code = "", + const char *qualifier = "", + const char *severity = ""); + + char *toString(char *bBuffer, int maxLen); + bool hasChanged() const { + return mChanged; } + + ELevels getLevel() const { + return mLevel; } + const char *getText() const { + return mText; } + const char *getNativeCode() const { + return mNativeCode; } + const char *getNativeSeverity() const { + return mNativeSeverity; } + const char *getQualifier() const { + return mQualifier; } + + void clear() { + mMarked = false; } + void mark() { + mMarked = true; } + bool isMarked() const { + return mMarked; } + bool isPlaceHolder() const { + return mPlaceHolder; } + }; + +protected: + std::vector mActiveList; + static const int mInitialActiveListSize = 16; + + bool mBegun; + bool mPrepared; + bool mSimple; + + void add(ActiveCondition *condition); + + static void append( + StringBuffer &stringBuffer, + char *buffer, + ActiveCondition *cond, + bool &first, + int maxLen); + +public: + Condition(const char *name = "", bool simple = false); + virtual ~Condition(); + + bool add( + ELevels level, + const char *text = "", + const char *code = "", + const char *qualifier = "", + const char *severity = ""); + void remove(const char *code); + + void removeAll(); + bool normal() { + return add(eNORMAL); } + bool isActive(const char *nativeCode) const; + void setSimple() { + mSimple = true; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool requiresFlush() const override; + bool unavailable() override; + bool append(StringBuffer &buffer) override; + void begin() override; + void prepare() override; + void cleanup() override; + void initialize() override; +}; + diff --git a/src/configuration.cpp b/src/configuration.cpp index 182791a..f3116ad 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -1,81 +1,113 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#include "configuration.hpp" -#include "yaml.h" - -using namespace std; - -Configuration::Configuration() - : mPort(7878), mScanDelay(1000), mTimeout(10000) -{ -} - -void Configuration::parse(istream &aStream, int aPort, int aDelay, int aTimeout, const char *aService) -{ - YAML::Parser parser(aStream); - YAML::Node doc; - parser.GetNextDocument(doc); - parse(doc, aPort, aDelay, aTimeout, aService); -} - -void Configuration::parse(YAML::Node &aDoc, int aPort, int aDelay, int aTimeout, const char *aService) -{ - if (aDoc.FindValue("adapter") != NULL) - { - const YAML::Node &adapter = aDoc["adapter"]; - SET_WITH_DEFAULT(adapter, "port", mPort, aPort); - SET_WITH_DEFAULT(adapter, "scanDelay", mScanDelay, aDelay); - SET_WITH_DEFAULT(adapter, "timeout", mTimeout, aTimeout); - SET_WITH_DEFAULT(adapter, "service", mServiceName, aService); - } - else - { - mPort = aPort; - mScanDelay = aDelay; - mTimeout = aTimeout; - mServiceName = aService; - } -} - -Configuration::~Configuration() -{ -} - -RegisterSet *Configuration::getRegisters(string &aName) -{ - return mRegisters[aName]; -} - - - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#include "configuration.hpp" +#include "yaml.h" + +using namespace std; + +template +void set_with_default(const YAML::Node &node, const char *key, T& value, V def) +{ + if (node.FindValue(key) != nullptr) + node[key] >> value; + else + value = def; +} + +template +void set_if_present(const YAML::Node &node, const char *key, T& value) +{ + if (node.FindValue(key) != nullptr) + node[key] >> value; +} + + +Configuration::Configuration() : + mPort(7878), + mScanDelay(1000), + mTimeout(10000) +{ +} + + +Configuration::~Configuration() +{ +} + + +void Configuration::parse( + istream &stream, + int port, + int delay, + int timeout, + const char *service) +{ + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + parse(doc, port, delay, timeout, service); +} + + +void Configuration::parse( + YAML::Node &doc, + int port, + int delay, + int timeout, + const char *service) +{ + if (doc.FindValue("adapter")) + { + const YAML::Node &adapter = doc["adapter"]; + set_with_default(adapter, "port", mPort, port); + set_with_default(adapter, "scanDelay", mScanDelay, delay); + set_with_default(adapter, "timeout", mTimeout, timeout); + set_with_default(adapter, "service", mServiceName, service); + } + else + { + mPort = port; + mScanDelay = delay; + mTimeout = timeout; + mServiceName = service; + } +} + + +RegisterSet *Configuration::getRegisters(string &aName) const +{ + auto regPos = mRegisters.find(aName); + if(regPos != mRegisters.cend()) + return regPos->second; + return nullptr; +} diff --git a/src/configuration.hpp b/src/configuration.hpp index 579c417..23fb816 100644 --- a/src/configuration.hpp +++ b/src/configuration.hpp @@ -1,144 +1,158 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef CONFIGURATION_HPP -#define CONFIGURATION_HPP - -#include -#include -#include -#include - -class DeviceDatum; -namespace YAML { - class Parser; - class Node; -} - -#define SET_WITH_DEFAULT(node, key, value, def) \ - if (node.FindValue(key) != NULL) \ - node[key] >> value; \ - else \ - value = def - -#define SET_IF_PRESENT(node, key, value) \ - if (node.FindValue(key) != NULL) \ - node[key] >> value; - -// A register represents a PLC/PMC register as an accessible unit. The -// value of the register will manifest as a typed value or a -// conditional that will map to an event and be represented by a -// state. -class Register -{ -public: - enum EType - { - FLOAT_64, - FLOAT_32, - INTEGER_32, - INTEGER_16, - INTEGER_8, - BOOL, - BIT, - CONDITION, - TEXT - }; - - Register(EType aType, int aOffset, bool aTimeSeries = false) { - mType = aType; - mOffset = aOffset; - mTimeseries = aTimeSeries; - } - ~Register(); - - Register(Register &aRegister) { - mType = aRegister.mType; - mOffset = aRegister.mOffset; - mTimeseries = aRegister.mTimeseries; - } - -protected: - EType mType; - int mOffset; - bool mTimeseries; - double mScaler; - int mScalerOffset; - int mCount; - - DeviceDatum *mDatum; -}; - -class RegisterSet -{ - void addRegister(Register &aRegister) { mRegisters.push_back(&aRegister); } - -protected: - int mAddress; - int mLength; - int mCount; - - std::vector mRegisters; -}; - -class Configuration -{ -public: - Configuration(); - virtual ~Configuration(); - - virtual void parse(std::istream &aStream, int aPort = 7878, int aDelay = 1000, - int aTimeout = 10000, const char *aService = "MTConnect Adapter"); - - int getPort() const { return mPort; } - int getScanDelay() const { return mScanDelay; } - int getTimeout() const { return mTimeout; } - const std::string &getServiceName() const { return mServiceName; } - - void setPort(int aPort) { mPort = aPort; } - - RegisterSet *getRegisters(std::string &aName); - -protected: - virtual void parse(YAML::Node &aDoc, int aPort, int aDelay, int aTimeout, const char *aService); - -protected: - int mPort; - int mScanDelay; - int mTimeout; - std::string mServiceName; - - std::map mRegisters; -}; - -#endif +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once +#include +#include +#include +#include + +// Forward Declarations +class DeviceDatum; +namespace YAML +{ + class Parser; + class Node; +} + + +// A register represents a PLC/PMC register as an accessible unit. The +// value of the register will manifest as a typed value or a +// conditional that will map to an event and be represented by a +// state. +class Register +{ +public: + enum EType + { + FLOAT_64, + FLOAT_32, + INTEGER_32, + INTEGER_16, + INTEGER_8, + BOOL, + BIT, + CONDITION, + TEXT + }; + + Register(EType type, int offset, bool timeSeries = false) : + mType(type), + mOffset(offset), + mTimeseries(timeSeries), + mScaler(0.0), + mScalerOffset(0), + mCount(0), + mDatum(nullptr) + { + } + + Register(Register &anotherRegister) : + mType(anotherRegister.mType), + mOffset(anotherRegister.mOffset), + mTimeseries(anotherRegister.mTimeseries), + mScaler(0.0), + mScalerOffset(0), + mCount(0), + mDatum(nullptr) + { + } + +protected: + EType mType; + int mOffset; + bool mTimeseries; + double mScaler; + int mScalerOffset; + int mCount; + + DeviceDatum *mDatum; +}; + + +class RegisterSet +{ + void addRegister(Register &newRegister) { + mRegisters.push_back(&newRegister); } + +protected: + int mAddress; + int mLength; + int mCount; + + std::vector mRegisters; +}; + + +class Configuration +{ +public: + Configuration(); + virtual ~Configuration(); + + virtual void parse( + std::istream &stream, + int port = 7878, + int delay = 1000, + int timeout = 10000, + const char *service = "MTConnect Adapter"); + + int getPort() const { + return mPort; } + int getScanDelay() const { + return mScanDelay; } + int getTimeout() const { + return mTimeout; } + const std::string &getServiceName() const { + return mServiceName; } + + void setPort(int aPort) { + mPort = aPort; } + + RegisterSet *getRegisters(std::string &name) const; + +protected: + virtual void parse( + YAML::Node &aDoc, + int aPort, + int aDelay, + int aTimeout, + const char *aService); + +protected: + int mPort; + int mScanDelay; + int mTimeout; + std::string mServiceName; + std::map mRegisters; +}; + diff --git a/src/cutting_tool.cpp b/src/cutting_tool.cpp index 7f6ebdf..bebc908 100644 --- a/src/cutting_tool.cpp +++ b/src/cutting_tool.cpp @@ -1,132 +1,195 @@ - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// #include "internal.hpp" #include "cutting_tool.hpp" #include using namespace std; -string encodeForXml( const string &aSrc ) +string encodeForXml(const string &source) { - ostringstream ret; - - for( string::const_iterator iter = aSrc.begin(); iter != aSrc.end(); iter++ ) - { - unsigned char c = (unsigned char)*iter; - - switch( c ) - { - case '&': ret << "&"; break; - case '<': ret << "<"; break; - case '>': ret << ">"; break; - case '"': ret << """; break; - case '\'': ret << "'"; break; - - default: - if ( c<32 || c>127 ) - { - ret << "&#" << (unsigned int)c << ";"; - } - else - { - ret << c; - } - } - } - - return ret.str(); + ostringstream ret; + + for (auto iter = source.cbegin(); iter != source.cend(); iter++) + { + unsigned char c = (unsigned char) * iter; + + switch (c) + { + case '&': + ret << "&"; + break; + + case '<': + ret << "<"; + break; + + case '>': + ret << ">"; + break; + + case '"': + ret << """; + break; + + case '\'': + ret << "'"; + break; + + default: + if (c < 32 || c > 127) + ret << "&#" << (unsigned int)c << ";"; + else + ret << c; + } + } + + return ret.str(); } -std::string CuttingToolProperty::toXML() + +std::string CuttingToolProperty::toXML() const { - ostringstream xml; - xml << '<' << mName; - - map::iterator iter; - for (iter = mAttributes.begin(); iter != mAttributes.end(); iter++) { - xml << ' ' << iter->first << "=\"" << encodeForXml(iter->second) << '"'; - } - if (!mValue.empty()) { - xml << '>' << encodeForXml(mValue) << "'; - - return xml.str(); + ostringstream xml; + xml << '<' << mName; + + for(auto const &mapPair : mAttributes) + xml << ' ' << mapPair.first << "=\"" << encodeForXml(mapPair.second) << '"'; + + if (!mValue.empty()) + xml << '>' << encodeForXml(mValue) << "'; + return xml.str(); } -std::string CuttingToolStatus::toXML() + +std::string CuttingToolStatus::toXML() const { - ostringstream xml; - xml << '<' << mName << '>'; - vector::iterator iter; - for (iter = mStatus.begin(); iter != mStatus.end(); iter++) { - xml << "" << *iter << ""; - } - - xml << "'; - - return xml.str(); + ostringstream xml; + xml << '<' << mName << '>'; + + for (auto const &status : mStatus) + xml << "" << status << ""; + + xml << "'; + + return xml.str(); } -static char *doubleToString(double aDouble, char *aBuffer) + +static char *doubleToString(double value, char *buffer) { - sprintf(aBuffer, "%.10g", aDouble); - return aBuffer; + sprintf(buffer, "%.10g", value); + return buffer; } -CuttingToolMeasurement::CuttingToolMeasurement(std::string aName, std::string aCode, - double aValue, double aNominal, double aMin, double aMax, - std::string aNativeUnits, std::string aUnits) - : CuttingToolProperty(aName) + +CuttingToolMeasurement::CuttingToolMeasurement( + std::string name, + std::string code, + double value, + double nominal, + double min, + double max, + std::string nativeUnits, + std::string units) + : + CuttingToolProperty(name) { - char buffer[80]; - mAttributes["code"] = aCode; - - if (aNominal != CT_NO_VALUE) mAttributes["nominal"] = doubleToString(aNominal, buffer); - if (aMin != CT_NO_VALUE) mAttributes["minimum"] = doubleToString(aMin, buffer); - if (aMax != CT_NO_VALUE) mAttributes["maximum"] = doubleToString(aMax, buffer); - if (!aNativeUnits.empty()) mAttributes["nativeUnits"] = aNativeUnits; - if (!aNativeUnits.empty()) mAttributes["units"] = aUnits; - - if (aValue != CT_NO_VALUE) mValue = doubleToString(aValue, buffer); + char buffer[80]; + mAttributes["code"] = code; + + if (nominal != CT_NO_VALUE) + mAttributes["nominal"] = doubleToString(nominal, buffer); + + if (min != CT_NO_VALUE) + mAttributes["minimum"] = doubleToString(min, buffer); + + if (max != CT_NO_VALUE) + mAttributes["maximum"] = doubleToString(max, buffer); + + if (!nativeUnits.empty()) + mAttributes["nativeUnits"] = nativeUnits; + + if (!units.empty()) + mAttributes["units"] = units; + + if (value != CT_NO_VALUE) + mValue = doubleToString(value, buffer); } -CuttingTool::CuttingTool(std::string &aAssetId, int aToolNumber, std::string &aDescription, CuttingToolStatus &aStatus) - : mAssetId(encodeForXml(aAssetId)), mToolNumber(aToolNumber), mDescription(encodeForXml(aDescription)), - mStatus(aStatus) + +CuttingTool::CuttingTool( + std::string &assetId, + int toolNumber, + std::string &description, + CuttingToolStatus &status) + : + mAssetId(encodeForXml(assetId)), + mToolNumber(toolNumber), + mDescription(encodeForXml(description)), + mStatus(status) { } + string CuttingTool::toString() { - // Agent takes care of reordering the properties, so we can cheat... - std::ostringstream xml; - - // Open tag... - xml << ""; - xml << "" << mDescription << ""; - xml << ""; - - // Properties - vector::iterator prop; - for (prop = mProperties.begin(); prop != mProperties.end(); prop++) { - xml << prop->toXML(); - } - - xml << ""; - - vector::iterator measure; - for (measure = mMeasurements.begin(); measure != mMeasurements.end(); measure++) { - xml << measure->toXML(); - } - - xml << ""; - - // Items... - xml << ""; - - return xml.str(); + // Agent takes care of reordering the properties, so we can cheat... + std::ostringstream xml; + + // Open tag... + xml << ""; + xml << "" << mDescription << ""; + xml << ""; + + // Properties + for (auto const &prop : mProperties) + xml << prop.toXML(); + + xml << ""; + for (auto const &measure : mMeasurements) + xml << measure.toXML(); + xml << ""; + + // Items... + xml << ""; + + return xml.str(); } \ No newline at end of file diff --git a/src/cutting_tool.hpp b/src/cutting_tool.hpp index 08c13c4..3d0fbb0 100644 --- a/src/cutting_tool.hpp +++ b/src/cutting_tool.hpp @@ -1,92 +1,158 @@ - -#ifndef CUTTING_TOOL_HPP -#define CUTTING_TOOL_HPP - -#include -#include -#include -#include - -class CuttingToolProperty { -public: - CuttingToolProperty(const std::string &aName, std::map &aAttributes, const std::string &aValue) - : mName(aName), mAttributes(aAttributes), mValue(aValue) - {} - - CuttingToolProperty(std::string aName) - : mName(aName) - {} - - CuttingToolProperty(const CuttingToolProperty &aProp) - : mName(aProp.mName), mAttributes(aProp.mAttributes), mValue(aProp.mValue) - {} - - virtual std::string toXML(); - -public: - std::string mName; - std::map mAttributes; - std::string mValue; -}; - -class CuttingToolStatus : public CuttingToolProperty { -public: - CuttingToolStatus(std::vector &aStatus) - : CuttingToolProperty("CutterStatus"), mStatus(aStatus) - { } - - CuttingToolStatus(const CuttingToolStatus &aStatus) - : CuttingToolProperty(aStatus), mStatus(aStatus.mStatus) - {} - - virtual std::string toXML(); - -public: - std::vector mStatus; -}; - -static const double CT_NO_VALUE = DBL_MAX; - -class CuttingToolMeasurement : public CuttingToolProperty { -public: - CuttingToolMeasurement(std::string aName, std::string aCode, double aValue, double aNominal = CT_NO_VALUE, - double aMin = CT_NO_VALUE, double aMax = CT_NO_VALUE, - std::string aNativeUnits = "", - std::string aUnits = ""); - - CuttingToolMeasurement(const CuttingToolMeasurement &aMeasure) - : CuttingToolProperty(aMeasure) - {} -}; - -class CuttingItem { -public: - std::vector mProperties; - std::vector mMeasurements; -}; - -class CuttingTool { -public: - CuttingTool(std::string &aAssetId, int aToolNumber, std::string &aDescription, - CuttingToolStatus &aStatus); - - void add(CuttingToolProperty &aProp) { mProperties.push_back(aProp); } - void add(CuttingToolMeasurement &aProp) { mMeasurements.push_back(aProp); } - - virtual std::string toString(); - - const std::string &getAssetId() const { return mAssetId; } - int getToolNumber() const { return mToolNumber; } - - bool isValid() const { return !mAssetId.empty(); } - -protected: - CuttingToolStatus mStatus; - std::vector mProperties; - std::vector mMeasurements; - std::string mAssetId; - int mToolNumber; - std::string mDescription; -}; - -#endif \ No newline at end of file +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once +#include +#include +#include +#include + + +class CuttingToolProperty +{ +public: + CuttingToolProperty( + const std::string &aName, + std::map &aAttributes, + const std::string &aValue) + : + mName(aName), + mAttributes(aAttributes), + mValue(aValue) + { + } + + CuttingToolProperty(std::string aName) : + mName(aName) + { + } + + CuttingToolProperty(const CuttingToolProperty &aProp) : + mName(aProp.mName), + mAttributes(aProp.mAttributes), + mValue(aProp.mValue) + { + } + + virtual std::string toXML() const; + +public: + std::string mName; + std::map mAttributes; + std::string mValue; +}; + + +class CuttingToolStatus : public CuttingToolProperty +{ +public: + CuttingToolStatus(std::vector &status) : + CuttingToolProperty("CutterStatus"), + mStatus(status) + { + } + + CuttingToolStatus(const CuttingToolStatus &status) : + CuttingToolProperty(status), + mStatus(status.mStatus) + { + } + + std::string toXML() const override; + +public: + std::vector mStatus; +}; + + +static const double CT_NO_VALUE = DBL_MAX; + + +class CuttingToolMeasurement : public CuttingToolProperty +{ +public: + CuttingToolMeasurement( + std::string name, + std::string code, + double value, + double nominal = CT_NO_VALUE, + double min = CT_NO_VALUE, + double max = CT_NO_VALUE, + std::string nativeUnits = "", + std::string units = ""); + + CuttingToolMeasurement(const CuttingToolMeasurement &measurement) : + CuttingToolProperty(measurement) + { + } +}; + + +class CuttingItem +{ +public: + std::vector mProperties; + std::vector mMeasurements; +}; + + +class CuttingTool +{ +public: + CuttingTool( + std::string &aAssetId, + int aToolNumber, + std::string &aDescription, + CuttingToolStatus &status); + + void add(CuttingToolProperty &aProp) { + mProperties.push_back(aProp); } + void add(CuttingToolMeasurement &aProp) { + mMeasurements.push_back(aProp); } + + virtual std::string toString(); + + const std::string &getAssetId() const { + return mAssetId; } + int getToolNumber() const { return mToolNumber; } + + bool isValid() const { + return !mAssetId.empty(); } + +protected: + CuttingToolStatus mStatus; + std::vector mProperties; + std::vector mMeasurements; + std::string mAssetId; + int mToolNumber; + std::string mDescription; +}; diff --git a/src/device_datum.cpp b/src/device_datum.cpp index 6e6c6be..74ea9af 100755 --- a/src/device_datum.cpp +++ b/src/device_datum.cpp @@ -1,676 +1,855 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#include "internal.hpp" -#include "device_datum.hpp" -#include "string_buffer.hpp" - -static const char *sUnavailable = "UNAVAILABLE"; - -/* - * Data value methods. - */ -DeviceDatum::DeviceDatum(const char *aName) -{ - strncpy(mName, aName, NAME_LEN); - mName[NAME_LEN - 1] = '\0'; - strcpy(mOrigName, mName); - mChanged = false; - mHasValue = false; -} - - -DeviceDatum::~DeviceDatum() -{ -} - -bool DeviceDatum::prefixName(const char *aName) -{ - // Check for overflow. - int len = strlen(aName); - if (strlen(mOrigName) + len >= (size_t) NAME_LEN) - return false; - - strcpy(mName, aName); - mName[len++] = ':'; - strcpy(mName + len, mOrigName); - - // Make sure the whole thing is terminated - mName[NAME_LEN - 1] = '\0'; - - return true; -} - -void DeviceDatum::setName(const char *aName) -{ - strncpy(mName, aName, NAME_LEN); - mName[NAME_LEN - 1] = '\0'; - strcpy(mOrigName, mName); -} - -void DeviceDatum::setNativeUnits(const char *aUnits) -{ - strncpy(mNativeUnits, aUnits, UNITS_LEN); - mNativeUnits[UNITS_LEN - 1] = '\0'; -} - -bool DeviceDatum::append(StringBuffer &aBuffer) -{ - char buffer[1024]; - aBuffer.append(toString(buffer, 1024)); - mChanged = false; - return mChanged; -} - -bool DeviceDatum::hasInitialValue() -{ - return mHasValue; -} - -bool DeviceDatum::requiresFlush() -{ - return false; -} - -// Append text to the buffer and remove all and characters. -void DeviceDatum::appendText(char *aBuffer, char *aValue, int aMaxLen) -{ - size_t len = strlen(aBuffer); - char *cp = aValue, *dp = aBuffer + len; - for (size_t i = len; i < (size_t) aMaxLen && *cp != '\0'; i++) - { - if (*cp == '\n' || *cp == '\r') - *dp = ' '; - else - *dp = *cp; - dp++; cp++; - } - *dp = '\0'; -} - -/* - * Event methods - */ -Event::Event(const char* aName) : - DeviceDatum(aName) -{ - mValue[0] = 0; -} - -bool Event::setValue(const char *aValue) -{ - if (strncmp(aValue, mValue, EVENT_VALUE_LEN) != 0 || !mHasValue) - { - mChanged = true; - strncpy(mValue, aValue, EVENT_VALUE_LEN); - mValue[EVENT_VALUE_LEN - 1] = '\0'; - mHasValue = true; - } - return mChanged; -} - -char *Event::toString(char *aBuffer, int aMaxLen) -{ - snprintf(aBuffer, aMaxLen, "|%s|", mName); - appendText(aBuffer, mValue, aMaxLen); - return aBuffer; -} - -bool Event::unavailable() -{ - return setValue(sUnavailable); -} - -/* - * IntEvent methods - */ -IntEvent::IntEvent(const char *aName) - : DeviceDatum(aName) -{ - mValue = 0; - mUnavailable = false; -} - -bool IntEvent::setValue(int aValue) -{ - if (aValue != mValue || !mHasValue || mUnavailable) - { - mChanged = true; - mValue = aValue; - mHasValue = true; - mUnavailable = false; - } - - return mChanged; -} - -char *IntEvent::toString(char *aBuffer, int aMaxLen) -{ - if (mUnavailable) - snprintf(aBuffer, aMaxLen, "|%s|UNAVAILABLE", mName); - else - snprintf(aBuffer, aMaxLen, "|%s|%d", mName, mValue); - - return aBuffer; -} - -bool IntEvent::unavailable() -{ - if (!mUnavailable) - { - mChanged = true; - mUnavailable = true; - } - - return mChanged; -} - -/* - * Sample methods - */ -Sample::Sample(const char *aName, double aEpsilon) - : DeviceDatum(aName), mEpsilon(aEpsilon) -{ - mValue = 0.0; - mUnavailable = false; -} - -bool Sample::setValue(double aValue) -{ - if (fabs(aValue - mValue) > mEpsilon || !mHasValue || - mUnavailable) - { - mChanged = true; - mValue = aValue; - mHasValue = true; - mUnavailable = false; - } - return mChanged; -} - -char *Sample::toString(char *aBuffer, int aMaxLen) -{ - if (mUnavailable) - snprintf(aBuffer, aMaxLen, "|%s|UNAVAILABLE", mName); - else - snprintf(aBuffer, aMaxLen, "|%s|%.10g", mName, mValue); - return aBuffer; -} - -bool Sample::unavailable() -{ - if (!mUnavailable) - { - mChanged = true; - mUnavailable = true; - mHasValue = true; - } - - return mChanged; -} - - -/* Power */ - -bool PowerState::setValue(enum EPowerState aState) -{ - if (mState != aState || !mHasValue) - { - mState = aState; - mChanged = true; - mHasValue = true; - } - return mChanged; -} - -char *PowerState::toString(char *aBuffer, int aMaxLen) -{ - const char *text; - switch(mState) - { - case eUNAVAILABLE: text = sUnavailable; break; - case eON: text = "ON"; break; - case eOFF: text = "OFF"; break; - default: text = ""; break; - } - snprintf(aBuffer, aMaxLen, "|%s|%s", mName, text); - return aBuffer; -} - -bool PowerState::unavailable() -{ - return setValue(eUNAVAILABLE); -} - -/* Execution */ - -bool Execution::setValue(enum EExecutionState aState) -{ - if (mState != aState || !mHasValue) - { - mState = aState; - mChanged = true; - mHasValue = true; - } - - return mChanged; -} - -char *Execution::toString(char *aBuffer, int aMaxLen) -{ - const char *text; - switch(mState) - { - case eUNAVAILABLE: text = sUnavailable; break; - case eACTIVE: text = "ACTIVE"; break; - case eREADY: text = "READY"; break; - case eINTERRUPTED: text = "INTERRUPTED"; break; - case eSTOPPED: text = "STOPPED"; break; - case eFEED_HOLD: text = "FEED_HOLD"; break; - default: text = ""; break; - } - snprintf(aBuffer, aMaxLen, "|%s|%s", mName, text); - return aBuffer; -} - -bool Execution::unavailable() -{ - return setValue(eUNAVAILABLE); -} - -/* ControllerMode */ - -char *ControllerMode::toString(char *aBuffer, int aMaxLen) -{ - const char *text; - switch(mMode) - { - case eUNAVAILABLE: text = sUnavailable; break; - case eSEMI_AUTOMATIC: text = "SEMI_AUTOMATIC"; break; - case eAUTOMATIC: text = "AUTOMATIC"; break; - case eMANUAL: text = "MANUAL"; break; - case eMANUAL_DATA_INPUT: text = "MANUAL_DATA_INPUT"; break; - default: text = ""; break; - } - snprintf(aBuffer, aMaxLen, "|%s|%s", mName, text); - return aBuffer; -} - -bool ControllerMode::setValue(enum EMode aMode) -{ - if (mMode != aMode || !mHasValue) - { - mMode = aMode; - mChanged = true; - mHasValue = true; - } - - return mChanged; -} - -bool ControllerMode::unavailable() -{ - return setValue(eUNAVAILABLE); -} - -/* Direction */ - -char *Direction::toString(char *aBuffer, int aMaxLen) -{ - const char *text; - switch(mDirection) - { - case eUNAVAILABLE: text = sUnavailable; break; - case eCLOCKWISE: text = "CLOCKWISE"; break; - case eCOUNTER_CLOCKWISE: text = "COUNTER_CLOCKWISE"; break; - default: text = ""; break; - } - snprintf(aBuffer, aMaxLen, "|%s|%s", mName, text); - return aBuffer; -} - -bool Direction::setValue(enum ERotationDirection aDirection) -{ - if (mDirection != aDirection || !mHasValue) - { - mDirection = aDirection; - mChanged = true; - mHasValue = true; - } - - return mChanged; -} - -bool Direction::unavailable() -{ - return setValue(eUNAVAILABLE); -} - -/* Emergency Stop */ - -char *EmergencyStop::toString(char *aBuffer, int aMaxLen) -{ - const char *text; - switch(mValue) - { - case eUNAVAILABLE: text = sUnavailable; break; - case eTRIGGERED: text = "TRIGGERED"; break; - case eARMED: text = "ARMED"; break; - default: text = ""; break; - } - snprintf(aBuffer, aMaxLen, "|%s|%s", mName, text); - return aBuffer; -} - -bool EmergencyStop::setValue(enum EValues aValue) -{ - if (mValue != aValue || !mHasValue) - { - mValue = aValue; - mChanged = true; - mHasValue = true; - } - - return mChanged; -} - -bool EmergencyStop::unavailable() -{ - return setValue(eUNAVAILABLE); -} - -/* Axis Coupling */ - -char *AxisCoupling::toString(char *aBuffer, int aMaxLen) -{ - const char *text; - switch(mValue) - { - case eUNAVAILABLE: text = sUnavailable; break; - case eTANDEM: text = "TANDEM"; break; - case eSYNCHRONOUS: text = "SYNCHRONOUS"; break; - case eMASTER: text = "MASTER"; break; - case eSLAVE: text = "SLAVE"; break; - default: text = ""; break; - } - snprintf(aBuffer, aMaxLen, "|%s|%s", mName, text); - return aBuffer; -} - -bool AxisCoupling::setValue(enum EValues aValue) -{ - if (mValue != aValue || !mHasValue) - { - mValue = aValue; - mChanged = true; - mHasValue = true; - } - return mChanged; -} - -bool AxisCoupling::unavailable() -{ - return setValue(eUNAVAILABLE); -} - -/* Door State */ - -char *DoorState::toString(char *aBuffer, int aMaxLen) -{ - const char *text; - switch(mValue) - { - case eUNAVAILABLE: text = sUnavailable; break; - case eOPEN: text = "CLOSED"; break; - case eCLOSED: text = "OPEN"; break; - default: text = ""; break; - } - snprintf(aBuffer, aMaxLen, "|%s|%s", mName, text); - return aBuffer; -} - -bool DoorState::setValue(enum EValues aValue) -{ - if (mValue != aValue || !mHasValue) - { - mValue = aValue; - mChanged = true; - mHasValue = true; - } - return mChanged; -} - -bool DoorState::unavailable() -{ - return setValue(eUNAVAILABLE); -} - -// Path Mode - -char *PathMode::toString(char *aBuffer, int aMaxLen) -{ - const char *text; - switch(mValue) - { - case eUNAVAILABLE: text = sUnavailable; break; - case eINDEPENDENT: text = "INDEPENDENT"; break; - case eSYNCHRONOUS: text = "SYNCHRONOUS"; break; - case eMIRROR: text = "MIRROR"; break; - default: text = ""; break; - } - snprintf(aBuffer, aMaxLen, "|%s|%s", mName, text); - return aBuffer; -} - -bool PathMode::setValue(enum EValues aValue) -{ - if (mValue != aValue || !mHasValue) - { - mValue = aValue; - mChanged = true; - mHasValue = true; - } - return mChanged; -} - -bool PathMode::unavailable() -{ - return setValue(eUNAVAILABLE); -} - -// Rotary Mode - -char *RotaryMode::toString(char *aBuffer, int aMaxLen) -{ - const char *text; - switch(mValue) - { - case eUNAVAILABLE: text = sUnavailable; break; - case eSPINDLE: text = "SPINDLE"; break; - case eINDEX: text = "INDEX"; break; - case eCONTOUR: text = "CONTOUR"; break; - default: text = ""; break; - } - snprintf(aBuffer, aMaxLen, "|%s|%s", mName, text); - return aBuffer; -} - -bool RotaryMode::setValue(enum EValues aValue) -{ - if (mValue != aValue || !mHasValue) - { - mValue = aValue; - mChanged = true; - mHasValue = true; - } - return mChanged; -} - -bool RotaryMode::unavailable() -{ - return setValue(eUNAVAILABLE); -} - - -// Message - -Message::Message(const char *aName) : - DeviceDatum(aName) -{ - mNativeCode[0] = 0; -} - -char *Message::toString(char *aBuffer, int aMaxLen) -{ - snprintf(aBuffer, aMaxLen, "|%s|%s|", mName, mNativeCode); - appendText(aBuffer, mText, aMaxLen); - return aBuffer; -} - - bool Message::setValue(const char *aText, const char *aCode) -{ - if (!mHasValue || - strncmp(aCode, mNativeCode, EVENT_VALUE_LEN) != 0 || - strncmp(aText, mText, EVENT_VALUE_LEN) != 0) - - { - strncpy(mNativeCode, aCode, EVENT_VALUE_LEN); - mNativeCode[EVENT_VALUE_LEN - 1] = '\0'; - - strncpy(mText, aText, EVENT_VALUE_LEN); - mText[EVENT_VALUE_LEN - 1] = '\0'; - - mChanged = true; - mHasValue = true; - } - - return mChanged; -} - -bool Message::requiresFlush() -{ - return true; -} - -bool Message::unavailable() -{ - return setValue(sUnavailable); -} - -/* - * PathPosition methods - */ -PathPosition::PathPosition(const char *aName, double aEpsilon) - : DeviceDatum(aName), mEpsilon(aEpsilon) -{ - mX = mY = mZ = 0.0; - mUnavailable = false; -} - -bool PathPosition::setValue(double aX, double aY, double aZ) -{ - if (!mHasValue || - fabs(aX - mX) > mEpsilon || - fabs(aY - mY) > mEpsilon || - fabs(aZ - mZ) > mEpsilon || - mUnavailable) - { - mChanged = true; - mX = aX; mY = aY; mZ = aZ; - mHasValue = true; - mUnavailable = false; - } - return mChanged; -} - -char *PathPosition::toString(char *aBuffer, int aMaxLen) -{ - if (mUnavailable) - snprintf(aBuffer, aMaxLen, "|%s|UNAVAILABLE", mName); - else - snprintf(aBuffer, aMaxLen, "|%s|%.10f %0.10f %0.10f", mName, mX, mY, mZ); - return aBuffer; -} - -bool PathPosition::unavailable() -{ - if (!mUnavailable) - { - mChanged = true; - mUnavailable = true; - } - - return mChanged; -} - -/* - * Availability methods - */ - -Availability::Availability(const char *aName) - : DeviceDatum(aName) -{ - mHasValue = true; - mUnavailable = false; -} - -char *Availability::toString(char *aBuffer, int aMaxLen) -{ - if (mUnavailable) - snprintf(aBuffer, aMaxLen, "|%s|UNAVAILABLE", mName); - else - snprintf(aBuffer, aMaxLen, "|%s|AVAILABLE", mName); - return aBuffer; -} - -bool Availability::unavailable() -{ - if (!mUnavailable) - { - mChanged = true; - mUnavailable = true; - } - - return mChanged; -} - -bool Availability::available() -{ - if (mUnavailable) - { - mChanged = true; - mUnavailable = false; - } - - return mChanged; -} +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#include "internal.hpp" +#include "device_datum.hpp" +#include "string_buffer.hpp" + +static const char *sUnavailable = "UNAVAILABLE"; + + +DeviceDatum::DeviceDatum(const char *name) +{ + strncpy(mName, name, NAME_LEN); + mName[NAME_LEN - 1] = '\0'; + strcpy(mOrigName, mName); + mChanged = false; + mHasValue = false; +} + + +DeviceDatum::~DeviceDatum() +{ +} + + +bool DeviceDatum::prefixName(const char *name) +{ + // Check for overflow. + auto len = strlen(name); + if (strlen(mOrigName) + len >= (size_t) NAME_LEN) + return false; + + strcpy(mName, name); + mName[len++] = ':'; + strcpy(mName + len, mOrigName); + + // Make sure the whole thing is terminated + mName[NAME_LEN - 1] = '\0'; + return true; +} + + +void DeviceDatum::setName(const char *name) +{ + strncpy(mName, name, NAME_LEN); + mName[NAME_LEN - 1] = '\0'; + strcpy(mOrigName, mName); +} + + +void DeviceDatum::setNativeUnits(const char *units) +{ + strncpy(mNativeUnits, units, UNITS_LEN); + mNativeUnits[UNITS_LEN - 1] = '\0'; +} + + +bool DeviceDatum::append(StringBuffer &stringBuffer) +{ + char buffer[1024]; + stringBuffer.append(toString(buffer, 1024)); + mChanged = false; + return mChanged; +} + + +bool DeviceDatum::hasInitialValue() const +{ + return mHasValue; +} + + +bool DeviceDatum::requiresFlush() const +{ + return false; +} + + +// Append text to the buffer and remove all and characters. +void DeviceDatum::appendText(char *buffer, char *value, int maxLen) +{ + auto len = strlen(buffer); + auto cp = value; + auto dp = buffer + len; + + for (auto i = len; i < (size_t)maxLen && *cp != '\0'; i++) + { + if (*cp == '\n' || *cp == '\r') + *dp = ' '; + else + *dp = *cp; + + dp++; + cp++; + } + + *dp = '\0'; +} + + +Event::Event(const char *name) : + DeviceDatum(name), + mValue{0} +{ +} + + +bool Event::setValue(const char *value) +{ + if (strncmp(value, mValue, EVENT_VALUE_LEN) != 0 || !mHasValue) + { + mChanged = true; + strncpy(mValue, value, EVENT_VALUE_LEN); + mValue[EVENT_VALUE_LEN - 1] = '\0'; + mHasValue = true; + } + + return mChanged; +} + + +char *Event::toString(char *buffer, int maxLen) +{ + snprintf(buffer, maxLen, "|%s|", mName); + appendText(buffer, mValue, maxLen); + return buffer; +} + + +bool Event::unavailable() +{ + return setValue(sUnavailable); +} + + +IntEvent::IntEvent(const char *name) : + DeviceDatum(name), + mValue{0}, + mUnavailable(false) +{ +} + + +bool IntEvent::setValue(int value) +{ + if (value != mValue || !mHasValue || mUnavailable) + { + mChanged = true; + mValue = value; + mHasValue = true; + mUnavailable = false; + } + + return mChanged; +} + + +char *IntEvent::toString(char *buffer, int maxLen) +{ + if (mUnavailable) + snprintf(buffer, maxLen, "|%s|UNAVAILABLE", mName); + else + snprintf(buffer, maxLen, "|%s|%d", mName, mValue); + + return buffer; +} + + +bool IntEvent::unavailable() +{ + if (!mUnavailable) + { + mChanged = true; + mUnavailable = true; + } + + return mChanged; +} + + +Sample::Sample(const char *name, double epsilon) : + DeviceDatum(name), + mValue(0.0), + mUnavailable(false), + mEpsilon(epsilon) +{ +} + + +bool Sample::setValue(double value) +{ + if (fabs(value - mValue) > mEpsilon || + !mHasValue || + mUnavailable ) + { + mChanged = true; + mValue = value; + mHasValue = true; + mUnavailable = false; + } + + return mChanged; +} + + +char *Sample::toString(char *buffer, int maxLen) +{ + if (mUnavailable) + snprintf(buffer, maxLen, "|%s|UNAVAILABLE", mName); + else + snprintf(buffer, maxLen, "|%s|%.10g", mName, mValue); + + return buffer; +} + + +bool Sample::unavailable() +{ + if (!mUnavailable) + { + mChanged = true; + mUnavailable = true; + mHasValue = true; + } + + return mChanged; +} + + +bool PowerState::setValue(enum EPowerState state) +{ + if (mState != state || !mHasValue) + { + mState = state; + mChanged = true; + mHasValue = true; + } + + return mChanged; +} + + +char *PowerState::toString(char *buffer, int maxLen) +{ + const char *text(nullptr); + + switch (mState) + { + case eUNAVAILABLE: + text = sUnavailable; + break; + + case eON: + text = "ON"; + break; + + case eOFF: + text = "OFF"; + break; + + default: + text = ""; + break; + } + + snprintf(buffer, maxLen, "|%s|%s", mName, text); + return buffer; +} + + +bool PowerState::unavailable() +{ + return setValue(eUNAVAILABLE); +} + + +bool Execution::setValue(enum EExecutionState state) +{ + if (mState != state || !mHasValue) + { + mState = state; + mChanged = true; + mHasValue = true; + } + + return mChanged; +} + + +char *Execution::toString(char *buffer, int maxLen) +{ + const char *text(nullptr); + + switch (mState) + { + case eUNAVAILABLE: + text = sUnavailable; + break; + + case eACTIVE: + text = "ACTIVE"; + break; + + case eREADY: + text = "READY"; + break; + + case eINTERRUPTED: + text = "INTERRUPTED"; + break; + + case eSTOPPED: + text = "STOPPED"; + break; + + case eFEED_HOLD: + text = "FEED_HOLD"; + break; + + default: + text = ""; + break; + } + + snprintf(buffer, maxLen, "|%s|%s", mName, text); + return buffer; +} + + +bool Execution::unavailable() +{ + return setValue(eUNAVAILABLE); +} + + +char *ControllerMode::toString(char *buffer, int maxLen) +{ + const char *text(nullptr); + + switch (mMode) + { + case eUNAVAILABLE: + text = sUnavailable; + break; + + case eSEMI_AUTOMATIC: + text = "SEMI_AUTOMATIC"; + break; + + case eAUTOMATIC: + text = "AUTOMATIC"; + break; + + case eMANUAL: + text = "MANUAL"; + break; + + case eMANUAL_DATA_INPUT: + text = "MANUAL_DATA_INPUT"; + break; + + default: + text = ""; + break; + } + + snprintf(buffer, maxLen, "|%s|%s", mName, text); + return buffer; +} + + +bool ControllerMode::setValue(enum EMode mode) +{ + if (mMode != mode || !mHasValue) + { + mMode = mode; + mChanged = true; + mHasValue = true; + } + + return mChanged; +} + + +bool ControllerMode::unavailable() +{ + return setValue(eUNAVAILABLE); +} + + +char *Direction::toString(char *buffer, int maxLen) +{ + const char *text(nullptr); + + switch (mDirection) + { + case eUNAVAILABLE: + text = sUnavailable; + break; + + case eCLOCKWISE: + text = "CLOCKWISE"; + break; + + case eCOUNTER_CLOCKWISE: + text = "COUNTER_CLOCKWISE"; + break; + + default: + text = ""; + break; + } + + snprintf(buffer, maxLen, "|%s|%s", mName, text); + return buffer; +} + + +bool Direction::setValue(enum ERotationDirection direction) +{ + if (mDirection != direction || !mHasValue) + { + mDirection = direction; + mChanged = true; + mHasValue = true; + } + + return mChanged; +} + + +bool Direction::unavailable() +{ + return setValue(eUNAVAILABLE); +} + + +char *EmergencyStop::toString(char *buffer, int maxLen) +{ + const char *text(nullptr); + + switch (mValue) + { + case eUNAVAILABLE: + text = sUnavailable; + break; + + case eTRIGGERED: + text = "TRIGGERED"; + break; + + case eARMED: + text = "ARMED"; + break; + + default: + text = ""; + break; + } + + snprintf(buffer, maxLen, "|%s|%s", mName, text); + return buffer; +} + + +bool EmergencyStop::setValue(enum EValues value) +{ + if (mValue != value || !mHasValue) + { + mValue = value; + mChanged = true; + mHasValue = true; + } + + return mChanged; +} + + +bool EmergencyStop::unavailable() +{ + return setValue(eUNAVAILABLE); +} + + +char *AxisCoupling::toString(char *buffer, int maxLen) +{ + const char *text(nullptr); + + switch (mValue) + { + case eUNAVAILABLE: + text = sUnavailable; + break; + + case eTANDEM: + text = "TANDEM"; + break; + + case eSYNCHRONOUS: + text = "SYNCHRONOUS"; + break; + + case eMASTER: + text = "MASTER"; + break; + + case eSLAVE: + text = "SLAVE"; + break; + + default: + text = ""; + break; + } + + snprintf(buffer, maxLen, "|%s|%s", mName, text); + return buffer; +} + + +bool AxisCoupling::setValue(enum EValues value) +{ + if (mValue != value || !mHasValue) + { + mValue = value; + mChanged = true; + mHasValue = true; + } + + return mChanged; +} + + +bool AxisCoupling::unavailable() +{ + return setValue(eUNAVAILABLE); +} + + +char *DoorState::toString(char *buffer, int maxLen) +{ + const char *text(nullptr); + + switch (mValue) + { + case eUNAVAILABLE: + text = sUnavailable; + break; + + case eOPEN: + text = "CLOSED"; + break; + + case eCLOSED: + text = "OPEN"; + break; + + default: + text = ""; + break; + } + + snprintf(buffer, maxLen, "|%s|%s", mName, text); + return buffer; +} + + +bool DoorState::setValue(enum EValues value) +{ + if (mValue != value || !mHasValue) + { + mValue = value; + mChanged = true; + mHasValue = true; + } + + return mChanged; +} + + +bool DoorState::unavailable() +{ + return setValue(eUNAVAILABLE); +} + + +char *PathMode::toString(char *buffer, int maxLen) +{ + const char *text(nullptr); + + switch (mValue) + { + case eUNAVAILABLE: + text = sUnavailable; + break; + + case eINDEPENDENT: + text = "INDEPENDENT"; + break; + + case eSYNCHRONOUS: + text = "SYNCHRONOUS"; + break; + + case eMIRROR: + text = "MIRROR"; + break; + + default: + text = ""; + break; + } + + snprintf(buffer, maxLen, "|%s|%s", mName, text); + return buffer; +} + + +bool PathMode::setValue(enum EValues value) +{ + if (mValue != value || !mHasValue) + { + mValue = value; + mChanged = true; + mHasValue = true; + } + + return mChanged; +} + + +bool PathMode::unavailable() +{ + return setValue(eUNAVAILABLE); +} + + +char *RotaryMode::toString(char *buffer, int maxLen) +{ + const char *text(nullptr); + + switch (mValue) + { + case eUNAVAILABLE: + text = sUnavailable; + break; + + case eSPINDLE: + text = "SPINDLE"; + break; + + case eINDEX: + text = "INDEX"; + break; + + case eCONTOUR: + text = "CONTOUR"; + break; + + default: + text = ""; + break; + } + + snprintf(buffer, maxLen, "|%s|%s", mName, text); + return buffer; +} + + +bool RotaryMode::setValue(enum EValues value) +{ + if (mValue != value || !mHasValue) + { + mValue = value; + mChanged = true; + mHasValue = true; + } + + return mChanged; +} + + +bool RotaryMode::unavailable() +{ + return setValue(eUNAVAILABLE); +} + + + +Message::Message(const char *name) : + DeviceDatum(name), + mNativeCode{0} +{ +} + + +char *Message::toString(char *buffer, int maxLen) +{ + snprintf(buffer, maxLen, "|%s|%s|", mName, mNativeCode); + appendText(buffer, mText, maxLen); + return buffer; +} + + +bool Message::setValue(const char *text, const char *code) +{ + if (!mHasValue || + strncmp(code, mNativeCode, EVENT_VALUE_LEN) || + strncmp(text, mText, EVENT_VALUE_LEN) ) + + { + strncpy(mNativeCode, code, EVENT_VALUE_LEN); + mNativeCode[EVENT_VALUE_LEN - 1] = '\0'; + + strncpy(mText, text, EVENT_VALUE_LEN); + mText[EVENT_VALUE_LEN - 1] = '\0'; + + mChanged = true; + mHasValue = true; + } + + return mChanged; +} + + +bool Message::unavailable() +{ + return setValue(sUnavailable); +} + + +PathPosition::PathPosition(const char *name, double epsilon) + : DeviceDatum(name), + mX(0.0), + mY(0.0), + mZ(0.0), + mUnavailable(false), + mEpsilon(epsilon) +{ +} + + +bool PathPosition::setValue(double x, double y, double z) +{ + if (!mHasValue || + fabs(x- mX) > mEpsilon || + fabs(y - mY) > mEpsilon || + fabs(z - mZ) > mEpsilon || + mUnavailable) + { + mChanged = true; + mX = x; + mY = y; + mZ = z; + mHasValue = true; + mUnavailable = false; + } + + return mChanged; +} + + +char *PathPosition::toString(char *buffer, int maxLen) +{ + if (mUnavailable) + snprintf(buffer, maxLen, "|%s|UNAVAILABLE", mName); + else + snprintf(buffer, maxLen, "|%s|%.10f %0.10f %0.10f", mName, mX, mY, mZ); + + return buffer; +} + + +bool PathPosition::unavailable() +{ + if (!mUnavailable) + { + mChanged = true; + mUnavailable = true; + } + + return mChanged; +} + + +Availability::Availability(const char *name) : + DeviceDatum(name), + mUnavailable(false) +{ + mHasValue = true; +} + + +char *Availability::toString(char *buffer, int maxLen) +{ + if (mUnavailable) + snprintf(buffer, maxLen, "|%s|UNAVAILABLE", mName); + else + snprintf(buffer, maxLen, "|%s|AVAILABLE", mName); + + return buffer; +} + + +bool Availability::unavailable() +{ + if (!mUnavailable) + { + mChanged = true; + mUnavailable = true; + } + + return mChanged; +} + + +bool Availability::available() +{ + if (mUnavailable) + { + mChanged = true; + mUnavailable = false; + } + + return mChanged; +} diff --git a/src/device_datum.hpp b/src/device_datum.hpp index 161d731..8b39808 100644 --- a/src/device_datum.hpp +++ b/src/device_datum.hpp @@ -1,410 +1,508 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef DEVICE_DATUM_HPP -#define DEVICE_DATUM_HPP - -/* Forward class definitions */ -class StringBuffer; - -/* Some constants for field lengths */ -const int NAME_LEN = 32; -const int CODE_LEN = 32; -const int UNITS_LEN = 32; -const int NATIVE_CODE_LEN = 32; -const int SEVERITY_LEN = 32; -const int STATE_LEN = 32; -const int DESCRIPTION_LEN = 512; -const int EVENT_VALUE_LEN = 512; - -/* - * An abstract data value that knows its name and tracks when it has changed. - * - * The data value will be set in the subclasses. - */ -class DeviceDatum { -protected: - /* The name of the Data Value */ - char mName[NAME_LEN]; - char mOrigName[NAME_LEN]; - char mNativeUnits[UNITS_LEN]; - - /* A changed flag to indicated that the value has changed since last append. */ - bool mChanged; - - /* Has this data value been initialized? */ - bool mHasValue; - -protected: - void appendText(char *aBuffer, char *aValue, int aMaxLen); - -public: - // The name will be supplied later... - DeviceDatum(const char *aName = ""); - - virtual ~DeviceDatum(); - - virtual bool changed() { return mChanged; } - void reset() { mChanged = false; } - - const char *getNativeUnits() { return mNativeUnits; } - void setNativeUnits(const char *aNativeUnits); - - bool prefixName(const char *aPrefix); - bool hasValue() const { return mHasValue; } - char *getName() { return mName; } - void setName(const char *aName = ""); - virtual char *toString(char *aBuffer, int aMaxLen) = 0; - virtual bool append(StringBuffer &aBuffer); - virtual bool hasInitialValue(); - virtual bool requiresFlush(); - - virtual bool unavailable() = 0; - virtual void begin() { } - virtual void prepare() { } - virtual void cleanup() { } - virtual void initialize() { } -}; - -/* - * An event is a data value with a string value. - */ -class Event : public DeviceDatum -{ -protected: - char mValue[EVENT_VALUE_LEN]; - -public: - Event(const char *aName = ""); - bool setValue(const char *aValue); - const char *getValue() { return mValue; } - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool unavailable(); -}; - -/* - * An int event is an event with an integer value. This can be used - * for line number events. - */ -class IntEvent : public DeviceDatum -{ -protected: - int mValue; - bool mUnavailable; - -public: - IntEvent(const char *aName = ""); - bool setValue(int aValue); - int getValue() { return mValue; } - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool unavailable(); -}; - -/* - * A sample event is used for floating point samples. - */ - -class Sample : public DeviceDatum -{ -protected: - double mValue; - bool mUnavailable; - double mEpsilon; - -public: - Sample(const char *aName = "", double aEpsilon = 0.000001); - bool setValue(double aValue); - double getValue() { return mValue; } - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool unavailable(); -}; - -/* Power status data value */ - -class PowerState : public DeviceDatum -{ -public: - enum EPowerState { - eUNAVAILABLE, - eON, - eOFF, - }; - -protected: - EPowerState mState; - -public: - PowerState(const char *aName = "") : DeviceDatum(aName) { } - bool setValue(enum EPowerState aState); - EPowerState getValue() { return mState; } - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool unavailable(); -}; - -/* Executaion state */ - -class Execution : public DeviceDatum -{ -public: - enum EExecutionState { - eUNAVAILABLE, - eREADY, - eINTERRUPTED, - eSTOPPED, - eACTIVE, - eFEED_HOLD - }; - -protected: - EExecutionState mState; - -public: - Execution(const char *aName = "") : DeviceDatum(aName) { } - bool setValue(enum EExecutionState aState); - EExecutionState getValue() { return mState; } - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool unavailable(); -}; - -/* ControllerMode */ - -class ControllerMode : public DeviceDatum -{ -public: - enum EMode { - eUNAVAILABLE, - eAUTOMATIC, - eMANUAL, - eMANUAL_DATA_INPUT, - eSEMI_AUTOMATIC - }; - -protected: - EMode mMode; - -public: - ControllerMode(const char *aName = "") : DeviceDatum(aName) { } - bool setValue(enum EMode aState); - EMode getValue() { return mMode; } - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool unavailable(); -}; - - -/* Direction */ - -class Direction : public DeviceDatum -{ -public: - enum ERotationDirection { - eUNAVAILABLE, - eCLOCKWISE, - eCOUNTER_CLOCKWISE - }; - -protected: - ERotationDirection mDirection; - -public: - Direction(const char *aName = "") : DeviceDatum(aName) { } - bool setValue(enum ERotationDirection aDirection); - ERotationDirection getValue() { return mDirection; } - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool unavailable(); -}; - -// Version 1.1 - -/* Emergency Stop */ - -class EmergencyStop : public DeviceDatum -{ -public: - enum EValues { - eUNAVAILABLE, - eTRIGGERED, - eARMED - }; - -protected: - EValues mValue; - -public: - EmergencyStop(const char *aName = "") : DeviceDatum(aName) { } - bool setValue(enum EValues aValue); - EValues getValue() { return mValue; } - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool unavailable(); -}; - - -class AxisCoupling : public DeviceDatum -{ -public: - enum EValues { - eUNAVAILABLE, - eTANDEM, - eSYNCHRONOUS, - eMASTER, - eSLAVE - }; - -protected: - EValues mValue; - -public: - AxisCoupling(const char *aName = "") : DeviceDatum(aName) { } - bool setValue(enum EValues aValue); - EValues getValue() { return mValue; } - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool unavailable(); -}; - -class DoorState : public DeviceDatum -{ -public: - enum EValues { - eUNAVAILABLE, - eOPEN, - eCLOSED - }; - -protected: - EValues mValue; - -public: - DoorState(const char *aName = "") : DeviceDatum(aName) { } - bool setValue(enum EValues aValue); - EValues getValue() { return mValue; } - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool unavailable(); -}; - -class PathMode : public DeviceDatum -{ -public: - enum EValues { - eUNAVAILABLE, - eINDEPENDENT, - eSYNCHRONOUS, - eMIRROR - }; - -protected: - EValues mValue; - -public: - PathMode(const char *aName = "") : DeviceDatum(aName) { } - bool setValue(enum EValues aValue); - EValues getValue() { return mValue; } - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool unavailable(); -}; - -class RotaryMode : public DeviceDatum -{ -public: - enum EValues { - eUNAVAILABLE, - eSPINDLE, - eINDEX, - eCONTOUR - }; - -protected: - EValues mValue; - -public: - RotaryMode(const char *aName = "") : DeviceDatum(aName) { } - bool setValue(enum EValues aValue); - EValues getValue() { return mValue; } - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool unavailable(); -}; - -class Message : public DeviceDatum { - char mText[EVENT_VALUE_LEN]; - char mNativeCode[EVENT_VALUE_LEN]; - -public: - Message(const char *aName = ""); - bool setValue(const char *aText, const char *aCode = ""); - virtual char *toString(char *aBuffer, int aMaxLen); - const char *getNativeCode() { return mNativeCode; } - - virtual bool requiresFlush(); - virtual bool unavailable(); -}; - -class PathPosition : public DeviceDatum { -protected: - double mX, mY, mZ; - bool mUnavailable; - double mEpsilon; - -public: - PathPosition(const char *aName = "", double aEpsilon = 0.000001); - bool setValue(double aX, double aY, double aZ); - double getX() { return mX; } - double getY() { return mY; } - double getZ() { return mZ; } - virtual char *toString(char *aBuffer, int aMaxLen); - - virtual bool unavailable(); -}; - -class Availability : public DeviceDatum -{ -protected: - bool mUnavailable; - -public: - Availability(const char *aName = ""); - virtual char *toString(char *aBuffer, int aMaxLen); - bool available(); - virtual bool unavailable(); -}; - -#endif +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +// Forward declarations +class StringBuffer; + +// Some constants for field lengths +const int NAME_LEN = 32; +const int CODE_LEN = 32; +const int UNITS_LEN = 32; +const int NATIVE_CODE_LEN = 32; +const int SEVERITY_LEN = 32; +const int STATE_LEN = 32; +const int DESCRIPTION_LEN = 512; +const int EVENT_VALUE_LEN = 512; + +// +// An abstract data value that knows its name and tracks when it has changed. +// +// The data value will be set in the subclasses. +// +class DeviceDatum +{ +protected: + // The name of the Data Value + char mName[NAME_LEN]; + char mOrigName[NAME_LEN]; + char mNativeUnits[UNITS_LEN]; + + // A changed flag to indicated that the value has changed since last append. + bool mChanged; + + // Has this data value been initialized? + bool mHasValue; + +protected: + static void appendText(char *buffer, char *value, int maxLen); + +public: + // The name will be supplied later... + DeviceDatum(const char *name = ""); + + virtual ~DeviceDatum(); + + void reset() { + mChanged = false; } + + const char *getNativeUnits() const { + return mNativeUnits; } + void setNativeUnits(const char *nativeUnits); + + bool prefixName(const char *prefix); + bool hasValue() const { + return mHasValue; } + const char *getName() const { + return mName; } + void setName(const char *name = ""); + +// Pure virtual and overridable methods +public: + virtual char *toString(char *buffer, int maxLen) = 0; + virtual bool unavailable() = 0; + + virtual bool changed() const { + return mChanged; } + virtual bool append(StringBuffer &buffer); + virtual bool hasInitialValue() const ; + virtual bool requiresFlush() const; + + virtual void begin() { } + virtual void prepare() { } + virtual void cleanup() { } + virtual void initialize() { } +}; + + +// +// An event is a data value with a string value. +// +class Event : public DeviceDatum +{ +protected: + char mValue[EVENT_VALUE_LEN]; + +public: + Event(const char *name = ""); + + bool setValue(const char *value); + const char *getValue() const { + return mValue; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + + +// +// An int event is an event with an integer value. This can be used +// for line number events. +// +class IntEvent : public DeviceDatum +{ +protected: + int mValue; + bool mUnavailable; + +public: + IntEvent(const char *name = ""); + + bool setValue(int value); + int getValue() const { + return mValue; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + + +// +// A sample event is used for floating point samples. +// +class Sample : public DeviceDatum +{ +protected: + double mValue; + bool mUnavailable; + double mEpsilon; + +public: + Sample(const char *name = "", double aEpsilon = 0.000001); + + bool setValue(double value); + double getValue() const { + return mValue; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + + +class PowerState : public DeviceDatum +{ +public: + enum EPowerState + { + eUNAVAILABLE, + eON, + eOFF, + }; + +protected: + EPowerState mState; + +public: + PowerState(const char *name = "") : DeviceDatum(name) { } + bool setValue(enum EPowerState state); + EPowerState getValue() const { + return mState; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + + +class Execution : public DeviceDatum +{ +public: + enum EExecutionState + { + eUNAVAILABLE, + eREADY, + eINTERRUPTED, + eSTOPPED, + eACTIVE, + eFEED_HOLD + }; + +protected: + EExecutionState mState; + +public: + Execution(const char *name = "") : + DeviceDatum(name) + { + } + + bool setValue(enum EExecutionState state); + EExecutionState getValue() const { + return mState; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + + +class ControllerMode : public DeviceDatum +{ +public: + enum EMode + { + eUNAVAILABLE, + eAUTOMATIC, + eMANUAL, + eMANUAL_DATA_INPUT, + eSEMI_AUTOMATIC + }; + +protected: + EMode mMode; + +public: + ControllerMode(const char *name = "") : + DeviceDatum(name) + { + } + + bool setValue(enum EMode state); + EMode getValue() const { + return mMode; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + + +class Direction : public DeviceDatum +{ +public: + enum ERotationDirection + { + eUNAVAILABLE, + eCLOCKWISE, + eCOUNTER_CLOCKWISE + }; + +protected: + ERotationDirection mDirection; + +public: + Direction(const char *name = "") : + DeviceDatum(name) + { + } + + bool setValue(enum ERotationDirection direction); + ERotationDirection getValue() const { + return mDirection; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + + +class EmergencyStop : public DeviceDatum +{ +public: + enum EValues + { + eUNAVAILABLE, + eTRIGGERED, + eARMED + }; + +protected: + EValues mValue; + +public: + EmergencyStop(const char *name = "") : + DeviceDatum(name) + { + } + + bool setValue(enum EValues value); + EValues getValue() const { + return mValue; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + + +class AxisCoupling : public DeviceDatum +{ +public: + enum EValues + { + eUNAVAILABLE, + eTANDEM, + eSYNCHRONOUS, + eMASTER, + eSLAVE + }; + +protected: + EValues mValue; + +public: + AxisCoupling(const char *name = "") : + DeviceDatum(name) + { + } + + bool setValue(enum EValues value); + EValues getValue() const { + return mValue; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + + +class DoorState : public DeviceDatum +{ +public: + enum EValues + { + eUNAVAILABLE, + eOPEN, + eCLOSED + }; + +protected: + EValues mValue; + +public: + DoorState(const char *name = "") : + DeviceDatum(name) + { + } + + bool setValue(enum EValues value); + EValues getValue() const { + return mValue; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + + +class PathMode : public DeviceDatum +{ +public: + enum EValues + { + eUNAVAILABLE, + eINDEPENDENT, + eSYNCHRONOUS, + eMIRROR + }; + +protected: + EValues mValue; + +public: + PathMode(const char *name = "") : + DeviceDatum(name) + { + } + + bool setValue(enum EValues value); + EValues getValue() const { + return mValue; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + + +class RotaryMode : public DeviceDatum +{ +public: + enum EValues + { + eUNAVAILABLE, + eSPINDLE, + eINDEX, + eCONTOUR + }; + +protected: + EValues mValue; + +public: + RotaryMode(const char *name = "") : DeviceDatum(name) { } + bool setValue(enum EValues value); + EValues getValue() const { + return mValue; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + + +class Message : public DeviceDatum +{ + char mText[EVENT_VALUE_LEN]; + char mNativeCode[EVENT_VALUE_LEN]; + +public: + Message(const char *name = ""); + + bool setValue(const char *text, const char *code = ""); + const char *getNativeCode() const { + return mNativeCode; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; + bool requiresFlush() const override { + return true; } +}; + + +class PathPosition : public DeviceDatum +{ +protected: + double mX, mY, mZ; + bool mUnavailable; + double mEpsilon; + +public: + PathPosition(const char *name = "", double aEpsilon = 0.000001); + bool setValue(double x, double y, double z); + double getX() const { + return mX; } + double getY() const { + return mY; } + double getZ() const { + return mZ; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + + +class Availability : public DeviceDatum +{ +protected: + bool mUnavailable; + +public: + Availability(const char *name = ""); + bool available(); + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; +}; + diff --git a/src/internal.hpp b/src/internal.hpp index e059230..64c4a38 100755 --- a/src/internal.hpp +++ b/src/internal.hpp @@ -1,95 +1,99 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ -#ifndef MTC_INTERNAL_HPP -#define MTC_INTERNAL_HPP - -#ifdef WIN32 -#define _CRT_SECURE_NO_DEPRECATE 1 - -/* Windows specific include files and types */ -#include "winsock2.h" -#ifndef AFX -#include "windows.h" -#endif -#include "errno.h" - -#define SHUT_RDWR SD_BOTH -typedef int socklen_t; -#define snprintf _snprintf -#define strdup _strdup -#define stricmp _stricmp -#define strdup _strdup - -/* Internal types */ -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned __int64 uint64_t; - -#define UINT16_MAX 0xFFFF - -#define sleep(t) Sleep(t * 1000) -#define usleep(t) Sleep(t / 1000) - -#else /* WIN32 */ - -/* Unix specifc include files */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef struct sockaddr_in SOCKADDR_IN; -typedef struct sockaddr SOCKADDR; -#define INVALID_SOCKET -1 -#define SOCKET_ERROR -1 -#define SOCKET int -#define closesocket close - -#endif /* WIN32 */ - -#include -#include -#include -#include - -#endif +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#ifdef WIN32 + #define _CRT_SECURE_NO_DEPRECATE 1 + + // Windows specific include files and types + #include + #include + #ifndef AFX + #include + #endif + #include + + #define inet_ntop InetNtop + + #define SHUT_RDWR SD_BOTH + typedef int socklen_t; + #if _MSC_VER < 1900 + #define snprintf _snprintf + #endif + #define strdup _strdup + #define stricmp _stricmp + #define strdup _strdup + + /* Internal types */ + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + typedef unsigned __int64 uint64_t; + + #if _MSC_VER < 1900 + #define UINT16_MAX 0xFFFF + #endif + + #define sleep(t) Sleep(t * 1000) + #define usleep(t) Sleep(t / 1000) + +#else /* WIN32 */ + + /* Unix specifc include files */ + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + typedef struct sockaddr_in SOCKADDR_IN; + typedef struct sockaddr SOCKADDR; + #define INVALID_SOCKET -1 + #define SOCKET_ERROR -1 + #define SOCKET int + #define closesocket close + +#endif /* WIN32 */ + +#include +#include +#include +#include diff --git a/src/logger.cpp b/src/logger.cpp index 597978a..9836859 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -1,83 +1,120 @@ - -#include "internal.hpp" -#include "logger.hpp" - -Logger *gLogger = NULL; - -void Logger::error(const char *aFormat, ...) -{ - char buffer[LOGGER_BUFFER_SIZE]; - char ts[32]; - va_list args; - va_start (args, aFormat); - fprintf(mFile, "%s - Error: %s\n", timestamp(ts), format(buffer, LOGGER_BUFFER_SIZE, aFormat, args)); - fflush(mFile); - va_end (args); -} - -void Logger::warning(const char *aFormat, ...) -{ - if (mLogLevel > eWARNING) return; - - char buffer[LOGGER_BUFFER_SIZE]; - char ts[32]; - va_list args; - va_start (args, aFormat); - fprintf(mFile, "%s - Warning: %s\n", timestamp(ts), format(buffer, LOGGER_BUFFER_SIZE, aFormat, args)); - fflush(mFile); - va_end (args); -} - -void Logger::info(const char *aFormat, ...) -{ - if (mLogLevel > eINFO) return; - - char buffer[LOGGER_BUFFER_SIZE]; - char ts[32]; - va_list args; - va_start (args, aFormat); - fprintf(mFile, "%s - Info: %s\n", timestamp(ts), format(buffer, LOGGER_BUFFER_SIZE, aFormat, args)); - fflush(mFile); - va_end (args); -} - -void Logger::debug(const char *aFormat, ...) -{ - if (mLogLevel > eDEBUG) return; - - char buffer[LOGGER_BUFFER_SIZE]; - char ts[32]; - va_list args; - va_start (args, aFormat); - fprintf(mFile, "%s - Debug: %s\n", timestamp(ts), format(buffer, LOGGER_BUFFER_SIZE, aFormat, args)); - fflush(mFile); - va_end (args); -} - - -const char *Logger::format(char *aBuffer, int aLen, const char *aFormat, va_list args) -{ - vsprintf(aBuffer, aFormat, args); - aBuffer[aLen - 1] = '\0'; - return aBuffer; -} - -const char *Logger::timestamp(char *aBuffer) -{ -#ifdef WIN32 - SYSTEMTIME st; - GetSystemTime(&st); - sprintf(aBuffer, "%4d-%02d-%02dT%02d:%02d:%02d.%03dZ", st.wYear, st.wMonth, st.wDay, st.wHour, - st.wMinute, st.wSecond, st.wMilliseconds); -#else - struct timeval tv; - struct timezone tz; - - gettimeofday(&tv, &tz); - - strftime(aBuffer, 64, "%Y-%m-%dT%H:%M:%S", gmtime(&tv.tv_sec)); - sprintf(aBuffer + strlen(aBuffer), ".%06dZ", tv.tv_usec); -#endif - - return aBuffer; -} +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#include "internal.hpp" +#include "logger.hpp" +#ifdef min + #undef min +#endif +#ifdef max + #undef max +#endif +#include +#include + +Logger *gLogger = nullptr; + + +void Logger::error(const char *inputformat, ...) +{ + char buffer[LOGGER_BUFFER_SIZE]; + va_list args; + va_start(args, inputformat); + fprintf(mFile, "%s - Error: %s\n", + timestamp().c_str(), + format(buffer, LOGGER_BUFFER_SIZE, inputformat, args)); + fflush(mFile); + va_end(args); +} + + +void Logger::warning(const char *inputformat, ...) +{ + if (mLogLevel > eWARNING) + return; + + char buffer[LOGGER_BUFFER_SIZE]; + va_list args; + va_start(args, inputformat); + fprintf(mFile, "%s - Warning: %s\n", + timestamp().c_str(), + format(buffer, LOGGER_BUFFER_SIZE, inputformat, args)); + fflush(mFile); + va_end(args); +} + + +void Logger::info(const char *inputformat, ...) +{ + if (mLogLevel > eINFO) + return; + + char buffer[LOGGER_BUFFER_SIZE]; + va_list args; + va_start(args, inputformat); + fprintf(mFile, "%s - Info: %s\n", + timestamp().c_str(), + format(buffer, LOGGER_BUFFER_SIZE, inputformat, args)); + fflush(mFile); + va_end(args); +} + + +void Logger::debug(const char *inputformat, ...) +{ + if (mLogLevel > eDEBUG) + return; + + char buffer[LOGGER_BUFFER_SIZE]; + va_list args; + va_start(args, inputformat); + fprintf(mFile, "%s - Debug: %s\n", + timestamp().c_str(), + format(buffer, LOGGER_BUFFER_SIZE, inputformat, args)); + fflush(mFile); + va_end(args); +} + + +const char *Logger::format(char *buffer, int aLen, const char *inputformat, va_list args) +{ + vsprintf(buffer, inputformat, args); + buffer[aLen - 1] = '\0'; + return buffer; +} + + +std::string Logger::timestamp() +{ + return date::format("%FT%TZ", + std::chrono::time_point_cast(std::chrono::system_clock::now())); +} \ No newline at end of file diff --git a/src/logger.hpp b/src/logger.hpp index 08f77ee..1c24f75 100644 --- a/src/logger.hpp +++ b/src/logger.hpp @@ -1,38 +1,76 @@ - -#ifndef LOGGER_HPP -#define LOGGER_HPP - -#include -#include - -#define LOGGER_BUFFER_SIZE 1024 - -class Logger { -public: - enum LogLevel { - eDEBUG, - eINFO, - eWARNING, - eERROR - }; - - Logger(FILE *aFile = stderr) : mFile(aFile) { mLogLevel = eINFO; } - void setLogLevel(LogLevel aLevel) { mLogLevel = aLevel; } - LogLevel getLogLevel() { return mLogLevel; } - - virtual void error(const char *aFormat, ...); - virtual void warning(const char *aFormat, ...); - virtual void info(const char *aFormat, ...); - virtual void debug(const char *aFormat, ...); - -protected: - const char *format(char *aBuffer, int aLen, const char *aFormat, va_list args); - const char *timestamp(char *aBuffer); - - LogLevel mLogLevel; - FILE *mFile; -}; - -extern Logger *gLogger; - -#endif +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include +#include +#include + +#define LOGGER_BUFFER_SIZE 1024 + +class Logger +{ +public: + enum LogLevel + { + eDEBUG, + eINFO, + eWARNING, + eERROR + }; + + Logger(FILE *aFile = stderr) : + mFile(aFile), + mLogLevel(eINFO) + { + } + + void setLogLevel(LogLevel aLevel) { + mLogLevel = aLevel; } + LogLevel getLogLevel() const { + return mLogLevel; } + + virtual void error(const char *format, ...); + virtual void warning(const char *format, ...); + virtual void info(const char *format, ...); + virtual void debug(const char *format, ...); + +protected: + const char *format(char *buffer, int aLen, const char *format, va_list args); + std::string timestamp(); + + LogLevel mLogLevel; + FILE *mFile; +}; + +extern Logger *gLogger; diff --git a/src/serial.cpp b/src/serial.cpp index b560cd2..0136d4f 100644 --- a/src/serial.cpp +++ b/src/serial.cpp @@ -1,182 +1,250 @@ - -#include "internal.hpp" -#include "serial.hpp" -#include "logger.hpp" - -#include - -Serial::SerialError::SerialError(const char *aMessage) -{ - strncpy(mMessage, aMessage, 1023); - mMessage[1023] = '\0'; -} - -Serial::Serial(const char *aDevice, - int aBaud, const char *aParity, int aDataBit, - int aStopBit) -{ - mBaud = aBaud; - strncpy(mDevice, aDevice, sizeof(mDevice) - 1); - mParity[sizeof(mDevice) - 1] = '\0'; - strncpy(mParity, aParity, sizeof(mParity) - 1); - mParity[sizeof(mParity) - 1] = '\0'; - mDataBit = aDataBit; - mStopBit = aStopBit; - mFlow = eNONE; - -#ifdef WIN32 - mFd = INVALID_HANDLE_VALUE; -#else - mFd = -1; -#endif - - mConnected = false; -} - -Serial::~Serial() -{ - disconnect(); -} - -int Serial::readUntil(const char *aUntil, char *aBuffer, int aLength) -{ - if (!mConnected) - { - gLogger->error("Trying to read when not connected"); - return -1; - } - - gLogger->debug("Reading upto %d bytes or '%c' we get a match", aLength, aUntil); - - int len = 0, count = 0; - char *cp = aBuffer; - const char *match = aUntil; - do - { - int ret = read(cp, 1); - if (ret == -1) - { - throw SerialError("Couldn't read"); - } - if (ret == 0) - { - usleep(10 * 1000); // 10 msec - if (count++ > 10) - { - gLogger->info("Read timed out\n"); - return -1; - } - } - else - { - count = 0; - - //printf("Received: %d == match: %d\n", *cp, *match); - if (*match == *cp) - match++; - else - match = aUntil; - - // See if we can match the beginnig of the string again. - if (*match == *cp) - match++; - //printf("Match now: %d\n", *match); - cp++; - len++; - } - } while (len <= aLength && *match != '\0'); - - *cp = '\0'; - - gLogger->debug("Read returned: %d - '%s'", len, aBuffer); - - return len; -} - -int Serial::write(const char *aBuffer) -{ - gLogger->debug("Writing '%s'\n", aBuffer); - - int ret = write(aBuffer, (int) strlen(aBuffer)); - if (ret < 0) - throw SerialError("Couldn't write"); - - gLogger->debug("Write returned: %d\n", ret); - - return ret; -} - -bool Serial::flushInput() -{ - char buffer[2]; - int ret; - do - { - ret = read(buffer, 1); - if (ret < 0) - throw SerialError("Couldn't read"); - } while (ret > 0); - -#ifdef WIN32 - DWORD errors; - COMSTAT stat; - ClearCommError(mFd, &errors, &stat); -#else - tcflush(mFd, TCIFLUSH); -#endif - - return true; -} - -int Serial::readFully(char *aBuffer, int len, uint32_t timeout) -{ - int consumed = 0; - uint64_t start = getTimestamp(); - while (consumed < len && (getTimestamp() - start) < timeout) { - int res = wait(100); - if (res > 0) { - int cnt = read(aBuffer + consumed, len - consumed); - if (cnt < 0) { - gLogger->debug("Read returned: %d\n", res); - return -1; - } - consumed += cnt; - } else if (res < 0) { - gLogger->debug("Wait returned: %d\n", res); - return res; - } - } - - return consumed; -} - -int Serial::writeFully(const char *aBuffer, int len, uint32_t timeout) -{ - int written = 0; - - uint64_t start = getTimestamp(); - while (written < len && (getTimestamp() - start) < timeout) { - int res = wait(100, Serial::WRITE); - if (res > 0) { - int cnt = write(aBuffer + written, len - written); - if (cnt > 0) { - written += cnt; - } else { - gLogger->debug("Write returned: %d\n", res); - return -1; - } - } else if (res < 0) { - gLogger->debug("Wait returned: %d\n", res); - return res; - } - } - - return written; -} - -#ifdef WIN32 -#include "serial.win32.inc" -#else -#include "serial.unix.inc" -#endif - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#include "internal.hpp" +#include "serial.hpp" +#include "logger.hpp" + +#include + + +Serial::SerialError::SerialError(const char *aMessage) +{ + strncpy(mMessage, aMessage, 1023); + mMessage[1023] = '\0'; +} + + +Serial::Serial( + const char *aDevice, + int aBaud, + const char *aParity, + int aDataBit, + int aStopBit) +{ + mBaud = aBaud; + strncpy(mDevice, aDevice, sizeof(mDevice) - 1); + mParity[sizeof(mDevice) - 1] = '\0'; + strncpy(mParity, aParity, sizeof(mParity) - 1); + mParity[sizeof(mParity) - 1] = '\0'; + mDataBit = aDataBit; + mStopBit = aStopBit; + mFlow = eNONE; + +#ifdef WIN32 + mFd = INVALID_HANDLE_VALUE; +#else + mFd = -1; +#endif + + mConnected = false; +} + + +Serial::~Serial() +{ + disconnect(); +} + + +int Serial::readUntil(const char *aUntil, char *aBuffer, int aLength) +{ + if (!mConnected) + { + gLogger->error("Trying to read when not connected"); + return -1; + } + + gLogger->debug("Reading upto %d bytes or '%c' we get a match", aLength, aUntil); + + int len = 0, count = 0; + char *cp = aBuffer; + const char *match = aUntil; + + do + { + int ret = read(cp, 1); + + if (ret == -1) + throw SerialError("Couldn't read"); + + if (ret == 0) + { + usleep(10 * 1000); // 10 msec + + if (count++ > 10) + { + gLogger->info("Read timed out\n"); + return -1; + } + } + else + { + count = 0; + + //printf("Received: %d == match: %d\n", *cp, *match); + if (*match == *cp) + match++; + else + match = aUntil; + + // See if we can match the beginnig of the string again. + if (*match == *cp) + match++; + + //printf("Match now: %d\n", *match); + cp++; + len++; + } + } + while (len <= aLength && *match != '\0'); + + *cp = '\0'; + + gLogger->debug("Read returned: %d - '%s'", len, aBuffer); + + return len; +} + + +int Serial::write(const char *aBuffer) +{ + gLogger->debug("Writing '%s'\n", aBuffer); + + int ret = write(aBuffer, (int) strlen(aBuffer)); + + if (ret < 0) + throw SerialError("Couldn't write"); + + gLogger->debug("Write returned: %d\n", ret); + + return ret; +} + + +bool Serial::flushInput() +{ + char buffer[2]; + int ret; + + do + { + ret = read(buffer, 1); + + if (ret < 0) + throw SerialError("Couldn't read"); + } + while (ret > 0); + +#ifdef WIN32 + DWORD errors; + COMSTAT stat; + ClearCommError(mFd, &errors, &stat); +#else + tcflush(mFd, TCIFLUSH); +#endif + + return true; +} + + +int Serial::readFully(char *aBuffer, int len, uint32_t timeout) +{ + int consumed = 0; + uint64_t start = getTimestamp(); + + while (consumed < len && (getTimestamp() - start) < timeout) + { + int res = wait(100); + + if (res > 0) + { + int cnt = read(aBuffer + consumed, len - consumed); + + if (cnt < 0) + { + gLogger->debug("Read returned: %d\n", res); + return -1; + } + + consumed += cnt; + } + else if (res < 0) + { + gLogger->debug("Wait returned: %d\n", res); + return res; + } + } + + return consumed; +} + + +int Serial::writeFully(const char *aBuffer, int len, uint32_t timeout) +{ + int written = 0; + + uint64_t start = getTimestamp(); + + while (written < len && (getTimestamp() - start) < timeout) + { + int res = wait(100, Serial::WRITE); + + if (res > 0) + { + int cnt = write(aBuffer + written, len - written); + + if (cnt > 0) + written += cnt; + else + { + gLogger->debug("Write returned: %d\n", res); + return -1; + } + } + else if (res < 0) + { + gLogger->debug("Wait returned: %d\n", res); + return res; + } + } + + return written; +} + + +#ifdef WIN32 + #include "serial.win32.inc" +#else + #include "serial.unix.inc" +#endif + diff --git a/src/serial.hpp b/src/serial.hpp index 9f6244d..19463e5 100644 --- a/src/serial.hpp +++ b/src/serial.hpp @@ -1,119 +1,162 @@ - -#ifndef SERIAL_HPP -#define SERIAL_HPP - -class Serial { -public: - class SerialError - { - private: - char mMessage[1024]; - - public: - SerialError(const char *aMessage); - const char *message() const { return mMessage; } - }; - -protected: - /* Descriptor (tty or socket) */ -#ifdef WIN32 - HANDLE mFd; -#else - int mFd; -#endif - - /* TCP port */ - int mPort; - - /* Device: "/dev/ttyS0", "/dev/ttyUSB0" or "/dev/tty.USA19*" - on Mac OS X for KeySpan USB<->Serial adapters this string - had to be made bigger on OS X as the directory+file name - was bigger than 19 bytes. Making it 67 bytes for now, but - OS X does support 256 byte file names. May become a problem - in the future. */ - -#ifdef __APPLE_CC__ - char mDevice[64]; -#else - char mDevice[16]; -#endif - - /* Bauds: 9600, 19200, 57600, 115200, etc */ - int mBaud; - - /* Data bit */ - unsigned char mDataBit; - - /* Stop bit */ - unsigned char mStopBit; - - /* Parity: "even", "odd", "none" */ - char mParity[5]; - bool mErrorHandling; - - enum FlowControl { - eSOFT, - eHARD, - eNONE - }; - FlowControl mFlow; - -#ifndef WIN32 - /* Save old termios settings */ - struct termios mOldTios; -#endif - - bool mConnected; - -public: - enum WaitMode { - READ, WRITE - }; - - Serial(const char *aDevice, - int aBaud, const char *aParity, int aDataBit, - int aStopBit); - ~Serial(); - - bool connected() { return mConnected; } - bool available() { return mConnected; } - - bool connect(); - bool disconnect(); - - int wait(int aTimeout, WaitMode mode = READ); - static uint64_t getTimestamp(); - - // Raw internal read - int read(char *aBuffer, int len); - - int readUntil(const char *aUntil, char *aBuffer, int aLength); - int read(char &c) { - char buffer[2]; - int ret = read(buffer, 1); - c = buffer[0]; - return ret; - } - int read(unsigned char &b) { - char c; - int ret = read(c); - b = (unsigned char) c; - return ret; - } - - int readFully(char *aBuffer, int len, uint32_t timeout = 1000); - - // Raw internal write - int write(const char *aBuffer, int len); - int writeFully(const char *aBuffer, int len, uint32_t timeout = 1000); - - // Write cover methods - int write(const char *aBuffer); - int print(char c) { char b[2]; b[0] = c; return write(b, 1); } - - bool flushInput(); - bool flush(); - bool printCommStatus(); -}; - -#endif +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + + +class Serial +{ +public: + class SerialError + { + private: + char mMessage[1024]; + + public: + SerialError(const char *aMessage); + const char *message() const { return mMessage; } + }; + +protected: + // Descriptor (tty or socket) +#ifdef WIN32 + HANDLE mFd; +#else + int mFd; +#endif + + // TCP port + int mPort; + + // Device: "/dev/ttyS0", "/dev/ttyUSB0" or "/dev/tty.USA19*" + // on Mac OS X for KeySpan USB<->Serial adapters this string + // had to be made bigger on OS X as the directory+file name + // was bigger than 19 bytes. Making it 67 bytes for now, but + // OS X does support 256 byte file names. May become a problem + // in the future. +#ifdef __APPLE_CC__ + char mDevice[64]; +#else + char mDevice[16]; +#endif + + // Bauds: 9600, 19200, 57600, 115200, etc + int mBaud; + + // Data bit + unsigned char mDataBit; + + // Stop bit + unsigned char mStopBit; + + // Parity: "even", "odd", "none" + char mParity[5]; + bool mErrorHandling; + + enum FlowControl + { + eSOFT, + eHARD, + eNONE + }; + FlowControl mFlow; + +#ifndef WIN32 + // Save old termios settings + struct termios mOldTios; +#endif + + bool mConnected; + +public: + enum WaitMode + { + READ, + WRITE + }; + + Serial(const char *aDevice, + int aBaud, + const char *aParity, + int aDataBit, + int aStopBit); + ~Serial(); + + bool connected() const { + return mConnected; } + bool available() const { + return mConnected; } + + bool connect(); + bool disconnect(); + + int wait(int aTimeout, WaitMode mode = READ); + static uint64_t getTimestamp(); + + // Raw internal read + int read(char *aBuffer, int len); + + int readUntil(const char *aUntil, char *aBuffer, int aLength); + int read(char &c) + { + char buffer[2]; + int ret = read(buffer, 1); + c = buffer[0]; + return ret; + } + int read(unsigned char &b) + { + char c; + int ret = read(c); + b = (unsigned char) c; + return ret; + } + + int readFully(char *aBuffer, int len, uint32_t timeout = 1000); + + // Raw internal write + int write(const char *aBuffer, int len); + int writeFully(const char *aBuffer, int len, uint32_t timeout = 1000); + + // Write cover methods + int write(const char *aBuffer); + int print(char c) + { + char b[2]; + b[0] = c; + return write(b, 1); + } + + bool flushInput(); + bool flush(); + bool printCommStatus(); +}; diff --git a/src/server.cpp b/src/server.cpp index 676e055..51a9798 100755 --- a/src/server.cpp +++ b/src/server.cpp @@ -1,321 +1,317 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#include "internal.hpp" -#include "server.hpp" -#include "client.hpp" -#include "logger.hpp" - -/* Constants */ -const int READ_BUFFER_LEN = 8092; - -/* Create the server and bind to the port */ -Server::Server(int aPort, int aHeartbeatFreq) -{ - mNumClients = 0; - mPort = aPort; - mTimeout = aHeartbeatFreq * 2; - - SOCKADDR_IN t; - -#ifndef WIN32 - signal(SIGPIPE, SIG_IGN); -#else - WSADATA w; - int iResult = WSAStartup(MAKEWORD(2, 2), &w); - - if (iResult != NO_ERROR) { - gLogger->error("Error at WSAStartup()\n"); - exit(1); - } -#endif - - mSocket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - - if (mSocket == INVALID_SOCKET) { - gLogger->error("Error at socket().", stderr); - delete this; - exit(1); - } - - t.sin_family = AF_INET; - t.sin_port = htons(aPort); - t.sin_addr.s_addr = htonl(INADDR_ANY); - - if (::bind(mSocket, (SOCKADDR *)&t, sizeof(t)) == SOCKET_ERROR) { - gLogger->error("Failed to bind on port %d", aPort); - delete this; - exit(1); - } - - if (listen(mSocket, 4) == SOCKET_ERROR) { - gLogger->error("Error listening."); - delete this; - exit(1); - } - - // Default to a 10 second heartbeat - sprintf(mPong, "* PONG %d\n", aHeartbeatFreq); - - gLogger->info("Server started, waiting on port %d", aPort); -} - -Server::~Server() -{ - for (int i = 0; i < mNumClients; i++) - { - Client *client = mClients[i]; - delete client; - } - - ::shutdown(mSocket, SHUT_RDWR); - -#ifdef WINDOWS - WSACleanup(); -#endif -} - -void Server::readFromClients() -{ - MTCAutoLock lock(mListLock); - - fd_set rset; - FD_ZERO(&rset); - int nfds = 0; - for (int i = 0; i < mNumClients; i++) - { - Client *client = mClients[i]; - FD_SET(client->socket(), &rset); -#ifndef WIN32 - if (client->socket() > nfds) - nfds = client->socket(); -#endif - } -#ifdef WIN32 - nfds = mNumClients; -#else - nfds++; -#endif - - struct timeval timeout; - ::memset(&timeout, 0, sizeof(timeout)); - - if (::select(nfds, &rset, 0, 0, &timeout) > 0) - { - char buffer[READ_BUFFER_LEN]; - int len; - - /* Since clients can be removed, we need to iterate backwards */ - for (int i = mNumClients - 1; i >= 0; i--) - { - Client *client = mClients[i]; - if (FD_ISSET(client->socket(), &rset)) - { - len = client->read(buffer, READ_BUFFER_LEN); - if (len > 0) - { - // Check for heartbeat - if (strncmp(buffer, "* PING", 6) == 0) - { - if (!client->mHeartbeats) - client->mHeartbeats = true; - client->mLastHeartbeat = getTimestamp(); - client->write(mPong); - } - else - printf("Received: %s", buffer); - } - else - removeClientInternal(client); - } - } - - } - - // Check heartbeats - for (int i = mNumClients - 1; i >= 0; i--) - { - Client *client = mClients[i]; - unsigned int now = getTimestamp(); - if (client->mHeartbeats) - { - if (deltaTimestamp(now, client->mLastHeartbeat) > (unsigned int) mTimeout) - { - gLogger->warning("Client has not sent heartbeat in over %d ms, disconnecting", - mTimeout); - removeClientInternal(client); - } - } - } -} - -void Server::sendToClient(Client *aClient, const char *aString) -{ - if (aClient->write(aString) < 0) - removeClient(aClient); -} - -void Server::sendToClients(const char *aString) -{ - MTCAutoLock lock(mListLock); - - for (int i = mNumClients - 1; i >= 0; i--) - { - if (mClients[i]->write(aString) < 0) - removeClientInternal(mClients[i]); - } -} - -Client *Server::connectToClients() -{ - fd_set rset; - FD_ZERO(&rset); - FD_SET(mSocket, &rset); -#ifdef WIN32 - int nfds = 1; -#else - int nfds = mSocket + 1; -#endif - - struct timeval timeout; - ::memset(&timeout, 0, sizeof(timeout)); - - Client *client = NULL; - bool added = false; - - if (::select(nfds, &rset, 0, 0, &timeout) > 0) - { - SOCKADDR_IN addr; - socklen_t len = sizeof(addr); - memset(&addr, 0, sizeof(addr)); - - SOCKET socket = ::accept(mSocket, (SOCKADDR*) &addr, &len); - if (socket == INVALID_SOCKET) { - gLogger->error("Error at accept()."); - return 0; - } - gLogger->info("Connected to: %s on port %d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); - - int flag = 1; - ::setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (const char*) &flag, sizeof(int)); - - client = addClient(new Client(socket)); - added = true; - } - - return client; -} - - -void Server::removeClientInternal(Client *aClient) -{ - int pos = 0; - for (pos = 0; pos < mNumClients; pos++) - { - if (mClients[pos] == aClient) - break; - } - - if (pos < mNumClients) - { - mNumClients--; - if (pos < mNumClients) - { - /* Shift the array left to remove the item */ - memmove(mClients + pos, - mClients + (pos + 1), - (mNumClients - pos) * sizeof(Client*)); - } - delete aClient; - mClients[mNumClients + 1] = 0; - } -} - -/* Removes a client from the client list. -* Because the client can be removed during list iteration, lists -* should always be iterated from last to first. -*/ -void Server::removeClient(Client *aClient) -{ - MTCAutoLock lock(mListLock); - - removeClientInternal(aClient); -} - -Client *Server::addClient(Client *aClient) -{ - MTCAutoLock lock(mListLock); - - if (mNumClients < MAX_CLIENTS) - { - mClients[mNumClients] = aClient; - mNumClients++; - } - else - { - delete aClient; - aClient = NULL; - } - - return aClient; -} - -unsigned int Server::getTimestamp() -{ -#ifdef WIN32 - return GetTickCount(); -#else - timeval curtime; - gettimeofday(&curtime, 0); - - unsigned long ts = (unsigned long) curtime.tv_sec; - // Allow to truncate - ts *= 1000; - ts += curtime.tv_usec / 1000; - - return ts; -#endif -} - -unsigned int Server::deltaTimestamp(unsigned int a, unsigned int b) -{ - // Assume we are doing a - b where a should be larger, if it is not - // we have a wrap-around - unsigned int res; - if ( a >= b ) - res = a - b; - else // b > a, Compute the distance from the end: - res = a + (0xFFFFFFFF - b); - return res; -} - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#include "internal.hpp" +#include "server.hpp" +#include "client.hpp" +#include "logger.hpp" +#include + +const int READ_BUFFER_LEN = 8092; + +// Create the server and bind to the port +Server::Server(int port, std::chrono::milliseconds heartbeatFreq) +{ + mNumClients = 0; + mPort = port; + mTimeout = heartbeatFreq * 2; + + SOCKADDR_IN t; + +#ifndef WIN32 + signal(SIGPIPE, SIG_IGN); +#else + WSADATA w; + int iResult = WSAStartup(MAKEWORD(2, 2), &w); + + if (iResult != NO_ERROR) + { + gLogger->error("Error at WSAStartup()\n"); + exit(1); + } + +#endif + + mSocket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (mSocket == INVALID_SOCKET) + { + gLogger->error("Error at socket().", stderr); + delete this; + exit(1); + } + + t.sin_family = AF_INET; + t.sin_port = htons(port); + t.sin_addr.s_addr = htonl(INADDR_ANY); + + if (::bind(mSocket, (SOCKADDR *)&t, sizeof(t)) == SOCKET_ERROR) + { + gLogger->error("Failed to bind on port %d", port); + delete this; + exit(1); + } + + if (listen(mSocket, 4) == SOCKET_ERROR) + { + gLogger->error("Error listening."); + delete this; + exit(1); + } + + // Default to a 10 second heartbeat + sprintf(mPong, "* PONG %I64d\n", heartbeatFreq.count()); + + gLogger->info("Server started, waiting on port %d", port); +} + + +Server::~Server() +{ + for (int i = 0; i < mNumClients; i++) + { + Client *client = mClients[i]; + delete client; + } + + ::shutdown(mSocket, SHUT_RDWR); + +#ifdef _WINDOWS + WSACleanup(); +#endif +} + + +void Server::readFromClients() +{ + std::lock_guard lock(mListLock); + + fd_set rset; + FD_ZERO(&rset); + int nfds = 0; + + for (int i = 0; i < mNumClients; i++) + { + Client *client = mClients[i]; + FD_SET(client->socket(), &rset); +#ifndef WIN32 + + if (client->socket() > nfds) + nfds = client->socket(); + +#endif + } + +#ifdef WIN32 + nfds = mNumClients; +#else + nfds++; +#endif + + struct timeval timeout; + ::memset(&timeout, 0, sizeof(timeout)); + + if (::select(nfds, &rset, 0, 0, &timeout) > 0) + { + char buffer[READ_BUFFER_LEN]; + int len; + + // Since clients can be removed, we need to iterate backwards + for (int i = mNumClients - 1; i >= 0; i--) + { + Client *client = mClients[i]; + + if (FD_ISSET(client->socket(), &rset)) + { + len = client->read(buffer, READ_BUFFER_LEN); + + if (len > 0) + { + // Check for heartbeat + if (strncmp(buffer, "* PING", 6) == 0) + { + if (!client->mHeartbeats) + client->mHeartbeats = true; + + client->mLastHeartbeat = std::chrono::system_clock::now(); + client->write(mPong); + } + else + printf("Received: %s", buffer); + } + else + removeClientInternal(client); + } + } + + } + + // Check heartbeats + for (int i = mNumClients - 1; i >= 0; i--) + { + auto client = mClients[i]; + auto now = std::chrono::system_clock::now(); + + if (client->mHeartbeats) + { + if(now - client->mLastHeartbeat >mTimeout) + { + gLogger->warning("Client has not sent heartbeat in over %d ms, disconnecting", + mTimeout); + removeClientInternal(client); + } + } + } +} + + +void Server::sendToClient(Client *client, const char *string) +{ + if (client->write(string) < 0) + removeClient(client); +} + + +void Server::sendToClients(const char *string) +{ + std::lock_guard lock(mListLock); + + for (int i = mNumClients - 1; i >= 0; i--) + { + if (mClients[i]->write(string) < 0) + removeClientInternal(mClients[i]); + } +} + + +Client *Server::connectToClients() +{ + fd_set rset; + FD_ZERO(&rset); + FD_SET(mSocket, &rset); +#ifdef WIN32 + int nfds = 1; +#else + int nfds = mSocket + 1; +#endif + + struct timeval timeout; + ::memset(&timeout, 0, sizeof(timeout)); + + Client *client = nullptr; + bool added = false; + + if (::select(nfds, &rset, 0, 0, &timeout) > 0) + { + SOCKADDR_IN addr; + socklen_t len = sizeof(addr); + memset(&addr, 0, sizeof(addr)); + + SOCKET socket = ::accept(mSocket, (SOCKADDR *) &addr, &len); + + if (socket == INVALID_SOCKET) + { + gLogger->error("Error at accept()."); + return 0; + } + + char targetNameBuffer[INET_ADDRSTRLEN] = {0}; + auto targetName = inet_ntop(AF_INET, &addr.sin_addr, targetNameBuffer, sizeof(targetNameBuffer)); + gLogger->info("Connected to: %s on port %d", targetName, ntohs(addr.sin_port)); + + int flag = 1; + ::setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (const char *) &flag, sizeof(int)); + + client = addClient(new Client(socket)); + added = true; + } + + return client; +} + + +void Server::removeClientInternal(Client *client) +{ + int pos = 0; + + for (pos = 0; pos < mNumClients; pos++) + { + if (mClients[pos] == client) + break; + } + + if (pos < mNumClients) + { + mNumClients--; + + if (pos < mNumClients) + { + // Shift the array left to remove the item + memmove(mClients + pos, + mClients + (pos + 1), + (mNumClients - pos) * sizeof(Client *)); + } + + delete client; client = nullptr; + mClients[mNumClients + 1] = nullptr; + } +} + + +// Removes a client from the client list. +// Because the client can be removed during list iteration, lists +// should always be iterated from last to first. +// +void Server::removeClient(Client *client) +{ + std::lock_guard lock(mListLock); + removeClientInternal(client); +} + + +Client *Server::addClient(Client *client) +{ + std::lock_guard lock(mListLock); + + if (mNumClients < MAX_CLIENTS) + { + mClients[mNumClients] = client; + mNumClients++; + } + else + { + delete client; + client = nullptr; + } + + return client; +} diff --git a/src/server.hpp b/src/server.hpp index 3afc802..28f20b9 100755 --- a/src/server.hpp +++ b/src/server.hpp @@ -1,87 +1,79 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef SERVER_HPP -#define SERVER_HPP - -#include "threading.hpp" - -class Client; - -/* Some constants */ -const int MAX_CLIENTS = 64; - -/* A socket server abstraction */ -class Server -{ -protected: - SOCKET mSocket; - Client *mClients[MAX_CLIENTS + 1]; - int mNumClients; - int mPort; - char mPong[32]; - int mTimeout; - - MTCMutex mListLock; - -protected: - // Assumes the mutex is already locked. - void removeClientInternal(Client *aClient); - - // Locks the mutex. - void removeClient(Client *aClient); - - Client *addClient(Client *aClient); - unsigned int getTimestamp(); - unsigned int deltaTimestamp(unsigned int, unsigned int); - -public: - Server(int aPort, int aHeartbeatFreq); - ~Server(); - - // Returns the new client. - Client *connectToClients(); /* Client factory */ - - /* I/O methods */ - void readFromClients(); /* discard data on read side of - sockets */ - void sendToClients(const char *aString); - void sendToClient(Client *aClient, const char *aString); - - /* Getters */ - int numClients() { return mNumClients; } - bool hasClients() { return mNumClients > 0; } - -}; - -#endif +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include +#include + +class Client; + +const int MAX_CLIENTS = 64; + +// A socket server abstraction +class Server +{ +protected: + SOCKET mSocket; + Client *mClients[MAX_CLIENTS + 1]; + int mNumClients; + int mPort; + char mPong[32]; + std::chrono::milliseconds mTimeout; + + std::mutex mListLock; + +protected: + // Assumes the mutex is already locked. + void removeClientInternal(Client *client); + + // Locks the mutex. + void removeClient(Client *client); + Client *addClient(Client *client); + +public: + Server(int port, std::chrono::milliseconds heartbeatFreq); + ~Server(); + + // Returns the new client. + Client *connectToClients(); // Client factory + + // I/O methods + void readFromClients(); // discard data on read side of sockets + void sendToClients(const char *string); + void sendToClient(Client *client, const char *string); + + /* Getters */ + int numClients() { return mNumClients; } + bool hasClients() { return mNumClients > 0; } + +}; diff --git a/src/service.cpp b/src/service.cpp index 0a008ef..a6eacd0 100644 --- a/src/service.cpp +++ b/src/service.cpp @@ -1,27 +1,63 @@ +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// #include "service.hpp" #include "string.h" + MTConnectService::MTConnectService() : - mIsService(false), mDebug(false) + mName{0}, + mIsService(false), + mDebug(false) { } -void MTConnectService::setName(const char *aName) +void MTConnectService::setName(const char *name) { - strncpy(mName, aName, 78); - mName[79] = '\0'; + strncpy_s(mName, sizeof(mName), name, sizeof(mName) - 1); } void MTConnectService::initialize(int aArgc, const char *aArgv[]) { - if (gLogger == NULL) { - if (mIsService) - gLogger = new ServiceLogger(); - else - gLogger = new Logger(); - } - if (mDebug) - gLogger->setLogLevel(Logger::eDEBUG); + if (!gLogger) + { + if (mIsService) + gLogger = new ServiceLogger(); + else + gLogger = new Logger(); + } + + if (mDebug) + gLogger->setLogLevel(Logger::eDEBUG); } #ifdef WIN32 @@ -31,245 +67,254 @@ void MTConnectService::initialize(int aArgc, const char *aArgv[]) #pragma comment(lib, "advapi32.lib") -#define SVC_ERROR ((DWORD)0xC0000001L) -#define SVC_WARNING ((DWORD)0x90000001L) -#define SVC_INFO ((DWORD)0x50000001L) +#define SVC_ERROR ((DWORD)0xC0000001L) +#define SVC_WARNING ((DWORD)0x90000001L) +#define SVC_INFO ((DWORD)0x50000001L) -SERVICE_STATUS gSvcStatus; -SERVICE_STATUS_HANDLE gSvcStatusHandle; +SERVICE_STATUS gSvcStatus; +SERVICE_STATUS_HANDLE gSvcStatusHandle; -VOID WINAPI SvcCtrlHandler( DWORD ); -VOID WINAPI SvcMain( DWORD, LPTSTR * ); +VOID WINAPI SvcCtrlHandler(DWORD); +VOID WINAPI SvcMain(DWORD, LPTSTR *); -VOID ReportSvcStatus( DWORD, DWORD, DWORD ); -VOID SvcInit( DWORD, LPTSTR * ); -VOID SvcReportEvent( LPTSTR ); +VOID ReportSvcStatus(DWORD, DWORD, DWORD); +VOID SvcInit(DWORD, LPTSTR *); +VOID SvcReportEvent(LPTSTR); -MTConnectService *gService = NULL; +MTConnectService *gService = nullptr; // -// Purpose: +// Purpose: // Entry point for the process // // Parameters: // None -// +// // Return value: // None // -int MTConnectService::main(int argc, const char *argv[]) -{ - // If command-line parameter is "install", install the service. - // Otherwise, the service is probably being started by the SCM. - - if(argc > 1) { - if (stricmp( argv[1], "debug") == 0 ) { - mDebug = true; - } - initialize(argc - 2, argv + 2); - if (stricmp( argv[1], "install") == 0 ) - { - install(argc - 2, argv + 2); - return 0; - } else if (stricmp( argv[1], "remove") == 0 ) { - remove(); - return 0; - } else if (stricmp( argv[1], "debug") == 0) { - gLogger->setLogLevel(Logger::eDEBUG); - start(); - return 0; - } else if (stricmp( argv[1], "run") == 0) { - start(); - return 0; - } - } - - mIsService = true; - SERVICE_TABLE_ENTRY DispatchTable[] = - { - { mName, (LPSERVICE_MAIN_FUNCTION) SvcMain }, - { NULL, NULL } - }; - - gService = this; - - if (!StartServiceCtrlDispatcher( DispatchTable )) - { - SvcReportEvent("StartServiceCtrlDispatcher"); - } - - return 0; -} - -// -// Purpose: +int MTConnectService::main(int argc, const char *argv[]) +{ + // If command-line parameter is "install", install the service. + // Otherwise, the service is probably being started by the SCM. + + if (argc > 1) + { + if (!stricmp(argv[1], "debug")) + mDebug = true; + + initialize(argc - 2, argv + 2); + + if (!stricmp(argv[1], "install")) + { + install(argc - 2, argv + 2); + return 0; + } + else if (!stricmp(argv[1], "remove")) + { + remove(); + return 0; + } + else if (!stricmp(argv[1], "debug")) + { + gLogger->setLogLevel(Logger::eDEBUG); + start(); + return 0; + } + else if (!stricmp(argv[1], "run")) + { + start(); + return 0; + } + } + + mIsService = true; + SERVICE_TABLE_ENTRY DispatchTable[] = + { + { mName, (LPSERVICE_MAIN_FUNCTION) SvcMain }, + { nullptr, nullptr } + }; + + gService = this; + + if (!StartServiceCtrlDispatcherA(DispatchTable)) + SvcReportEvent("StartServiceCtrlDispatcher"); + + return 0; +} + +// +// Purpose: // Installs a service in the SCM database // // Parameters: // None -// +// // Return value: // None // void MTConnectService::install(int argc, const char *argv[]) { - SC_HANDLE schSCManager; - SC_HANDLE schService; - char szPath[MAX_PATH]; - - if( !GetModuleFileName( NULL, szPath, MAX_PATH ) ) - { - printf("Cannot install service (%d)\n", GetLastError()); - return; - } - - // Get a handle to the SCM database. - - schSCManager = OpenSCManager( - NULL, // local computer - NULL, // ServicesActive database - SC_MANAGER_ALL_ACCESS); // full access rights - - if (NULL == schSCManager) - { - printf("OpenSCManager failed (%d)\n", GetLastError()); - return; - } - - schService = OpenService(schSCManager, mName, SC_MANAGER_ALL_ACCESS); - if (schService != NULL) { - if (! ChangeServiceConfig( - schService, // handle of service - SERVICE_WIN32_OWN_PROCESS | - SERVICE_INTERACTIVE_PROCESS, // service type: no change - SERVICE_AUTO_START, // service start type - SERVICE_NO_CHANGE, // error control: no change - szPath, // binary path: no change - NULL, // load order group: no change - NULL, // tag ID: no change - NULL, // dependencies: no change - NULL, // account name: no change - NULL, // password: no change - NULL) ) // display name: no change - { - printf("ChangeServiceConfig failed (%d)\n", GetLastError()); - } - else printf("Service updated successfully.\n"); - } else { - - // Create the service - - schService = CreateService( - schSCManager, // SCM database - mName, // name of service - mName, // service name to display - SERVICE_ALL_ACCESS, // desired access - SERVICE_WIN32_OWN_PROCESS | - SERVICE_INTERACTIVE_PROCESS, // service type - SERVICE_AUTO_START, // start type - SERVICE_ERROR_NORMAL, // error control type - szPath, // path to service's binary - NULL, // no load ordering group - NULL, // no tag identifier - NULL, // no dependencies - NULL, // LocalSystem account - NULL); // no password - - if (schService == NULL) - { - printf("CreateService failed (%d)\n", GetLastError()); - CloseServiceHandle(schSCManager); - return; - } - else printf("Service installed successfully\n"); - } - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - - HKEY software; - LONG res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE", &software); - if (res != ERROR_SUCCESS) - { - printf("Could not open software key: %d\n", res); - return; - } - - HKEY mtc; - res = RegOpenKey(software, "MTConnect", &mtc); - if (res != ERROR_SUCCESS) - { - //printf("Could not open MTConnect, creating: %d\n", res); - res = RegCreateKey(software, "MTConnect", &mtc); - if (res != ERROR_SUCCESS) - { - RegCloseKey(software); - printf("Could not create MTConnect: %d\n", res); - return; - } - } - RegCloseKey(software); - - // Create Service Key - HKEY adapter; - res = RegOpenKey(mtc, mName, &adapter); - if (res != ERROR_SUCCESS) - { - //printf("Could not open %s, creating: %d\n", mName, res); - res = RegCreateKey(mtc, mName, &adapter); - if (res != ERROR_SUCCESS) - { - RegCloseKey(mtc); - printf("Could not create %s: %d\n", mName, res); - return; - } - } - RegCloseKey(mtc); - - char arguments[2048]; - // TODO: create registry entries for arguments to be passed in later to create the adapter multi_sz - int d = 0; - for (int i = 0; i < argc; i++) { - strcpy(arguments + d, argv[i]); - d += strlen(arguments + d) + 1; - } - - arguments[d] = '\0'; - RegSetValueEx(adapter, "Arguments", 0, REG_MULTI_SZ, (const BYTE*) arguments, d); - RegCloseKey(adapter); + char szPath[MAX_PATH] = {0}; + if (!GetModuleFileNameA(nullptr, szPath, MAX_PATH)) + { + printf("Cannot install service (%d)\n", GetLastError()); + return; + } + + // Get a handle to the SCM database. + auto schSCManager = OpenSCManagerA( + nullptr, // local computer + nullptr, // ServicesActive database + SC_MANAGER_ALL_ACCESS); // full access rights + + if (!schSCManager) + { + printf("OpenSCManager failed (%d)\n", GetLastError()); + return; + } + + auto schService = OpenServiceA(schSCManager, mName, SC_MANAGER_ALL_ACCESS); + if (schService) + { + if (! ChangeServiceConfigA( + schService, // handle of service + SERVICE_WIN32_OWN_PROCESS | + SERVICE_INTERACTIVE_PROCESS, // service type: no change + SERVICE_AUTO_START, // service start type + SERVICE_NO_CHANGE, // error control: no change + szPath, // binary path: no change + nullptr, // load order group: no change + nullptr, // tag ID: no change + nullptr, // dependencies: no change + nullptr, // account name: no change + nullptr, // password: no change + nullptr) ) // display name: no change + { + printf("ChangeServiceConfig failed (%d)\n", GetLastError()); + } + else + printf("Service updated successfully.\n"); + } + else + { + // Create the service + schService = CreateServiceA( + schSCManager, // SCM database + mName, // name of service + mName, // service name to display + SERVICE_ALL_ACCESS, // desired access + SERVICE_WIN32_OWN_PROCESS | + SERVICE_INTERACTIVE_PROCESS, // service type + SERVICE_AUTO_START, // start type + SERVICE_ERROR_NORMAL, // error control type + szPath, // path to service's binary + nullptr, // no load ordering group + nullptr, // no tag identifier + nullptr, // no dependencies + nullptr, // LocalSystem account + nullptr); // no password + + if (!schService) + { + printf("CreateService failed (%d)\n", GetLastError()); + CloseServiceHandle(schSCManager); + return; + } + else + printf("Service installed successfully\n"); + } + + CloseServiceHandle(schService); schService = nullptr; + CloseServiceHandle(schSCManager); schSCManager = nullptr; + + HKEY software(nullptr); + auto res = RegOpenKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE", &software); + if (res != ERROR_SUCCESS) + { + printf("Could not open software key: %d\n", res); + return; + } + + HKEY mtc(nullptr); + res = RegOpenKeyA(software, "MTConnect", &mtc); + if (res != ERROR_SUCCESS) + { + //printf("Could not open MTConnect, creating: %d\n", res); + res = RegCreateKeyA(software, "MTConnect", &mtc); + if (res != ERROR_SUCCESS) + { + RegCloseKey(software); + printf("Could not create MTConnect: %d\n", res); + return; + } + } + + RegCloseKey(software); + + // Create Service Key + HKEY adapter(nullptr); + res = RegOpenKeyA(mtc, mName, &adapter); + if (res != ERROR_SUCCESS) + { + //printf("Could not open %s, creating: %d\n", mName, res); + res = RegCreateKeyA(mtc, mName, &adapter); + if (res != ERROR_SUCCESS) + { + RegCloseKey(mtc); + printf("Could not create %s: %d\n", mName, res); + return; + } + } + + RegCloseKey(mtc); + + char arguments[2048] = {0}; + // TODO: create registry entries for arguments to be passed in later to create the adapter multi_sz + int d = 0; + for (int i = 0; i < argc; i++) + { + strcpy_s(arguments + d, 2048 - d, argv[i]); + d += strlen(arguments + d) + 1; + } + + arguments[d] = '\0'; + RegSetValueExA(adapter, "Arguments", 0, REG_MULTI_SZ, (const BYTE *) arguments, d); + RegCloseKey(adapter); } + void MTConnectService::remove() { - SC_HANDLE manager; - SC_HANDLE service; - manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); - - if (manager == NULL) { - printf("Could not open Service Control Manager"); - return; - } - service = ::OpenService(manager, mName, SERVICE_ALL_ACCESS); - CloseServiceHandle(manager); - if (service == NULL) { - printf("Could not open Service "); - return; - } - - if(::DeleteService(service) == 0) { - printf("Could delete service %s\n", mName); - } else { - printf("Successfully removed service %s\n", mName); - } - - ::CloseServiceHandle(service); + auto manager = OpenSCManagerA(nullptr, nullptr, SC_MANAGER_ALL_ACCESS); + if (!manager) + { + printf("Could not open Service Control Manager"); + return; + } + + auto service = ::OpenServiceA(manager, mName, SERVICE_ALL_ACCESS); + CloseServiceHandle(manager); + + if (!service) + { + printf("Could not open Service "); + return; + } + + if (!::DeleteService(service)) + printf("Could delete service %s\n", mName); + else + printf("Successfully removed service %s\n", mName); + + ::CloseServiceHandle(service); } // -// Purpose: +// Purpose: // Entry point for the service // // Parameters: @@ -277,55 +322,55 @@ void MTConnectService::remove() // lpszArgv - Array of strings. The first string is the name of // the service and subsequent strings are passed by the process // that called the StartService function to start the service. -// +// // Return value: // None. // -VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv ) +VOID WINAPI SvcMain(DWORD dwArgc, LPTSTR *lpszArgv) { - // Register the handler function for the service - char path[MAX_PATH]; - if( !GetModuleFileName(NULL, path, MAX_PATH ) ) - { - printf("Cannot get path of executable (%d)\n", GetLastError()); - return; - } - - char *cp = strrchr(path, '\\'); - if (cp != NULL) - { - *cp = '\0'; - SetCurrentDirectory(path); - } - - gService->setName(lpszArgv[0]); - gSvcStatusHandle = RegisterServiceCtrlHandler( - gService->name(), - SvcCtrlHandler); - - if( !gSvcStatusHandle ) - { - SvcReportEvent("RegisterServiceCtrlHandler"); - return; - } - - // These SERVICE_STATUS members remain as set here - - gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - gSvcStatus.dwServiceSpecificExitCode = 0; - - // Report initial status to the SCM - - ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 10000 ); - - // Perform service-specific initialization and work. - Sleep(20000); - - SvcInit( dwArgc, lpszArgv ); + // Register the handler function for the service + char path[MAX_PATH] = {0}; + + if (!GetModuleFileNameA(nullptr, path, MAX_PATH)) + { + printf("Cannot get path of executable (%d)\n", GetLastError()); + return; + } + + auto cp = strrchr(path, '\\'); + if (cp != nullptr) + { + *cp = '\0'; + SetCurrentDirectoryA(path); + } + + gService->setName(lpszArgv[0]); + gSvcStatusHandle = RegisterServiceCtrlHandlerA( + gService->name(), + SvcCtrlHandler); + + if (!gSvcStatusHandle) + { + SvcReportEvent("RegisterServiceCtrlHandler"); + return; + } + + // These SERVICE_STATUS members remain as set here + gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + gSvcStatus.dwServiceSpecificExitCode = 0; + + // Report initial status to the SCM + ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 10000ul); + + // Perform service-specific initialization and work. + Sleep(20000); + + SvcInit(dwArgc, lpszArgv); } + // -// Purpose: +// Purpose: // The service code // // Parameters: @@ -333,250 +378,271 @@ VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv ) // lpszArgv - Array of strings. The first string is the name of // the service and subsequent strings are passed by the process // that called the StartService function to start the service. -// +// // Return value: // None // -VOID SvcInit( DWORD dwArgc, LPTSTR *lpszArgv) +VOID SvcInit(DWORD dwArgc, LPTSTR *lpszArgv) { - // Get the real arguments from the registry - char key[1024]; - snprintf(key, 1022, "SOFTWARE\\MTConnect\\%s", gService->name()); - key[1023] = '\0'; - - HKEY adapter; - LONG res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &adapter); - if (res != ERROR_SUCCESS) - { - SvcReportEvent("RegOpenKey: Could not open Adapter"); - ReportSvcStatus( SERVICE_STOPPED, 1, 0 ); - return; - } - - char *argp[64]; - BYTE arguments[2048]; - DWORD len = 2047, type, argc = 0; - res = RegQueryValueEx(adapter, "Arguments", 0, &type, (BYTE*) arguments, &len); - if (res == ERROR_SUCCESS) - { - DWORD i = 0; - while (i < len) { - argp[argc] = (char*) arguments + i; - i += strlen((char*) arguments + i) + 1; - argc++; - } - argp[argc] = 0; - } else { - SvcReportEvent("RegOpenKey: Could not get Arguments"); - RegCloseKey(adapter); - ReportSvcStatus( SERVICE_STOPPED, 1, 0 ); - return; - } - - gService->initialize(argc, (const char**) argp); - - // TO_DO: Declare and set any required variables. - // Be sure to periodically call ReportSvcStatus() with - // SERVICE_START_PENDING. If initialization fails, call - // ReportSvcStatus with SERVICE_STOPPED. - - // Create an event. The control handler function, SvcCtrlHandler, - // signals this event when it receives the stop control code. - - // Report running status when initialization is complete. - - ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 ); - - // TO_DO: Perform work until service stops. - gService->start(); - - ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 ); + // Get the real arguments from the registry + char key[1024] = {0}; + snprintf(key, 1022, "SOFTWARE\\MTConnect\\%s", gService->name()); + key[1023] = '\0'; + + HKEY adapter(nullptr); + auto res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &adapter); + if (res != ERROR_SUCCESS) + { + SvcReportEvent("RegOpenKey: Could not open Adapter"); + ReportSvcStatus(SERVICE_STOPPED, 1ul, 0ul); + return; + } + + char *argp[64] = {0}; + BYTE arguments[2048] = {0}; + DWORD len = 2047ul, type, argc = 0ul; + res = RegQueryValueExA(adapter, "Arguments", 0, &type, (BYTE *) arguments, &len); + if (res == ERROR_SUCCESS) + { + DWORD i = 0ul; + while (i < len) + { + argp[argc] = (char *) arguments + i; + i += strlen((char *) arguments + i) + 1ul; + argc++; + } + + argp[argc] = 0; + } + else + { + SvcReportEvent("RegOpenKey: Could not get Arguments"); + RegCloseKey(adapter); + ReportSvcStatus(SERVICE_STOPPED, 1ul, 0ul); + return; + } + + gService->initialize(argc, (const char **) argp); + + // TO_DO: Declare and set any required variables. + // Be sure to periodically call ReportSvcStatus() with + // SERVICE_START_PENDING. If initialization fails, call + // ReportSvcStatus with SERVICE_STOPPED. + + // Create an event. The control handler function, SvcCtrlHandler, + // signals this event when it receives the stop control code. + + // Report running status when initialization is complete. + ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0ul); + + // TO_DO: Perform work until service stops. + gService->start(); + ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0ul); } + // -// Purpose: +// Purpose: // Sets the current service status and reports it to the SCM. // // Parameters: // dwCurrentState - The current state (see SERVICE_STATUS) // dwWin32ExitCode - The system error code -// dwWaitHint - Estimated time for pending operation, +// dwWaitHint - Estimated time for pending operation, // in milliseconds -// +// // Return value: // None // -VOID ReportSvcStatus( DWORD dwCurrentState, - DWORD dwWin32ExitCode, - DWORD dwWaitHint) +VOID ReportSvcStatus( + DWORD dwCurrentState, + DWORD dwWin32ExitCode, + DWORD dwWaitHint) { - static DWORD dwCheckPoint = 1; + static DWORD dwCheckPoint = 1ul; - // Fill in the SERVICE_STATUS structure. + // Fill in the SERVICE_STATUS structure. - gSvcStatus.dwCurrentState = dwCurrentState; - gSvcStatus.dwWin32ExitCode = dwWin32ExitCode; - gSvcStatus.dwWaitHint = dwWaitHint; + gSvcStatus.dwCurrentState = dwCurrentState; + gSvcStatus.dwWin32ExitCode = dwWin32ExitCode; + gSvcStatus.dwWaitHint = dwWaitHint; - if (dwCurrentState == SERVICE_START_PENDING) - gSvcStatus.dwControlsAccepted = 0; - else - gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + if (dwCurrentState == SERVICE_START_PENDING) + gSvcStatus.dwControlsAccepted = 0; + else + gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; - if ( (dwCurrentState == SERVICE_RUNNING) || - (dwCurrentState == SERVICE_STOPPED) ) - gSvcStatus.dwCheckPoint = 0; - else - gSvcStatus.dwCheckPoint = dwCheckPoint++; + if (dwCurrentState == SERVICE_RUNNING || + dwCurrentState == SERVICE_STOPPED ) + { + gSvcStatus.dwCheckPoint = 0; + } + else + gSvcStatus.dwCheckPoint = dwCheckPoint++; - // Report the status of the service to the SCM. - SetServiceStatus( gSvcStatusHandle, &gSvcStatus ); + // Report the status of the service to the SCM. + SetServiceStatus(gSvcStatusHandle, &gSvcStatus); } + // -// Purpose: +// Purpose: // Called by SCM whenever a control code is sent to the service // using the ControlService function. // // Parameters: // dwCtrl - control code -// +// // Return value: // None // -VOID WINAPI SvcCtrlHandler( DWORD dwCtrl ) +VOID WINAPI SvcCtrlHandler(DWORD dwCtrl) { - // Handle the requested control code. + // Handle the requested control code. + + switch (dwCtrl) + { + case SERVICE_CONTROL_STOP: + ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0ul); + + if (gService) + gService->stop(); - switch(dwCtrl) - { - case SERVICE_CONTROL_STOP: - ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); - if (gService != NULL) - gService->stop(); - ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0); + ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0ul); - return; + return; - case SERVICE_CONTROL_INTERROGATE: - break; + case SERVICE_CONTROL_INTERROGATE: + break; - default: - break; - } + default: + break; + } } + // -// Purpose: +// Purpose: // Logs messages to the event log // // Parameters: // szFunction - name of function that failed -// +// // Return value: // None // // Remarks: // The service must have an entry in the Application event log. // -VOID SvcReportEvent(LPTSTR szFunction) -{ - HANDLE hEventSource; - LPCTSTR lpszStrings[2]; - char Buffer[80]; - - hEventSource = RegisterEventSource(NULL, gService->name()); - - if( NULL != hEventSource ) - { - sprintf(Buffer, "%-60s failed with %d", szFunction, GetLastError()); - - lpszStrings[0] = gService->name(); - lpszStrings[1] = Buffer; - - ReportEvent(hEventSource, // event log handle - EVENTLOG_ERROR_TYPE, // event type - 0, // event category - SVC_ERROR, // event identifier - NULL, // no security identifier - 2, // size of lpszStrings array - 0, // no binary data - lpszStrings, // array of strings - NULL); // no binary data - - DeregisterEventSource(hEventSource); - } +VOID SvcReportEvent(LPTSTR functionName) +{ + HANDLE hEventSource(nullptr); + LPCTSTR lpszStrings[2] = {nullptr, nullptr}; + char Buffer[80] = {0}; + + hEventSource = RegisterEventSourceA(nullptr, gService->name()); + + if (hEventSource) + { + snprintf(Buffer, _countof(Buffer), "%-60s failed with %d", functionName, GetLastError()); + + lpszStrings[0] = gService->name(); + lpszStrings[1] = Buffer; + + ReportEventA(hEventSource, // event log handle + EVENTLOG_ERROR_TYPE, // event type + 0, // event category + SVC_ERROR, // event identifier + nullptr, // no security identifier + 2, // size of lpszStrings array + 0ul, // no binary data + lpszStrings, // array of strings + nullptr); // no binary data + + DeregisterEventSource(hEventSource); + } } -VOID SvcLogEvent(WORD aType, DWORD aId, LPSTR aText) -{ - HANDLE hEventSource; - LPCTSTR lpszStrings[3]; - - hEventSource = RegisterEventSource(NULL, gService->name()); - - if( NULL != hEventSource ) - { - lpszStrings[0] = gService->name(); - lpszStrings[1] = "\n\n"; - lpszStrings[2] = aText; - - ReportEvent(hEventSource, // event log handle - aType, // event type - 0, // event category - aId, // event identifier - NULL, // no security identifier - 3, // size of lpszStrings array - 0, // no binary data - lpszStrings, // array of strings - NULL); // no binary data - - DeregisterEventSource(hEventSource); - } + +VOID SvcLogEvent(WORD type, DWORD id, LPSTR text) +{ + HANDLE hEventSource(nullptr); + LPCTSTR lpszStrings[3] = {nullptr}; + + hEventSource = RegisterEventSourceA(nullptr, gService->name()); + if (hEventSource) + { + lpszStrings[0] = gService->name(); + lpszStrings[1] = "\n\n"; + lpszStrings[2] = text; + + ReportEventA(hEventSource, // event log handle + type, // event type + 0, // event category + id, // event identifier + nullptr, // no security identifier + 3, // size of lpszStrings array + 0, // no binary data + lpszStrings, // array of strings + nullptr); // no binary data + + DeregisterEventSource(hEventSource); + } } -void ServiceLogger::error(const char *aFormat, ...) +void ServiceLogger::error(const char *inputFormat, ...) { - char buffer[LOGGER_BUFFER_SIZE]; - va_list args; - va_start (args, aFormat); - SvcLogEvent(EVENTLOG_ERROR_TYPE, SVC_ERROR, (LPSTR) format(buffer, LOGGER_BUFFER_SIZE, aFormat, args)); - va_end (args); + char buffer[LOGGER_BUFFER_SIZE] = {0}; + va_list args; + va_start(args, inputFormat); + SvcLogEvent( + EVENTLOG_ERROR_TYPE, + SVC_ERROR, + (LPSTR)format(buffer, LOGGER_BUFFER_SIZE, inputFormat, args)); + va_end(args); } -void ServiceLogger::warning(const char *aFormat, ...) + +void ServiceLogger::warning(const char *inputFormat, ...) { - char buffer[LOGGER_BUFFER_SIZE]; - va_list args; - va_start (args, aFormat); - SvcLogEvent(EVENTLOG_WARNING_TYPE, SVC_WARNING, (LPSTR) format(buffer, LOGGER_BUFFER_SIZE, aFormat, args)); - va_end (args); + char buffer[LOGGER_BUFFER_SIZE] = {0}; + va_list args; + va_start(args, inputFormat); + SvcLogEvent( + EVENTLOG_WARNING_TYPE, + SVC_WARNING, (LPSTR)format(buffer, LOGGER_BUFFER_SIZE, inputFormat, args)); + va_end(args); } -void ServiceLogger::info(const char *aFormat, ...) + +void ServiceLogger::info(const char *inputFormat, ...) { - char buffer[LOGGER_BUFFER_SIZE]; - va_list args; - va_start (args, aFormat); - SvcLogEvent(EVENTLOG_INFORMATION_TYPE, SVC_INFO, (LPSTR) format(buffer, LOGGER_BUFFER_SIZE, aFormat, args)); - va_end (args); + char buffer[LOGGER_BUFFER_SIZE] = {0}; + va_list args; + va_start(args, inputFormat); + SvcLogEvent( + EVENTLOG_INFORMATION_TYPE, + SVC_INFO, + (LPSTR) format(buffer, LOGGER_BUFFER_SIZE, inputFormat, args)); + va_end(args); } -void ServiceLogger::debug(const char *aFormat, ...) + +void ServiceLogger::debug(const char *inputFormat, ...) { - // Debug service logging is not supported + // Debug service logging is not supported } #else -int MTConnectService::main(int argc, const char *argv[]) -{ - initialize(argc - 1, argv + 1); - start(); - return 0; -} +int MTConnectService::main(int argc, const char *argv[]) +{ + initialize(argc - 1, argv + 1); + start(); + return 0; +} void MTConnectService::install(int argc, const char *argv[]) { diff --git a/src/service.hpp b/src/service.hpp index 1409f1d..6f193a7 100644 --- a/src/service.hpp +++ b/src/service.hpp @@ -1,41 +1,77 @@ -#ifndef SERVICE_HPP -#define SERVICE_HPP - -#include "logger.hpp" - -#define SERVICE_NAME_LEN 80 - -class MTConnectService { -public: - MTConnectService(); - virtual int main(int aArgc, const char *aArgv[]); - virtual void initialize(int aArgc, const char *aArgv[]) = 0; - - void setName(const char *aName); - virtual void stop() = 0; - virtual void start() = 0; - const char *name() { return mName; } - -protected: - char mName[SERVICE_NAME_LEN]; - bool mIsService; - bool mDebug; - - void install(int argc, const char *argv[]); - void remove(); -}; - -#ifdef WIN32 -class ServiceLogger : public Logger { -public: - virtual void error(const char *aFormat, ...); - virtual void warning(const char *aFormat, ...); - virtual void info(const char *aFormat, ...); - virtual void debug(const char *aFormat, ...); - -protected: -}; -#else -class ServiceLogger : public Logger {}; -#endif -#endif +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include "logger.hpp" + +#define SERVICE_NAME_LEN 80 + + +class MTConnectService +{ +public: + MTConnectService(); + + virtual int main(int argc, const char *argv[]); + virtual void initialize(int argc, const char *argv[]) = 0; + virtual void stop() = 0; + virtual void start() = 0; + + void setName(const char *name); + const char *name() const { + return mName; } + +protected: + char mName[SERVICE_NAME_LEN]; + bool mIsService; + bool mDebug; + + void install(int argc, const char *argv[]); + void remove(); +}; + + +#ifdef WIN32 + class ServiceLogger : public Logger + { + public: + void error(const char *inputFormat, ...) override; + void warning(const char *inputFormat, ...) override; + void info(const char *inputFormat, ...) override; + void debug(const char *inputFormat, ...) override; + + protected: + }; +#else + class ServiceLogger : public Logger {}; +#endif diff --git a/src/string_array.cpp b/src/string_array.cpp index 1ef1ed2..b95e5d6 100644 --- a/src/string_array.cpp +++ b/src/string_array.cpp @@ -1,80 +1,119 @@ - -#include "internal.hpp" -#include "string_array.hpp" - -#define BLOCK_SIZE 256 - -StringArray::StringArray() -{ - mLength = 0; - mSize = BLOCK_SIZE; - mArray = (char **) malloc(sizeof(char*) * mSize); - mArray[mLength = 0]; -} - -StringArray::~StringArray() -{ - clear(); - free(mArray); -} - -void StringArray::clear() -{ - for (int i = 0; i < mLength; i++) - free(mArray[i]); - mLength = 0; -} - -void StringArray::append(const char *aString) -{ - char *dup = strdup(aString); - if (dup == 0) - { - perror("StringArray::append"); - exit(2); - } - - if (mLength >= mSize - 1) - { - mSize += BLOCK_SIZE; - mArray = (char**) realloc(mArray, mSize * sizeof(char*)); - if (mArray == 0) - { - perror("StringArray::append"); - exit(2); - } - } - - mArray[mLength++] = dup; -} - -int StringArray::readFile(const char *aFileName) -{ - // First clear out existing contents - clear(); - - // Parse file. - FILE *file = fopen(aFileName, "r"); - if (file == 0) - { - printf("Could not open file: %s\n", aFileName); - } - else - { - printf("Parsing file: %s\n", aFileName); - char buffer[1024]; - while (fgets(buffer, 1024, file) != 0) - { - int last = strlen(buffer) - 1; - if (last > 0 && buffer[last] == '\n') - buffer[last] = 0; - append(buffer); - } - } - return mLength; -} - - - - - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#include "internal.hpp" +#include "string_array.hpp" + +#define BLOCK_SIZE 256 + + +StringArray::StringArray() +{ + mLength = 0; + mSize = BLOCK_SIZE; + mArray = (char **) malloc(sizeof(char *) * mSize); + mArray[mLength = 0]; +} + + +StringArray::~StringArray() +{ + clear(); + free(mArray); + mArray = nullptr; +} + + +void StringArray::clear() +{ + for (int i = 0; i < mLength; i++) + free(mArray[i]); + + mLength = 0; +} + + +void StringArray::append(const char *string) +{ + char *dup = strdup(string); + + if (!dup) + { + perror("StringArray::append"); + exit(2); + } + + if (mLength >= mSize - 1) + { + mSize += BLOCK_SIZE; + mArray = (char **) realloc(mArray, mSize * sizeof(char *)); + + if (!mArray) + { + perror("StringArray::append"); + exit(2); + } + } + + mArray[mLength++] = dup; +} + + +int StringArray::readFile(const char *fileName) +{ + // First clear out existing contents + clear(); + + // Parse file. + auto file = fopen(fileName, "r"); + + if (!file) + printf("Could not open file: %s\n", fileName); + else + { + printf("Parsing file: %s\n", fileName); + char buffer[1024] = {0}; + + while (fgets(buffer, 1024, file) != 0) + { + int last = strlen(buffer) - 1; + + if (last > 0 && buffer[last] == '\n') + buffer[last] = 0; + + append(buffer); + } + } + + return mLength; +} + diff --git a/src/string_array.hpp b/src/string_array.hpp index 5fd990c..db85b7e 100755 --- a/src/string_array.hpp +++ b/src/string_array.hpp @@ -1,80 +1,74 @@ - -/* -* Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef STRING_ARRAY_HPP -#define STRING_ARRAY_HPP - -/* - * A string array that atomaticially resizes when the size is - * exceeded. Used for storing the program codes - */ - -class StringArray -{ -protected: - char **mArray; - int mLength; - int mSize; - -public: - StringArray(); - ~StringArray(); - - int length() { return mLength; } - - // Copies the string when it is appended - void append(const char *aString); - void clear(); - - // Getters - const char *stringAt(int index); - const char *operator[](int index) { return stringAt(index); } - - // File Handler method, should be another class... - // Returns file size. - int readFile(const char *aFileName); -}; - -inline const char *StringArray::stringAt(int index) -{ - if (index >= 0 && index < mLength) - return mArray[index]; - else - return 0; -} - -#endif - - - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +// +// A string array that atomaticially resizes when the size is +// exceeded. Used for storing the program codes +// +class StringArray +{ +protected: + char **mArray; + int mLength; + int mSize; + +public: + StringArray(); + ~StringArray(); + + int length() const { + return mLength; } + + // Copies the string when it is appended + void append(const char *string); + void clear(); + + // Getters + const char *stringAt(int index) const; + const char *operator[](int index) const { + return stringAt(index); } + + // File Handler method, should be another class... + // Returns file size. + int readFile(const char *fileName); +}; + + +inline const char *StringArray::stringAt(int index) const +{ + if (index >= 0 && index < mLength) + return mArray[index]; + else + return nullptr; +} diff --git a/src/string_buffer.cpp b/src/string_buffer.cpp index e582230..12388f7 100755 --- a/src/string_buffer.cpp +++ b/src/string_buffer.cpp @@ -1,121 +1,118 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#include "internal.hpp" -#include "string_buffer.hpp" - -StringBuffer::StringBuffer(const char *aString) -{ - mLength = mSize = 0; - mTimestamp[0] = 0; - if (aString != 0) - { - append(aString); - } - else - { - mBuffer = 0; - } -} - -StringBuffer::~StringBuffer() -{ - if (mBuffer != 0) - free(mBuffer); -} - -const char *StringBuffer::append(const char* aString) -{ - /* Include additional length for timestamp */ - size_t len = strlen(aString); - size_t totalLength = mLength + len; - size_t tsLen = strlen(mTimestamp); - if (mLength == 0) - totalLength += tsLen; - if (totalLength >= mSize) - { - size_t newLen = ((totalLength / 1024) + 1) * 1024; - char *newBuffer = (char*) malloc(newLen); - memcpy(newBuffer, mBuffer, mLength); - - free(mBuffer); - mBuffer = newBuffer; - mSize = newLen; - } - - if (mLength == 0 && tsLen > 0) - { - strcpy(mBuffer, mTimestamp); - mLength += tsLen; - } - - strcpy(mBuffer + mLength, aString); - mLength += len; - - return mBuffer; -} - -void StringBuffer::newline() -{ - append("\n"); - append(mTimestamp); -} - -void StringBuffer::reset() -{ - if (mBuffer != 0) - { - mBuffer[0] = 0; - mLength = 0; - } -} - -void StringBuffer::timestamp() -{ -#ifdef WIN32 - SYSTEMTIME st; - GetSystemTime(&st); - sprintf(mTimestamp, "%4d-%02d-%02dT%02d:%02d:%02d.%03dZ", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); -#else - struct timeval tv; - struct timezone tz; - - gettimeofday(&tv, &tz); - - strftime(mTimestamp, 64, "%Y-%m-%dT%H:%M:%S", gmtime(&tv.tv_sec)); - sprintf(mTimestamp + strlen(mTimestamp), ".%06dZ", tv.tv_usec); -#endif -} - - - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#include "internal.hpp" +#include "string_buffer.hpp" +#ifdef min + #undef min +#endif +#ifdef max + #undef max +#endif +#include + +StringBuffer::StringBuffer(const char *string) : + mBuffer(nullptr), + mSize(0u), + mLength(0u) +{ + if (string) + append(string); +} + + +StringBuffer::~StringBuffer() +{ + if (mBuffer) + { + free(mBuffer); + mBuffer = nullptr; + } +} + + +const char *StringBuffer::append(const char *string) +{ + // Include additional length for timestamp + auto len = strlen(string); + auto totalLength = mLength + len; + auto tsLen = mTimestamp.size(); + + if (!mLength) + totalLength += tsLen; + + if (totalLength >= mSize) + { + auto newLen = ((totalLength / 1024u) + 1u) * 1024u; + auto newBuffer = (char *) malloc(newLen); + memcpy(newBuffer, mBuffer, mLength); + + free(mBuffer); + mBuffer = newBuffer; + mSize = newLen; + } + + if (!mLength && tsLen > 0) + { + strcpy(mBuffer, mTimestamp.c_str()); + mLength += tsLen; + } + + strcpy(mBuffer + mLength, string); + mLength += len; + + return mBuffer; +} + + +void StringBuffer::newline() +{ + append("\n"); + append(mTimestamp.c_str()); +} + + +void StringBuffer::reset() +{ + if (mBuffer) + { + mBuffer[0] = 0; + mLength = 0u; + } +} + + +void StringBuffer::timestamp() +{ + mTimestamp = date::format("%FT%TZ", + std::chrono::time_point_cast(std::chrono::system_clock::now())); +} diff --git a/src/string_buffer.hpp b/src/string_buffer.hpp index 0ec5292..9b04966 100755 --- a/src/string_buffer.hpp +++ b/src/string_buffer.hpp @@ -1,66 +1,68 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef STRING_BUFFER_HPP -#define STRING_BUFFER_HPP - -/* - * A simple extensible string that can be appended to. The memory will be reused - * since it maintains its length. The string buffer also supports setting a timestamp - * that will be prepended to the string once some data is appended. - * - * Currently allocating in 1k increments. - */ -class StringBuffer -{ -protected: - char *mBuffer; /* A resizable character buffer */ - size_t mSize; /* The allocated size of the string */ - size_t mLength; /* The length of the string */ - char mTimestamp[64]; - -public: - StringBuffer(const char *aString = 0); - ~StringBuffer(); - - operator const char *() { return mBuffer; } - const char *append(const char *aString); - const char* operator<<(const char *aString) { return append(aString); } - void reset(); - void timestamp(); - void setTimestamp(const char *aTs) { strcpy(mTimestamp, aTs); } - size_t length() { return mLength; } - void newline(); -}; - -#endif +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once +#include + +// +// A simple extensible string that can be appended to. The memory will be reused +// since it maintains its length. The string buffer also supports setting a timestamp +// that will be prepended to the string once some data is appended. +// +// Currently allocating in 1k increments. +// +class StringBuffer +{ +protected: + char *mBuffer; // A resizable character buffer + size_t mSize; // The allocated size of the string + size_t mLength; // The length of the string + std::string mTimestamp; + + +public: + StringBuffer(const char *string = nullptr); + ~StringBuffer(); + + operator const char *() const { + return mBuffer; } + const char *append(const char *string); + const char *operator<<(const char *string) { + return append(string); } + void reset(); + void timestamp(); + void setTimestamp(const char *timestamp) { + mTimestamp = timestamp; } + size_t length() const { + return mLength; } + void newline(); +}; diff --git a/src/threading.hpp b/src/threading.hpp index 65d946b..1dc8cbb 100644 --- a/src/threading.hpp +++ b/src/threading.hpp @@ -1,119 +1,104 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef THREADING_HPP -#define THREADING_HPP - -#ifdef THREADED - -#ifndef WIN32 -#include -#endif - -class MTCMutex -{ -public: - MTCMutex() { -#ifdef WIN32 - InitializeCriticalSection(&mLock); -#else - pthread_mutex_init(&mLock, NULL); -#endif - } - - ~MTCMutex() { -#ifdef WIN32 - DeleteCriticalSection(&mLock); -#else - pthread_mutex_destroy(&mLock); -#endif - } - - void lock() { -#ifdef WIN32 - EnterCriticalSection(&mLock); -#else - pthread_mutex_lock(&mLock); -#endif - } - - void unlock() { -#ifdef WIN32 - LeaveCriticalSection(&mLock); -#else - pthread_mutex_unlock(&mLock); -#endif - } - -protected: -#ifdef WIN32 - CRITICAL_SECTION mLock; -#else - pthread_mutex_t mLock; -#endif - -private: - MTCMutex(const MTCMutex& aMutex) { - // No copy constructor is possible - } -}; - -#else // Not threaded - -class MTCMutex -{ -public: - void lock() {} - void unlock() {} -}; - -#endif - -class MTCAutoLock { -public: - MTCAutoLock(MTCMutex &aMutex) : mMutex(&aMutex) { - mMutex->lock(); - } - - ~MTCAutoLock() { - mMutex->unlock(); - } - -protected: - MTCMutex *mMutex; - -private: - MTCAutoLock() : mMutex(NULL) {} -}; - -#endif \ No newline at end of file +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#ifdef THREADED + +#include + + +class MTCMutex +{ +public: + MTCMutex() + { + } + + ~MTCMutex() + { + } + + void lock() + { + m_Mutex.lock(); + } + + void unlock() + { + m_Mutex.unlock(); + } + +protected: + std::mutex m_Mutex; + +private: + MTCMutex(const MTCMutex& aMutex) + { + // No copy constructor is possible + } +}; + +#else // Not threaded + +class MTCMutex +{ +public: + void lock() {} + void unlock() {} +}; + +#endif + +class MTCAutoLock +{ +public: + MTCAutoLock(MTCMutex &aMutex) : + mMutex(&aMutex) + { + mMutex->lock(); + } + + ~MTCAutoLock() + { + mMutex->unlock(); + } + +protected: + MTCMutex *mMutex; + +private: + MTCAutoLock() : + mMutex(nullptr) + { + } +}; diff --git a/src/time_series.cpp b/src/time_series.cpp index 2380c6c..659aa9b 100644 --- a/src/time_series.cpp +++ b/src/time_series.cpp @@ -1,115 +1,120 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#include "internal.hpp" -#include "time_series.hpp" -#include "string_buffer.hpp" - -using namespace std; - -/* - * TimeSeries methods - */ -TimeSeries::TimeSeries(const char *aName, float aEpsilon, float aRate) - : DeviceDatum(aName), mEpsilon(aEpsilon), mRate(aRate) -{ - mUnavailable = false; -} - -void TimeSeries::addValue(float aValue) -{ - mValues.push_back(aValue); - - mChanged = true; - mHasValue = true; - mUnavailable = false; -} - -bool TimeSeries::setValue(std::vector aValues) -{ - mValues = aValues; - - mChanged = true; - mHasValue = true; - mUnavailable = false; - - return true; -} - -bool TimeSeries::append(StringBuffer &aStringBuffer) -{ - char buffer[1024]; - if (mUnavailable) - { - snprintf(buffer, 1023, "|%s|0||UNAVAILABLE", mName); - aStringBuffer.append(buffer); - } - else - { - if (mRate > 0) - snprintf(buffer, 1023, "|%s|%d|%g|", mName, (int) mValues.size(), mRate); - else - snprintf(buffer, 1023, "|%s|%d||", mName, (int) mValues.size()); - aStringBuffer.append(buffer); - for (size_t i = 0; i < mValues.size(); i++) - { - snprintf(buffer, 1023, "%.10g ", mValues[i]); - aStringBuffer.append(buffer); - } - } - - mChanged = false; - return true; -} - -char *TimeSeries::toString(char *aBuffer, int aMaxLen) -{ - return aBuffer; -} - -bool TimeSeries::unavailable() -{ - if (!mUnavailable) - { - mChanged = true; - mUnavailable = true; - mHasValue = true; - } - - return mChanged; -} - -bool TimeSeries::requiresFlush() -{ - return true; -} +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#include "internal.hpp" +#include "time_series.hpp" +#include "string_buffer.hpp" + +using namespace std; + + +TimeSeries::TimeSeries(const char *name, float epsilon, float rate) : + DeviceDatum(name), + mUnavailable(false), + mEpsilon(epsilon), + mRate(rate) +{ +} + + +void TimeSeries::addValue(float value) +{ + mValues.push_back(value); + + mChanged = true; + mHasValue = true; + mUnavailable = false; +} + + +bool TimeSeries::setValue(std::vector values) +{ + mValues = values; + + mChanged = true; + mHasValue = true; + mUnavailable = false; + + return true; +} + + +bool TimeSeries::append(StringBuffer &stringBuffer) +{ + char buffer[1024] = {0}; + if (mUnavailable) + { + snprintf(buffer, 1023u, "|%s|0||UNAVAILABLE", mName); + stringBuffer.append(buffer); + } + else + { + if (mRate > 0) + snprintf(buffer, 1023u, "|%s|%d|%g|", mName, (int) mValues.size(), mRate); + else + snprintf(buffer, 1023u, "|%s|%d||", mName, (int) mValues.size()); + stringBuffer.append(buffer); + for (auto i = 0u; i < mValues.size(); i++) + { + snprintf(buffer, 1023, "%.10g ", mValues[i]); + stringBuffer.append(buffer); + } + } + + mChanged = false; + return true; +} + + +char *TimeSeries::toString(char *buffer, int maxLen) +{ + return buffer; +} + + +bool TimeSeries::unavailable() +{ + if (!mUnavailable) + { + mChanged = true; + mUnavailable = true; + mHasValue = true; + } + + return mChanged; +} + + +bool TimeSeries::requiresFlush() const +{ + return true; +} diff --git a/src/time_series.hpp b/src/time_series.hpp index 62544ef..e218608 100644 --- a/src/time_series.hpp +++ b/src/time_series.hpp @@ -1,71 +1,75 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef TIME_SERIES_HPP -#define TIME_SERIES_HPP - -#include "device_datum.hpp" -#include - -/* - * A time series of samples - */ - -class TimeSeries : public DeviceDatum -{ -protected: - std::vector mValues; - bool mUnavailable; - float mEpsilon; - float mRate; - -public: - TimeSeries(const char *aName, float aEpsilon = 0.000001, - float aRate = -1.0); - - bool setValue(std::vector aValues); - void addValue(float aValue); - std::vector &getValues() { return mValues; } - int getCount() { return mValues.size(); } - void clear() { mValues.clear(); } - float getRate() { return mRate; } - void setRate(float aRate) { mRate = aRate; } - - virtual char *toString(char *aBuffer, int aMaxLen); - virtual bool unavailable(); - virtual bool requiresFlush(); - virtual bool append(StringBuffer &aBuffer); -}; - - -#endif +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include "device_datum.hpp" +#include + +// +// A time series of samples +// +class TimeSeries : public DeviceDatum +{ +protected: + std::vector mValues; + bool mUnavailable; + float mEpsilon; + float mRate; + +public: + TimeSeries(const char *mame, float epsilon = 0.000001, float rate = -1.0); + + bool setValue(std::vector values); + void addValue(float value); + + std::vector &getValues() { + return mValues; } + const std::vector &getValues() const { + return mValues; } + + int getCount() const { + return mValues.size(); } + void clear() { + mValues.clear(); } + float getRate() const { + return mRate; } + void setRate(float rate) { + mRate = rate; } + +// Overrides from DeviceDatum +public: + char *toString(char *buffer, int maxLen) override; + bool unavailable() override; + bool requiresFlush() const override; + bool append(StringBuffer &buffer) override; +}; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a8bedf1..2c90f62 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,44 +1,57 @@ -# The name of our project is "HELLO". CMakeLists files in this project can -# refer to the root source directory of the project as ${HELLO_SOURCE_DIR} and -# to the root binary directory of the project as ${HELLO_BINARY_DIR}. -cmake_minimum_required (VERSION 2.6) - -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") - -set(CMAKE_BUILD_TYPE DEBUG) -set(CMAKE_FIND_FRAMEWORK NEVER FORCE) -set(CMAKE_FIND_APPBUNDLE NEVER) - -if(WIN32) - set(CPPUNIT_INCLUDE_DIR ../win32/cppunit-1.12.1/include) - file(GLOB CPPUNIT_LIBRARY ../win32/cppunit-1.12.1/lib/cppunitd.lib) -endif(WIN32) - if(UNIX) - execute_process(COMMAND uname OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE CMAKE_SYSTEM_NAME) - if(CMAKE_SYSTEM_NAME MATCHES Linux) - set(LINUX_LIBRARIES pthread) - endif(CMAKE_SYSTEM_NAME MATCHES Linux) + execute_process(COMMAND uname OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE CMAKE_SYSTEM_NAME) + if(CMAKE_SYSTEM_NAME MATCHES Linux) + set(LINUX_LIBRARIES pthread) + endif(CMAKE_SYSTEM_NAME MATCHES Linux) endif(UNIX) -set(YAML_CPP_SOURCE_DIR ../yaml/src) -set(YAML_CPP_INCLUDE_DIR ../yaml/include) -set(ADAPTER_CPP_SOURCE_DIR ../src) -set(ADAPTER_CPP_INCLUDE_DIR ../src) +set(YAML_CPP_SOURCE_DIR ${CMAKE_SOURCE_DIR}/yaml/src) +set(YAML_CPP_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/yaml/include) +set(ADAPTER_CPP_SOURCE_DIR ${CMAKE_SOURCE_DIR}/src) +set(ADAPTER_CPP_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/src) file(GLOB yaml_sources ${YAML_CPP_SOURCE_DIR}/[a-z]*.cpp) +file(GLOB yaml_headers ${YAML_CPP_SOURCE_DIR}/[a-z]*.h) file(GLOB adapter_sources ${ADAPTER_CPP_SOURCE_DIR}/[a-z_]*.cpp) +file(GLOB adapter_headers ${ADAPTER_CPP_SOURCE_DIR}/[a-z_]*.hpp) file(GLOB test_sources [a-zA-Z_]*.cpp [a-z]*.c) file(GLOB headers [a-z_]*.hpp) -include_directories(${YAML_CPP_SOURCE_DIR} ${YAML_CPP_INCLUDE_DIR} ${ADAPTER_CPP_INCLUDE_DIR}) +# Allow better viewing and grouping of files in Visual Studio by defining source groups +source_group("Headers Files" FILES ${headers}) +source_group("Headers Files\\adapter" FILES ${adapter_headers}) +source_group("Headers Files\\YAML" FILES ${yaml_headers}) +source_group("Source Files" FILES ${test_sources}) +source_group("Source Files\\adapter" FILES ${adapter_sources}) +source_group("Source Files\\YAML" FILES ${yaml_sources}) + + +add_executable(test + ${yaml_sources} + ${yaml_headers} + ${adapter_sources} + ${adapter_headers} + ${test_sources} + ${headers} + ) + +target_include_directories(test + PRIVATE ${YAML_CPP_SOURCE_DIR} + PRIVATE ${YAML_CPP_INCLUDE_DIR} + PRIVATE ${ADAPTER_CPP_INCLUDE_DIR} + ) + +target_link_libraries(test + PRIVATE ${LINUX_LIBRARIES} + ) -project (test) - -find_package(CppUnit REQUIRED) - -add_definitions() -include_directories(${CPPUNIT_INCLUDE_DIR}) - -add_executable(test ${yaml_sources} ${adapter_sources} ${test_sources}) -target_link_libraries(test ${CPPUNIT_LIBRARY} ${LINUX_LIBRARIES}) +if(WIN32) + target_link_libraries(test + PRIVATE wsock32.lib + PRIVATE Ws2_32.lib + ) +endif() + +AddMsvcXPSupport(test) #This will only apply if an XP compatible toolset has been selected in CMake +AddCppUnitSupport(test) +AddDateSupport(test) diff --git a/test/condition_test.cpp b/test/condition_test.cpp index 28f973b..4920abc 100644 --- a/test/condition_test.cpp +++ b/test/condition_test.cpp @@ -1,147 +1,159 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#include "condition_test.hpp" -#include "string_buffer.hpp" -#include - -using namespace std; - -CPPUNIT_TEST_SUITE_REGISTRATION(ConditionTest); - -void ConditionTest::setUp() -{ -} - -void ConditionTest::tearDown() -{ -} - -void ConditionTest::testInitial() -{ - Condition cond("Test"); - StringBuffer buffer; - - CPPUNIT_ASSERT_EQUAL(string("Test"), string(cond.getName())); - - CPPUNIT_ASSERT(cond.changed()); - CPPUNIT_ASSERT(cond.hasInitialValue()); - CPPUNIT_ASSERT(cond.requiresFlush()); - - cond.append(buffer); - CPPUNIT_ASSERT_EQUAL(string("|Test|UNAVAILABLE||||"), string((const char*) buffer)); -} - -void ConditionTest::testInitialNormal() -{ - Condition cond("Test"); - StringBuffer buffer; - - CPPUNIT_ASSERT(cond.normal()); - - cond.append(buffer); - CPPUNIT_ASSERT_EQUAL(string("|Test|NORMAL||||"), string((const char*) buffer)); -} - -void ConditionTest::testAdd() -{ - Condition cond("Test"); - StringBuffer buffer; - - cond.begin(); - CPPUNIT_ASSERT(cond.add(Condition::eFAULT, "A Fault", "123", "HIGH", "1")); - CPPUNIT_ASSERT(cond.append(buffer)); - CPPUNIT_ASSERT_EQUAL(string("|Test|FAULT|123|1|HIGH|A Fault"), string((const char*) buffer)); - cond.cleanup(); -} - -void ConditionTest::testActive() -{ - Condition cond("Test"); - StringBuffer buffer; - - cond.begin(); - CPPUNIT_ASSERT(cond.add(Condition::eFAULT, "A Fault", "123", "HIGH", "1")); - CPPUNIT_ASSERT(cond.append(buffer)); - CPPUNIT_ASSERT_EQUAL(string("|Test|FAULT|123|1|HIGH|A Fault"), string((const char*) buffer)); - - CPPUNIT_ASSERT(cond.isActive("123")); - CPPUNIT_ASSERT(!cond.isActive("1234")); - cond.cleanup(); -} - -void ConditionTest::testCleanup() -{ - Condition cond("Test"); - StringBuffer buffer; - - cond.begin(); - CPPUNIT_ASSERT(cond.add(Condition::eFAULT, "A Fault", "123", "HIGH", "1")); - CPPUNIT_ASSERT(cond.append(buffer)); - CPPUNIT_ASSERT_EQUAL(string("|Test|FAULT|123|1|HIGH|A Fault"), string((const char*) buffer)); - cond.cleanup(); - - buffer.reset(); - - cond.begin(); - cond.append(buffer); - CPPUNIT_ASSERT_EQUAL(string("|Test|NORMAL||||"), string((const char*) buffer)); - cond.cleanup(); - - buffer.reset(); - - cond.begin(); - CPPUNIT_ASSERT(cond.add(Condition::eFAULT, "A Fault", "123", "HIGH", "1")); - CPPUNIT_ASSERT(cond.add(Condition::eFAULT, "Another Fault", "124", "HIGH", "1")); - CPPUNIT_ASSERT(cond.append(buffer)); - CPPUNIT_ASSERT_EQUAL(string("|Test|FAULT|124|1|HIGH|Another Fault\n" - "|Test|FAULT|123|1|HIGH|A Fault"), - string((const char*) buffer)); - - CPPUNIT_ASSERT(cond.isActive("123")); - CPPUNIT_ASSERT(cond.isActive("124")); - cond.cleanup(); - - buffer.reset(); - - cond.begin(); - CPPUNIT_ASSERT(!cond.add(Condition::eFAULT, "A Fault", "123", "HIGH", "1")); - - cond.append(buffer); - CPPUNIT_ASSERT_EQUAL(string("|Test|NORMAL|124|||"), string((const char*) buffer)); - cond.cleanup(); - - CPPUNIT_ASSERT(cond.isActive("123")); - CPPUNIT_ASSERT(!cond.isActive("124")); -} - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// + +#include "condition_test.hpp" +#include "string_buffer.hpp" +#include + +using namespace std; + +CPPUNIT_TEST_SUITE_REGISTRATION(ConditionTest); + + +void ConditionTest::setUp() +{ +} + + +void ConditionTest::tearDown() +{ +} + + +void ConditionTest::testInitial() +{ + Condition cond("Test"); + StringBuffer buffer; + + CPPUNIT_ASSERT_EQUAL(string("Test"), string(cond.getName())); + + CPPUNIT_ASSERT(cond.changed()); + CPPUNIT_ASSERT(cond.hasInitialValue()); + CPPUNIT_ASSERT(cond.requiresFlush()); + + cond.append(buffer); + CPPUNIT_ASSERT_EQUAL(string("|Test|UNAVAILABLE||||"), string((const char *) buffer)); +} + + +void ConditionTest::testInitialNormal() +{ + Condition cond("Test"); + StringBuffer buffer; + + CPPUNIT_ASSERT(cond.normal()); + + cond.append(buffer); + CPPUNIT_ASSERT_EQUAL(string("|Test|NORMAL||||"), string((const char *) buffer)); +} + + +void ConditionTest::testAdd() +{ + Condition cond("Test"); + StringBuffer buffer; + + cond.begin(); + CPPUNIT_ASSERT(cond.add(Condition::eFAULT, "A Fault", "123", "HIGH", "1")); + cond.prepare(); + CPPUNIT_ASSERT(cond.append(buffer)); + CPPUNIT_ASSERT_EQUAL(string("|Test|FAULT|123|1|HIGH|A Fault"), string((const char *) buffer)); + cond.cleanup(); +} + + +void ConditionTest::testActive() +{ + Condition cond("Test"); + StringBuffer buffer; + + cond.begin(); + CPPUNIT_ASSERT(cond.add(Condition::eFAULT, "A Fault", "123", "HIGH", "1")); + cond.prepare(); + CPPUNIT_ASSERT(cond.append(buffer)); + CPPUNIT_ASSERT_EQUAL(string("|Test|FAULT|123|1|HIGH|A Fault"), string((const char *) buffer)); + + CPPUNIT_ASSERT(cond.isActive("123")); + CPPUNIT_ASSERT(!cond.isActive("1234")); + cond.cleanup(); +} + + +void ConditionTest::testCleanup() +{ + Condition cond("Test"); + StringBuffer buffer; + + cond.begin(); + CPPUNIT_ASSERT(cond.add(Condition::eFAULT, "A Fault", "123", "HIGH", "1")); + cond.prepare(); + CPPUNIT_ASSERT(cond.append(buffer)); + CPPUNIT_ASSERT_EQUAL(string("|Test|FAULT|123|1|HIGH|A Fault"), string((const char *) buffer)); + cond.cleanup(); + + buffer.reset(); + + cond.begin(); + cond.prepare(); + cond.append(buffer); + CPPUNIT_ASSERT_EQUAL(string("|Test|NORMAL||||"), string((const char *) buffer)); + cond.cleanup(); + + buffer.reset(); + + cond.begin(); + CPPUNIT_ASSERT(cond.add(Condition::eFAULT, "A Fault", "123", "HIGH", "1")); + CPPUNIT_ASSERT(cond.add(Condition::eFAULT, "Another Fault", "124", "HIGH", "1")); + cond.prepare(); + CPPUNIT_ASSERT(cond.append(buffer)); + CPPUNIT_ASSERT_EQUAL(string("|Test|FAULT|124|1|HIGH|Another Fault\n" + "|Test|FAULT|123|1|HIGH|A Fault"), + string((const char *) buffer)); + + CPPUNIT_ASSERT(cond.isActive("123")); + CPPUNIT_ASSERT(cond.isActive("124")); + cond.cleanup(); + + buffer.reset(); + + cond.begin(); + CPPUNIT_ASSERT(!cond.add(Condition::eFAULT, "A Fault", "123", "HIGH", "1")); + cond.prepare(); + cond.append(buffer); + CPPUNIT_ASSERT_EQUAL(string("|Test|NORMAL|124|||"), string((const char *) buffer)); + cond.cleanup(); + + CPPUNIT_ASSERT(cond.isActive("123")); + CPPUNIT_ASSERT(!cond.isActive("124")); +} + diff --git a/test/condition_test.hpp b/test/condition_test.hpp index 01700df..d44f917 100644 --- a/test/condition_test.hpp +++ b/test/condition_test.hpp @@ -1,65 +1,62 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef CONDITION_TEST_HPP -#define CONDITION_TEST_HPP - -#include -#include - -#include "condition.hpp" - -class ConditionTest : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(ConditionTest); - CPPUNIT_TEST(testInitial); - CPPUNIT_TEST(testInitialNormal); - CPPUNIT_TEST(testAdd); - CPPUNIT_TEST(testActive); - CPPUNIT_TEST(testCleanup); - CPPUNIT_TEST_SUITE_END(); - -protected: - void testInitial(); - void testInitialNormal(); - void testAdd(); - void testActive(); - void testCleanup(); - -public: - void setUp(); - void tearDown(); -}; - -#endif - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include +#include +#include + +#include "condition.hpp" + +class ConditionTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(ConditionTest); + CPPUNIT_TEST(testInitial); + CPPUNIT_TEST(testInitialNormal); + CPPUNIT_TEST(testAdd); + CPPUNIT_TEST(testActive); + CPPUNIT_TEST(testCleanup); + CPPUNIT_TEST_SUITE_END(); + +protected: + void testInitial(); + void testInitialNormal(); + void testAdd(); + void testActive(); + void testCleanup(); + +public: + void setUp(); + void tearDown(); +}; + diff --git a/test/configuration_test.cpp b/test/configuration_test.cpp index 288225a..44ebdfd 100644 --- a/test/configuration_test.cpp +++ b/test/configuration_test.cpp @@ -1,64 +1,68 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#include "configuration_test.hpp" -#include -#include - -using namespace std; - -CPPUNIT_TEST_SUITE_REGISTRATION(ConfigurationTest); - -void ConfigurationTest::setUp() -{ -} - -void ConfigurationTest::tearDown() -{ -} - -void ConfigurationTest::testConstructor() -{ - string config = - "adapter:\n" - " port: 7878\n" - " scanDelay: 100\n" - " timeout: 10000\n"; - - istringstream str(config); - Configuration cfg(str); - - CPPUNIT_ASSERT_EQUAL(cfg.getPort(), 7878); - CPPUNIT_ASSERT_EQUAL(cfg.getScanDelay(), 100); - CPPUNIT_ASSERT_EQUAL(cfg.getTimeout(), 10000); -} +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// + +#include "configuration_test.hpp" +#include +#include + +using namespace std; + +CPPUNIT_TEST_SUITE_REGISTRATION(ConfigurationTest); + + +void ConfigurationTest::setUp() +{ +} + + +void ConfigurationTest::tearDown() +{ +} + + +void ConfigurationTest::testConstructor() +{ + string config = + "adapter:\n" + " port: 7878\n" + " scanDelay: 100\n" + " timeout: 10000\n"; + + istringstream str(config); + Configuration cfg; + cfg.parse(str); + + CPPUNIT_ASSERT_EQUAL(cfg.getPort(), 7878); + CPPUNIT_ASSERT_EQUAL(cfg.getScanDelay(), 100); + CPPUNIT_ASSERT_EQUAL(cfg.getTimeout(), 10000); +} diff --git a/test/configuration_test.hpp b/test/configuration_test.hpp index 751db6b..02df597 100644 --- a/test/configuration_test.hpp +++ b/test/configuration_test.hpp @@ -1,57 +1,54 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef CONFIGURATION_TEST_HPP -#define CONFIGURATION_TEST_HPP - -#include -#include - -#include "configuration.hpp" - -class ConfigurationTest : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(ConfigurationTest); - CPPUNIT_TEST(testConstructor); - CPPUNIT_TEST_SUITE_END(); - -protected: - void testConstructor(); - -public: - void setUp(); - void tearDown(); -}; - -#endif - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include +#include +#include + +#include "configuration.hpp" + +class ConfigurationTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(ConfigurationTest); + CPPUNIT_TEST(testConstructor); + CPPUNIT_TEST_SUITE_END(); + +protected: + void testConstructor(); + +public: + void setUp(); + void tearDown(); +}; + diff --git a/test/device_datum_test.cpp b/test/device_datum_test.cpp index e46ec3f..0a7cd0c 100644 --- a/test/device_datum_test.cpp +++ b/test/device_datum_test.cpp @@ -1,123 +1,127 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#include "device_datum_test.hpp" -#include - -using namespace std; - -CPPUNIT_TEST_SUITE_REGISTRATION(DeviceDatumTest); - -void DeviceDatumTest::setUp() -{ -} - -void DeviceDatumTest::tearDown() -{ -} - -void DeviceDatumTest::testEvent() -{ - Event event("Test"); - char buffer[256]; - - CPPUNIT_ASSERT_EQUAL(string("Test"), string(event.getName())); - - CPPUNIT_ASSERT(!event.changed()); - CPPUNIT_ASSERT(!event.hasInitialValue()); - CPPUNIT_ASSERT_EQUAL(string(""), string(event.getValue())); - - event.unavailable(); - CPPUNIT_ASSERT(event.changed()); - CPPUNIT_ASSERT(event.hasInitialValue()); - - CPPUNIT_ASSERT(event.toString(buffer, 255) != 0); - CPPUNIT_ASSERT_EQUAL(string("|Test|UNAVAILABLE"), string(buffer)); - - event.reset(); - CPPUNIT_ASSERT(!event.changed()); - CPPUNIT_ASSERT(event.hasInitialValue()); - - CPPUNIT_ASSERT(event.setValue("Hello")); - CPPUNIT_ASSERT(event.changed()); - CPPUNIT_ASSERT(event.toString(buffer, 255) != 0); - CPPUNIT_ASSERT_EQUAL(string("|Test|Hello"), string(buffer)); - CPPUNIT_ASSERT_EQUAL(string("Hello"), string(event.getValue())); - - event.reset(); - CPPUNIT_ASSERT(!event.changed()); - - CPPUNIT_ASSERT(!event.setValue("Hello")); -} - -void DeviceDatumTest::testSample() -{ - Sample sample("Test"); - char buffer[256]; - - CPPUNIT_ASSERT_EQUAL(0, strcmp(sample.getName(), "Test")); - - CPPUNIT_ASSERT(!sample.changed()); - CPPUNIT_ASSERT(!sample.hasInitialValue()); - CPPUNIT_ASSERT_EQUAL(0.0, sample.getValue()); - - sample.unavailable(); - CPPUNIT_ASSERT(sample.changed()); - CPPUNIT_ASSERT(sample.hasInitialValue()); - - CPPUNIT_ASSERT(sample.toString(buffer, 255) != 0); - CPPUNIT_ASSERT_EQUAL(string("|Test|UNAVAILABLE"), string(buffer)); - - CPPUNIT_ASSERT(sample.setValue(1.234567)); - CPPUNIT_ASSERT(sample.changed()); - CPPUNIT_ASSERT(sample.hasInitialValue()); - - CPPUNIT_ASSERT(sample.toString(buffer, 255) != 0); - CPPUNIT_ASSERT_EQUAL(string("|Test|1.234567"), string(buffer)); - - CPPUNIT_ASSERT(sample.setValue(1.234568)); - CPPUNIT_ASSERT(sample.changed()); - CPPUNIT_ASSERT(sample.hasInitialValue()); - - CPPUNIT_ASSERT(sample.toString(buffer, 255) != 0); - CPPUNIT_ASSERT_EQUAL(string("|Test|1.234568"), string(buffer)); - - sample.reset(); - - // Check epsilon change does not change value. - CPPUNIT_ASSERT(!sample.setValue(1.2345681)); - CPPUNIT_ASSERT(!sample.changed()); - - CPPUNIT_ASSERT(sample.toString(buffer, 255) != 0); - CPPUNIT_ASSERT_EQUAL(string("|Test|1.234568"), string(buffer)); -} +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// + +#include "device_datum_test.hpp" +#include + +using namespace std; + +CPPUNIT_TEST_SUITE_REGISTRATION(DeviceDatumTest); + + +void DeviceDatumTest::setUp() +{ +} + + +void DeviceDatumTest::tearDown() +{ +} + + +void DeviceDatumTest::testEvent() +{ + Event event("Test"); + char buffer[256]; + + CPPUNIT_ASSERT_EQUAL(string("Test"), string(event.getName())); + + CPPUNIT_ASSERT(!event.changed()); + CPPUNIT_ASSERT(!event.hasInitialValue()); + CPPUNIT_ASSERT_EQUAL(string(""), string(event.getValue())); + + event.unavailable(); + CPPUNIT_ASSERT(event.changed()); + CPPUNIT_ASSERT(event.hasInitialValue()); + + CPPUNIT_ASSERT(event.toString(buffer, 255) != 0); + CPPUNIT_ASSERT_EQUAL(string("|Test|UNAVAILABLE"), string(buffer)); + + event.reset(); + CPPUNIT_ASSERT(!event.changed()); + CPPUNIT_ASSERT(event.hasInitialValue()); + + CPPUNIT_ASSERT(event.setValue("Hello")); + CPPUNIT_ASSERT(event.changed()); + CPPUNIT_ASSERT(event.toString(buffer, 255) != 0); + CPPUNIT_ASSERT_EQUAL(string("|Test|Hello"), string(buffer)); + CPPUNIT_ASSERT_EQUAL(string("Hello"), string(event.getValue())); + + event.reset(); + CPPUNIT_ASSERT(!event.changed()); + + CPPUNIT_ASSERT(!event.setValue("Hello")); +} + + +void DeviceDatumTest::testSample() +{ + Sample sample("Test"); + char buffer[256]; + + CPPUNIT_ASSERT_EQUAL(0, strcmp(sample.getName(), "Test")); + + CPPUNIT_ASSERT(!sample.changed()); + CPPUNIT_ASSERT(!sample.hasInitialValue()); + CPPUNIT_ASSERT_EQUAL(0.0, sample.getValue()); + + sample.unavailable(); + CPPUNIT_ASSERT(sample.changed()); + CPPUNIT_ASSERT(sample.hasInitialValue()); + + CPPUNIT_ASSERT(sample.toString(buffer, 255) != 0); + CPPUNIT_ASSERT_EQUAL(string("|Test|UNAVAILABLE"), string(buffer)); + + CPPUNIT_ASSERT(sample.setValue(1.234567)); + CPPUNIT_ASSERT(sample.changed()); + CPPUNIT_ASSERT(sample.hasInitialValue()); + + CPPUNIT_ASSERT(sample.toString(buffer, 255) != 0); + CPPUNIT_ASSERT_EQUAL(string("|Test|1.234567"), string(buffer)); + + CPPUNIT_ASSERT(sample.setValue(1.234568)); + CPPUNIT_ASSERT(sample.changed()); + CPPUNIT_ASSERT(sample.hasInitialValue()); + + CPPUNIT_ASSERT(sample.toString(buffer, 255) != 0); + CPPUNIT_ASSERT_EQUAL(string("|Test|1.234568"), string(buffer)); + + sample.reset(); + + // Check epsilon change does not change value. + CPPUNIT_ASSERT(!sample.setValue(1.2345681)); + CPPUNIT_ASSERT(!sample.changed()); + + CPPUNIT_ASSERT(sample.toString(buffer, 255) != 0); + CPPUNIT_ASSERT_EQUAL(string("|Test|1.234568"), string(buffer)); +} diff --git a/test/device_datum_test.hpp b/test/device_datum_test.hpp index d095074..a6b626e 100644 --- a/test/device_datum_test.hpp +++ b/test/device_datum_test.hpp @@ -1,59 +1,56 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef DEVICE_DATUM_TEST_HPP -#define DEVICE_DATUM_TEST_HPP - -#include -#include - -#include "device_datum.hpp" - -class DeviceDatumTest : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(DeviceDatumTest); - CPPUNIT_TEST(testEvent); - CPPUNIT_TEST(testSample); - CPPUNIT_TEST_SUITE_END(); - -protected: - void testEvent(); - void testSample(); - -public: - void setUp(); - void tearDown(); -}; - -#endif - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include +#include +#include + +#include "device_datum.hpp" + +class DeviceDatumTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(DeviceDatumTest); + CPPUNIT_TEST(testEvent); + CPPUNIT_TEST(testSample); + CPPUNIT_TEST_SUITE_END(); + +protected: + void testEvent(); + void testSample(); + +public: + void setUp(); + void tearDown(); +}; + diff --git a/test/test.cpp b/test/test.cpp index 9c3d346..571019a 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -1,35 +1,67 @@ - - -#include -#include -#include -#include -#include -#include - -int main (int argc, char* argv[]) -{ - // informs test-listener about testresults - CPPUNIT_NS :: TestResult testresult; - - // register listener for collecting the test-results - CPPUNIT_NS :: TestResultCollector collectedresults; - testresult.addListener (&collectedresults); - - // register listener for per-test progress output - CPPUNIT_NS :: BriefTestProgressListener progress; - testresult.addListener (&progress); - - // insert test-suite at test-runner by registry - CPPUNIT_NS :: TestRunner testrunner; - testrunner.addTest (CPPUNIT_NS :: TestFactoryRegistry :: getRegistry ().makeTest ()); - testrunner.run (testresult); - - // output results in compiler-format - CPPUNIT_NS :: CompilerOutputter compileroutputter (&collectedresults, std::cerr); - compileroutputter.write (); - - // return 0 if tests were successful - return collectedresults.wasSuccessful () ? 0 : 1; -} - +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// + +#include +#include +#include +#include +#include +#include + + +int main(int argc, char *argv[]) +{ + // informs test-listener about testresults + CPPUNIT_NS :: TestResult testresult; + + // register listener for collecting the test-results + CPPUNIT_NS :: TestResultCollector collectedresults; + testresult.addListener(&collectedresults); + + // register listener for per-test progress output + CPPUNIT_NS :: BriefTestProgressListener progress; + testresult.addListener(&progress); + + // insert test-suite at test-runner by registry + CPPUNIT_NS :: TestRunner testrunner; + testrunner.addTest(CPPUNIT_NS :: TestFactoryRegistry :: getRegistry().makeTest()); + testrunner.run(testresult); + + // output results in compiler-format + CPPUNIT_NS :: CompilerOutputter compileroutputter(&collectedresults, std::cerr); + compileroutputter.write(); + + // return 0 if tests were successful + return collectedresults.wasSuccessful() ? 0 : 1; +} + diff --git a/test/time_series_test.cpp b/test/time_series_test.cpp index ee9cef7..0c9aaad 100644 --- a/test/time_series_test.cpp +++ b/test/time_series_test.cpp @@ -1,78 +1,83 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#include "time_series_test.hpp" -#include "string_buffer.hpp" -#include - -using namespace std; - -CPPUNIT_TEST_SUITE_REGISTRATION(TimeSeriesTest); - -void TimeSeriesTest::setUp() -{ -} - -void TimeSeriesTest::tearDown() -{ -} - -void TimeSeriesTest::testTimeSeries() -{ - StringBuffer buffer; - TimeSeries series("test"); - - for (int i = 0; i < 5; i++) - series.addValue((double) i); - - series.append(buffer); - CPPUNIT_ASSERT_EQUAL(string("|test|5||0 1 2 3 4 "), - string((const char*) buffer)); - - series.clear(); - buffer.reset(); - - series.append(buffer); - CPPUNIT_ASSERT_EQUAL(string("|test|0||"), - string((const char*) buffer)); - - buffer.reset(); - - series.addValue(2.0); - series.addValue(4.0); - series.setRate(42000); - - series.append(buffer); - CPPUNIT_ASSERT_EQUAL(string("|test|2|42000|2 4 "), - string((const char*) buffer)); -} +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#include "time_series_test.hpp" +#include "string_buffer.hpp" +#include + +using namespace std; + +CPPUNIT_TEST_SUITE_REGISTRATION(TimeSeriesTest); + + +void TimeSeriesTest::setUp() +{ +} + + +void TimeSeriesTest::tearDown() +{ +} + + +void TimeSeriesTest::testTimeSeries() +{ + StringBuffer buffer; + TimeSeries series("test"); + + for (auto i = 0.0f; i < 5.0f; i++) + series.addValue(i); + + series.append(buffer); + CPPUNIT_ASSERT_EQUAL( + string("|test|5||0 1 2 3 4 "), + string((const char *) buffer)); + + series.clear(); + buffer.reset(); + + series.append(buffer); + CPPUNIT_ASSERT_EQUAL( + string("|test|0||"), + string((const char *) buffer)); + + buffer.reset(); + + series.addValue(2.0f); + series.addValue(4.0f); + series.setRate(42000); + + series.append(buffer); + CPPUNIT_ASSERT_EQUAL( + string("|test|2|42000|2 4 "), + string((const char *) buffer)); +} diff --git a/test/time_series_test.hpp b/test/time_series_test.hpp index eeb8fb8..4942cf8 100644 --- a/test/time_series_test.hpp +++ b/test/time_series_test.hpp @@ -1,56 +1,54 @@ -/* -* Copyright (c) 2008, AMT – The Association For Manufacturing Technology (“AMT”) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the AMT nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED -* BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" -* AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR -* RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS -* (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR -* WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT -* LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, -* MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - -* LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT -* PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS -* OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, -* CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, -* WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF -* THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT -* SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. -*/ - -#ifndef DEVICE_DATUM_TEST_HPP -#define DEVICE_DATUM_TEST_HPP - -#include -#include - -#include "time_series.hpp" - -class TimeSeriesTest : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TimeSeriesTest); - CPPUNIT_TEST(testTimeSeries); - CPPUNIT_TEST_SUITE_END(); - -protected: - void testTimeSeries(); - -public: - void setUp(); - void tearDown(); -}; - -#endif +// +// Copyright (c) 2008, AMT - The Association For Manufacturing Technology ("AMT") +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the AMT nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// DISCLAIMER OF WARRANTY. ALL MTCONNECT MATERIALS AND SPECIFICATIONS PROVIDED +// BY AMT, MTCONNECT OR ANY PARTICIPANT TO YOU OR ANY PARTY ARE PROVIDED "AS IS" +// AND WITHOUT ANY WARRANTY OF ANY KIND. AMT, MTCONNECT, AND EACH OF THEIR +// RESPECTIVE MEMBERS, OFFICERS, DIRECTORS, AFFILIATES, SPONSORS, AND AGENTS +// (COLLECTIVELY, THE "AMT PARTIES") AND PARTICIPANTS MAKE NO REPRESENTATION OR +// WARRANTY OF ANY KIND WHATSOEVER RELATING TO THESE MATERIALS, INCLUDING, WITHOUT +// LIMITATION, ANY EXPRESS OR IMPLIED WARRANTY OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// LIMITATION OF LIABILITY. IN NO EVENT SHALL AMT, MTCONNECT, ANY OTHER AMT +// PARTY, OR ANY PARTICIPANT BE LIABLE FOR THE COST OF PROCURING SUBSTITUTE GOODS +// OR SERVICES, LOST PROFITS, LOSS OF USE, LOSS OF DATA OR ANY INCIDENTAL, +// CONSEQUENTIAL, INDIRECT, SPECIAL OR PUNITIVE DAMAGES OR OTHER DIRECT DAMAGES, +// WHETHER UNDER CONTRACT, TORT, WARRANTY OR OTHERWISE, ARISING IN ANY WAY OUT OF +// THIS AGREEMENT, USE OR INABILITY TO USE MTCONNECT MATERIALS, WHETHER OR NOT +// SUCH PARTY HAD ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. +// +#pragma once + +#include +#include +#include + +#include "time_series.hpp" + +class TimeSeriesTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(TimeSeriesTest); + CPPUNIT_TEST(testTimeSeries); + CPPUNIT_TEST_SUITE_END(); + +protected: + void testTimeSeries(); + + public: + void setUp(); + void tearDown(); +}; + diff --git a/yaml/src/scanner.cpp b/yaml/src/scanner.cpp index 33052c2..b78bc2e 100644 --- a/yaml/src/scanner.cpp +++ b/yaml/src/scanner.cpp @@ -4,6 +4,7 @@ #include "exp.h" #include #include +#include namespace YAML { diff --git a/yaml/src/stream.cpp b/yaml/src/stream.cpp index 0d1426a..570a50a 100644 --- a/yaml/src/stream.cpp +++ b/yaml/src/stream.cpp @@ -1,5 +1,5 @@ #include "stream.h" -#include +#include #include "exp.h" #ifndef YAML_PREFETCH_SIZE diff --git a/yaml/src/tag.cpp b/yaml/src/tag.cpp index 694a4f3..e62c23e 100644 --- a/yaml/src/tag.cpp +++ b/yaml/src/tag.cpp @@ -2,6 +2,7 @@ #include "token.h" #include "parserstate.h" #include +#include namespace YAML { diff --git a/yaml/src/token.h b/yaml/src/token.h index cf7c0fe..f5f5e6a 100644 --- a/yaml/src/token.h +++ b/yaml/src/token.h @@ -5,6 +5,7 @@ #include "mark.h" +#include #include #include #include