diff --git a/CMakeLists.txt b/CMakeLists.txt index 58234bf27..961ccebf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,12 @@ # ---------------------------------------------------------------------------- # Title : ROGUE CMAKE Control # ---------------------------------------------------------------------------- -# This file is part of the rogue software package. It is subject to -# the license terms in the LICENSE.txt file found in the top-level directory -# of this distribution and at: -# https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. -# No part of the rogue software package, including this file, may be -# copied, modified, propagated, or distributed except according to the terms +# This file is part of the rogue software package. It is subject to +# the license terms in the LICENSE.txt file found in the top-level directory +# of this distribution and at: +# https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +# No part of the rogue software package, including this file, may be +# copied, modified, propagated, or distributed except according to the terms # contained in the LICENSE.txt file. # ---------------------------------------------------------------------------- # See notes for compiling on macros under anaconda: @@ -37,12 +37,16 @@ enable_language(CXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-deprecated") add_definitions(-D__STDC_FORMAT_MACROS) +SET(CMAKE_SKIP_BUILD_RPATH TRUE) +SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) +SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) + ##################################### # Boost + Python ##################################### -if ( NOT NO_PYTHON ) - find_package(PythonInterp 3.6 QUIET REQUIRED) - find_package(PythonLibs 3.6 QUIET REQUIRED) +if ( NOT NO_PYTHON ) + find_package(PythonInterp 3 QUIET REQUIRED) + find_package(PythonLibs 3 QUIET REQUIRED) # Find Numpy execute_process( @@ -58,36 +62,43 @@ if ( NOT NO_PYTHON ) endif() set(Boost_USE_MULTITHREADED ON) + set(Boost_NO_BOOST_CMAKE ON) + + # Hint for boost on anaconda + if (DEFINED ENV{CONDA_PREFIX}) + set(BOOST_ROOT $ENV{CONDA_PREFIX}) - # Boost may need help on SLAC machines - set(BOOST_ROOT:PATHNAME $ENV{BOOST_PATH}) + # SLAC AFS custom path + elseif (DEFINED ENV{BOOST_PATH}) + set(BOOST_ROOT $ENV{BOOST_PATH}) + endif() - # First try standard suffix for boost - message("Looking for boost/python3") - find_package(Boost 1.58 QUIET COMPONENTS system thread python3) + # libboost_python3.7 style libraries + message("Looking for libboost_python${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}") + FIND_PACKAGE(Boost 1.58 QUIET COMPONENTS python${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}) - # Next try boost/python38 + # libboost_python3 style libraries if (NOT Boost_FOUND) - message("Looking for boost/python38") - find_package(Boost 1.58 QUIET COMPONENTS system thread python38) + message("Looking for libboost_python${PYTHON_VERSION_MAJOR}") + FIND_PACKAGE(Boost 1.58 QUIET COMPONENTS python${PYTHON_VERSION_MAJOR}) endif() - # Next try boost/python37 + # libboost_python style libraries if (NOT Boost_FOUND) - message("Looking for boost/python37") - find_package(Boost 1.58 QUIET COMPONENTS system thread python37) + message("Looking for libboost_python") + FIND_PACKAGE(Boost 1.58 QUIET COMPONENTS system thread python) endif() - # Next try boost/python-py36 + # libboost_python-py37 style libraries if (NOT Boost_FOUND) - message("Looking for boost/python-py36") - find_package(Boost 1.58 QUIET COMPONENTS system thread python-py36) + message("Looking for libboost_python-py${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}") + FIND_PACKAGE(Boost 1.58 QUIET COMPONENTS python-py${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}) endif() - # Next try boost/python36 + # libboost_python3-py37 style libraries if (NOT Boost_FOUND) - message("Looking for boost/python36") - find_package(Boost 1.58 QUIET COMPONENTS system thread python36) + message("Looking for libboost_python3-py${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}") + FIND_PACKAGE(Boost 1.58 QUIET COMPONENTS python3-py${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}) endif() # Nothing worked @@ -95,15 +106,18 @@ if ( NOT NO_PYTHON ) message("") message(FATAL_ERROR "Failed to find boost libraries!") endif() + else() add_definitions( -DNO_PYTHON ) endif() + ##################################### # BZIP2 ##################################### find_package(BZip2 QUIET REQUIRED) + ##################################### # ZeroMQ ##################################### @@ -112,7 +126,7 @@ find_package(ZeroMQ QUIET) # ZeroMQ does not always support cmake, use brute force if (NOT ZeroMQ_FOUND) - + # Convert LD_LIBRARY PATH for search if(DEFINED ENV{LD_LIBRARY_PATH}) string(REPLACE ":" ";" HINT_PATHS $ENV{LD_LIBRARY_PATH}) @@ -121,12 +135,12 @@ if (NOT ZeroMQ_FOUND) endif() # See if zmq library is in LD_LIBRARY_PATH - find_library(ZeroMQ_LIBRARY - NAMES zmq + find_library(ZeroMQ_LIBRARY + NAMES zmq PATHS ${HINT_PATHS}) # Found it - if (ZeroMQ_LIBRARY) + if (ZeroMQ_LIBRARY) # Get the base directory get_filename_component(ZMQ_LIBDIR ${ZeroMQ_LIBRARY} DIRECTORY) @@ -145,8 +159,10 @@ if (NOT ZeroMQ_FOUND) message("") message(FATAL_ERROR "Failed to find zeroMQ!") endif() + endif() + ##################################### # EPICS V3 ##################################### @@ -156,7 +172,7 @@ if((NOT NO_PYTHON) AND (NOT NO_EPICS) AND DEFINED ENV{EPICS_BASE}) if(DEFINED ENV{EPICS_HOST_ARCH}) set(EPICS_ARCH $ENV{EPICS_HOST_ARCH}) else() - execute_process(COMMAND ${EPICS_BASE_DIR}/startup/EpicsHostArch + execute_process(COMMAND ${EPICS_BASE_DIR}/startup/EpicsHostArch OUTPUT_VARIABLE EPICS_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE) string(REGEX REPLACE "\n$" "" EPICS_ARCH "${EPICS_ARCH}") endif() @@ -178,33 +194,35 @@ if((NOT NO_PYTHON) AND (NOT NO_EPICS) AND DEFINED ENV{EPICS_BASE}) set(EPICS_INCLUDES ${EPICS_PCAS_DIR}/include ${EPICS_BASE_DIR}/include - ${EPICS_BASE_DIR}/include/compiler/gcc + ${EPICS_BASE_DIR}/include/compiler/clang ${EPICS_BASE_DIR}/include/os/Darwin) - set(EPICS_LIBRARIES ${EPICS_PCAS_DIR}/lib/${EPICS_ARCH}/libcas.dylib + set(EPICS_LIBRARIES ${EPICS_PCAS_DIR}/lib/${EPICS_ARCH}/libcas.dylib ${EPICS_PCAS_DIR}/lib/${EPICS_ARCH}/libgdd.dylib - ${EPICS_BASE_DIR}/lib/${EPICS_ARCH}/libca.dylib + ${EPICS_BASE_DIR}/lib/${EPICS_ARCH}/libca.dylib ${EPICS_BASE_DIR}/lib/${EPICS_ARCH}/libCom.dylib ) else() set(EPICS_INCLUDES ${EPICS_PCAS_DIR}/include ${EPICS_BASE_DIR}/include - ${EPICS_BASE_DIR}/include/compiler/gcc + ${EPICS_BASE_DIR}/include/compiler/gcc ${EPICS_BASE_DIR}/include/os/Linux) - set(EPICS_LIBRARIES ${EPICS_PCAS_DIR}/lib/${EPICS_ARCH}/libcas.so + set(EPICS_LIBRARIES ${EPICS_PCAS_DIR}/lib/${EPICS_ARCH}/libcas.so ${EPICS_PCAS_DIR}/lib/${EPICS_ARCH}/libgdd.so - ${EPICS_BASE_DIR}/lib/${EPICS_ARCH}/libca.so + ${EPICS_BASE_DIR}/lib/${EPICS_ARCH}/libca.so ${EPICS_BASE_DIR}/lib/${EPICS_ARCH}/libCom.so ) endif() + else() set(DO_EPICS_V3 0) endif() + ########################################################## # Generate version with GIT If Not Passed As -DVERSION ########################################################## -if ( NOT ROGUE_VERSION ) +if ( NOT ROGUE_VERSION ) # Set version from git tag find_package(Git QUIET) @@ -213,20 +231,20 @@ if ( NOT ROGUE_VERSION ) COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_SOURCE_DIR}/.git --work-tree=${CMAKE_SOURCE_DIR} describe --tags --dirty OUTPUT_VARIABLE ROGUE_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - - string(REGEX MATCH "^v([0-9]+)\\.([0-9]+)" ROGUE_SOVER ${ROGUE_VERSION}) else() message("") message(FATAL_ERROR "Git is required to build rogue!") endif() endif() +string(REGEX MATCH "^v([0-9]+)\\.([0-9]+)" ROGUE_SOVER ${ROGUE_VERSION}) + ##################################### # Setup Type and Directories ##################################### # Default install type -if ( NOT ROGUE_INSTALL ) +if ( NOT ROGUE_INSTALL ) if (DEFINED ENV{CONDA_PREFIX}) set (ROGUE_INSTALL "conda") else() @@ -237,9 +255,11 @@ endif() # Default Install directory if (${ROGUE_INSTALL} STREQUAL "local") set (ROGUE_DIR ${PROJECT_SOURCE_DIR}) -elseif (NOT ROGUE_DIR) +elseif (NOT ROGUE_DIR) if (${ROGUE_INSTALL} STREQUAL "custom") set (ROGUE_DIR "$ENV{CONDA_PREFIX}/${CMAKE_INSTALL_PREFIX}/rogue") + elseif (${ROGUE_INSTALL} STREQUAL "target_arch") + set (ROGUE_DIR "${PROJECT_BINARY_DIR}") elseif (${ROGUE_INSTALL} STREQUAL "conda") set (ROGUE_DIR "$ENV{CONDA_PREFIX}") else() @@ -247,6 +267,15 @@ elseif (NOT ROGUE_DIR) endif() endif() +if ( NOT CMAKE_INSTALL_LIBDIR ) + set (CMAKE_INSTALL_LIBDIR "${ROGUE_DIR}/lib") +endif() + +if ( NOT CMAKE_INSTALL_INCLUDEDIR ) + set (CMAKE_INSTALL_INCLUDEDIR "${ROGUE_DIR}/include") +endif() + + ##################################### # Setup build, core library ##################################### @@ -286,34 +315,34 @@ set_target_properties(rogue-core-shared PROPERTIES OUTPUT_NAME librogue-core) set_target_properties(rogue-core-shared PROPERTIES PREFIX "" SUFFIX ".so") set_target_properties(rogue-core-shared PROPERTIES VERSION ${ROGUE_VERSION} SOVERSION ${ROGUE_SOVER}) -# Link rogue core to boost, python and bzip -TARGET_LINK_LIBRARIES(rogue-core-shared LINK_PUBLIC ${Boost_LIBRARIES}) -TARGET_LINK_LIBRARIES(rogue-core-shared LINK_PUBLIC ${ZeroMQ_LIBRARY}) -TARGET_LINK_LIBRARIES(rogue-core-shared LINK_PUBLIC ${EPICS_LIBRARIES}) -TARGET_LINK_LIBRARIES(rogue-core-shared LINK_PUBLIC ${BZIP2_LIBRARIES}) +TARGET_LINK_LIBRARIES(rogue-core-shared PUBLIC ${Boost_LIBRARIES}) +TARGET_LINK_LIBRARIES(rogue-core-shared PUBLIC ${ZeroMQ_LIBRARY}) +TARGET_LINK_LIBRARIES(rogue-core-shared PUBLIC ${EPICS_LIBRARIES}) +TARGET_LINK_LIBRARIES(rogue-core-shared PUBLIC ${BZIP2_LIBRARIES}) # Do not link directly against python in mac os if (APPLE) set_target_properties(rogue-core-shared PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") else() - TARGET_LINK_LIBRARIES(rogue-core-shared LINK_PUBLIC ${PYTHON_LIBRARIES}) - TARGET_LINK_LIBRARIES(rogue-core-shared LINK_PUBLIC rt) + TARGET_LINK_LIBRARIES(rogue-core-shared PUBLIC ${PYTHON_LIBRARIES}) + TARGET_LINK_LIBRARIES(rogue-core-shared PUBLIC rt) endif() -if(STATIC_LIB) +if(STATIC_LIB) add_library(rogue-core-static STATIC $ "") set_target_properties(rogue-core-static PROPERTIES OUTPUT_NAME librogue-core) set_target_properties(rogue-core-static PROPERTIES PREFIX "" SUFFIX ".a") # Link rogue core to boost, python and bzip - TARGET_LINK_LIBRARIES(rogue-core-static LINK_PUBLIC ${Boost_LIBRARIES}) - TARGET_LINK_LIBRARIES(rogue-core-static LINK_PUBLIC ${ZeroMQ_LIBRARY}) - TARGET_LINK_LIBRARIES(rogue-core-static LINK_PUBLIC ${EPICS_LIBRARIES}) - TARGET_LINK_LIBRARIES(rogue-core-static LINK_PUBLIC ${BZIP2_LIBRARIES}) - TARGET_LINK_LIBRARIES(rogue-core-static LINK_PUBLIC ${PYTHON_LIBRARIES}) - TARGET_LINK_LIBRARIES(rogue-core-static LINK_PUBLIC rt) + TARGET_LINK_LIBRARIES(rogue-core-static PUBLIC ${Boost_LIBRARIES}) + TARGET_LINK_LIBRARIES(rogue-core-static PUBLIC ${ZeroMQ_LIBRARY}) + TARGET_LINK_LIBRARIES(rogue-core-static PUBLIC ${EPICS_LIBRARIES}) + TARGET_LINK_LIBRARIES(rogue-core-static PUBLIC ${BZIP2_LIBRARIES}) + TARGET_LINK_LIBRARIES(rogue-core-static PUBLIC ${PYTHON_LIBRARIES}) + TARGET_LINK_LIBRARIES(rogue-core-static PUBLIC rt) endif() + ##################################### # Setup build, python library ##################################### @@ -334,30 +363,31 @@ if (NOT NO_PYTHON) endif() # Link to rogue core - TARGET_LINK_LIBRARIES(rogue LINK_PUBLIC rogue-core-shared) + TARGET_LINK_LIBRARIES(rogue PUBLIC rogue-core-shared) else() add_definitions( -DNO_PYTHON ) endif() + ######################################### # Configuration & Setup Script Generation ######################################### -set(CONF_INCLUDE_DIRS ${ROGUE_DIR}/include) +set(CONF_INCLUDE_DIRS ${CMAKE_INSTALL_INCLUDEDIR}) # Setup configuration file if ((${ROGUE_INSTALL} STREQUAL "system") OR (${ROGUE_INSTALL} STREQUAL "conda")) - set(CONF_LIBRARIES LINK_PUBLIC rogue-core) + set(CONF_LIBRARIES PUBLIC rogue-core) else() if (APPLE) - set(CONF_LIBRARIES ${ROGUE_DIR}/lib/librogue-core.${ROGUE_SOVER}.dylib) + set(CONF_LIBRARIES ${CMAKE_INSTALL_LIBDIR}/librogue-core.${ROGUE_SOVER}.dylib) else() - set(CONF_LIBRARIES ${ROGUE_DIR}/lib/librogue-core.so.${ROGUE_SOVER}) + set(CONF_LIBRARIES ${CMAKE_INSTALL_LIBDIR}/librogue-core.so.${ROGUE_SOVER}) endif() endif() # Create the config file -configure_file(${PROJECT_SOURCE_DIR}/templates/RogueConfig.cmake.in +configure_file(${PROJECT_SOURCE_DIR}/templates/RogueConfig.cmake.in ${PROJECT_BINARY_DIR}/RogueConfig.cmake @ONLY) # Create the setup files @@ -370,18 +400,19 @@ configure_file(${PROJECT_SOURCE_DIR}/templates/setup_rogue.sh.in configure_file(${PROJECT_SOURCE_DIR}/templates/setup.py.in ${PROJECT_BINARY_DIR}/setup.py) + ##################################### # Install Setup ##################################### # Always install core libraries and config files if (STATIC_LIB) - install(TARGETS rogue-core-static LIBRARY DESTINATION ${ROGUE_DIR}/lib ARCHIVE DESTINATION ${ROGUE_DIR}/lib) + install(TARGETS rogue-core-static LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() -install(TARGETS rogue-core-shared LIBRARY DESTINATION ${ROGUE_DIR}/lib ARCHIVE DESTINATION ${ROGUE_DIR}/lib) +install(TARGETS rogue-core-shared LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(FILES ${PROJECT_BINARY_DIR}/RogueConfig.cmake DESTINATION ${ROGUE_DIR}/lib) +install(FILES ${PROJECT_BINARY_DIR}/RogueConfig.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}) # Copy setup files for local or custom if ((${ROGUE_INSTALL} STREQUAL "custom") OR (${ROGUE_INSTALL} STREQUAL "local")) @@ -390,7 +421,7 @@ endif() # Install header files for non local installs if (NOT (${ROGUE_INSTALL} STREQUAL "local")) - install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/rogue DESTINATION ${ROGUE_DIR}/include FILES_MATCHING PATTERN "*.h") + install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/rogue DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h") endif() # Conda activate and deactivate functions @@ -411,21 +442,22 @@ if (NOT NO_PYTHON) # Use setuptools with python3 for system elseif (${ROGUE_INSTALL} STREQUAL "system") - install(CODE "execute_process(COMMAND python3 ${PROJECT_SOURCE_DIR}/build/setup.py install)") - + install(CODE "execute_process(COMMAND python3 ${PROJECT_BINARY_DIR}/setup.py install)") + # Use setuptools with python for anaconda elseif (${ROGUE_INSTALL} STREQUAL "conda") - install(CODE "execute_process(COMMAND python - ${PROJECT_SOURCE_DIR}/build/setup.py install --prefix=${ROGUE_DIR})") + install(CODE "execute_process(COMMAND python + ${PROJECT_BINARY_DIR}/setup.py install --prefix=${ROGUE_DIR})") endif() # Do byte compile for custom or local if ((${ROGUE_INSTALL} STREQUAL "custom") OR (${ROGUE_INSTALL} STREQUAL "local")) install(CODE "execute_process(COMMAND python3 -m compileall ${ROGUE_DIR}/python)") - endif() + endif() endif() + ##################################### # Print status ##################################### @@ -443,9 +475,9 @@ if (NO_PYTHON) message("-- Compiling without boost & python!") else() message("-- Found boost: ${Boost_INCLUDE_DIRS}") + message("-- Found boost: ${Boost_LIBRARIES}") message("") message("-- Found python: ${PYTHON_LIBRARIES}") - message("") message("-- Found numpy: ${Python3_NumPy_INCLUDE_DIRS}") endif() diff --git a/include/rogue/Logging.h b/include/rogue/Logging.h index 09975953e..a1798468e 100755 --- a/include/rogue/Logging.h +++ b/include/rogue/Logging.h @@ -8,12 +8,12 @@ * Description: * Logging interface for pyrogue * ---------------------------------------------------------------------------- - * This file is part of the rogue software platform. It is subject to - * the license terms in the LICENSE.txt file found in the top-level directory - * of this distribution and at: - * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. - * No part of the rogue software platform, including this file, may be - * copied, modified, propagated, or distributed except according to the terms + * This file is part of the rogue software platform. It is subject to + * the license terms in the LICENSE.txt file found in the top-level directory + * of this distribution and at: + * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. + * No part of the rogue software platform, including this file, may be + * copied, modified, propagated, or distributed except according to the terms * contained in the LICENSE.txt file. * ---------------------------------------------------------------------------- **/ @@ -25,6 +25,7 @@ #include #include #include +#include namespace rogue { @@ -43,9 +44,9 @@ namespace rogue { //! Logging class Logging { - - //! Global Logging level - static uint32_t gblLevel_; + + //! Global Logging level + static uint32_t gblLevel_; //! Logging level lock static std::mutex levelMtx_; diff --git a/include/rogue/interfaces/memory/Transaction.h b/include/rogue/interfaces/memory/Transaction.h index 452d9eaac..1e2a44987 100755 --- a/include/rogue/interfaces/memory/Transaction.h +++ b/include/rogue/interfaces/memory/Transaction.h @@ -27,6 +27,7 @@ #include #include #include +#include #ifndef NO_PYTHON #include diff --git a/include/rogue/interfaces/memory/TransactionLock.h b/include/rogue/interfaces/memory/TransactionLock.h index 285d5ab02..70d6a7e4b 100755 --- a/include/rogue/interfaces/memory/TransactionLock.h +++ b/include/rogue/interfaces/memory/TransactionLock.h @@ -8,12 +8,12 @@ * Description: * Memory Transaction lock * ---------------------------------------------------------------------------- - * This file is part of the rogue software platform. It is subject to - * the license terms in the LICENSE.txt file found in the top-level directory - * of this distribution and at: - * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. - * No part of the rogue software platform, including this file, may be - * copied, modified, propagated, or distributed except according to the terms + * This file is part of the rogue software platform. It is subject to + * the license terms in the LICENSE.txt file found in the top-level directory + * of this distribution and at: + * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. + * No part of the rogue software platform, including this file, may be + * copied, modified, propagated, or distributed except according to the terms * contained in the LICENSE.txt file. * ---------------------------------------------------------------------------- **/ @@ -21,6 +21,7 @@ #define __ROGUE_INTERFACES_MEMORY_TRANSACTION_LOCK_H__ #include #include +#include namespace rogue { namespace interfaces { @@ -30,7 +31,7 @@ namespace rogue { //! Transaction Lock /** - * The TransactionLock is a container for holding a lock on Transaction data while accessing + * The TransactionLock is a container for holding a lock on Transaction data while accessing * that data. This lock ensures that Transaction is not destroyed when the Slave is updating * its data and result. This object is created by calling Transaction::lock(). */ @@ -65,7 +66,7 @@ namespace rogue { void unlock(); //! Enter method for python, does nothing - /** This exists only to support the + /** This exists only to support the * with call in python. * * Exposed as __enter__() to Python @@ -73,7 +74,7 @@ namespace rogue { void enter(); //! Exit method for python, does nothing - /** This exists only to support the + /** This exists only to support the * with call in python. * * Exposed as __exit__() to Python diff --git a/include/rogue/interfaces/stream/FrameLock.h b/include/rogue/interfaces/stream/FrameLock.h index de3ad9a94..1ed7da336 100755 --- a/include/rogue/interfaces/stream/FrameLock.h +++ b/include/rogue/interfaces/stream/FrameLock.h @@ -8,12 +8,12 @@ * Description: * Memory Frame lock * ---------------------------------------------------------------------------- - * This file is part of the rogue software platform. It is subject to - * the license terms in the LICENSE.txt file found in the top-level directory - * of this distribution and at: - * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. - * No part of the rogue software platform, including this file, may be - * copied, modified, propagated, or distributed except according to the terms + * This file is part of the rogue software platform. It is subject to + * the license terms in the LICENSE.txt file found in the top-level directory + * of this distribution and at: + * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. + * No part of the rogue software platform, including this file, may be + * copied, modified, propagated, or distributed except according to the terms * contained in the LICENSE.txt file. * ---------------------------------------------------------------------------- **/ @@ -21,6 +21,7 @@ #define __ROGUE_INTERFACES_MEMORY_FRAME_LOCK_H__ #include #include +#include namespace rogue { namespace interfaces { @@ -71,7 +72,7 @@ namespace rogue { void unlock(); //! Enter method for python, does nothing - /** This exists only to support the + /** This exists only to support the * with call in python. * * Exposed as __enter__() to Python @@ -79,7 +80,7 @@ namespace rogue { void enter(); //! Exit method for python, does nothing - /** This exists only to support the + /** This exists only to support the * with call in python. * * Exposed as __exit__() to Python diff --git a/include/rogue/protocols/packetizer/Core.h b/include/rogue/protocols/packetizer/Core.h index c38d8e616..9a1b7278c 100755 --- a/include/rogue/protocols/packetizer/Core.h +++ b/include/rogue/protocols/packetizer/Core.h @@ -5,12 +5,12 @@ * Description: * Packetizer Core * ---------------------------------------------------------------------------- - * This file is part of the rogue software platform. It is subject to - * the license terms in the LICENSE.txt file found in the top-level directory - * of this distribution and at: - * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. - * No part of the rogue software platform, including this file, may be - * copied, modified, propagated, or distributed except according to the terms + * This file is part of the rogue software platform. It is subject to + * the license terms in the LICENSE.txt file found in the top-level directory + * of this distribution and at: + * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. + * No part of the rogue software platform, including this file, may be + * copied, modified, propagated, or distributed except according to the terms * contained in the LICENSE.txt file. * ---------------------------------------------------------------------------- **/ @@ -18,6 +18,7 @@ #define __ROGUE_PROTOCOLS_PACKETIZER_CORE_H__ #include #include +#include namespace rogue { namespace protocols { diff --git a/include/rogue/protocols/packetizer/CoreV2.h b/include/rogue/protocols/packetizer/CoreV2.h index e6bb7ef68..d2f61d28c 100755 --- a/include/rogue/protocols/packetizer/CoreV2.h +++ b/include/rogue/protocols/packetizer/CoreV2.h @@ -8,12 +8,12 @@ * Description: * Packetizer Core, Version 2 * ---------------------------------------------------------------------------- - * This file is part of the rogue software platform. It is subject to - * the license terms in the LICENSE.txt file found in the top-level directory - * of this distribution and at: - * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. - * No part of the rogue software platform, including this file, may be - * copied, modified, propagated, or distributed except according to the terms + * This file is part of the rogue software platform. It is subject to + * the license terms in the LICENSE.txt file found in the top-level directory + * of this distribution and at: + * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. + * No part of the rogue software platform, including this file, may be + * copied, modified, propagated, or distributed except according to the terms * contained in the LICENSE.txt file. * ---------------------------------------------------------------------------- **/ @@ -21,6 +21,7 @@ #define __ROGUE_PROTOCOLS_PACKETIZER_CORE_V2_H__ #include #include +#include namespace rogue { namespace protocols { diff --git a/include/rogue/protocols/rssi/Client.h b/include/rogue/protocols/rssi/Client.h index 379ca6981..6cb941ded 100755 --- a/include/rogue/protocols/rssi/Client.h +++ b/include/rogue/protocols/rssi/Client.h @@ -5,12 +5,12 @@ * Description: * UDP Client * ---------------------------------------------------------------------------- - * This file is part of the rogue software platform. It is subject to - * the license terms in the LICENSE.txt file found in the top-level directory - * of this distribution and at: - * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. - * No part of the rogue software platform, including this file, may be - * copied, modified, propagated, or distributed except according to the terms + * This file is part of the rogue software platform. It is subject to + * the license terms in the LICENSE.txt file found in the top-level directory + * of this distribution and at: + * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. + * No part of the rogue software platform, including this file, may be + * copied, modified, propagated, or distributed except according to the terms * contained in the LICENSE.txt file. * ---------------------------------------------------------------------------- **/ @@ -18,6 +18,7 @@ #define __ROGUE_PROTOCOLS_RSSI_CLIENT_H__ #include #include +#include namespace rogue { namespace protocols { @@ -70,7 +71,7 @@ namespace rogue { //! Get Retransmit Count uint32_t getRetranCount(); - + //! Get locBusy bool getLocBusy(); diff --git a/include/rogue/protocols/rssi/Server.h b/include/rogue/protocols/rssi/Server.h index 1e6e81dd4..4c0166a29 100755 --- a/include/rogue/protocols/rssi/Server.h +++ b/include/rogue/protocols/rssi/Server.h @@ -5,12 +5,12 @@ * File : Server.h * Created : 2017-06-13 * ---------------------------------------------------------------------------- - * This file is part of the rogue software platform. It is subject to - * the license terms in the LICENSE.txt file found in the top-level directory - * of this distribution and at: - * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. - * No part of the rogue software platform, including this file, may be - * copied, modified, propagated, or distributed except according to the terms + * This file is part of the rogue software platform. It is subject to + * the license terms in the LICENSE.txt file found in the top-level directory + * of this distribution and at: + * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. + * No part of the rogue software platform, including this file, may be + * copied, modified, propagated, or distributed except according to the terms * contained in the LICENSE.txt file. * ---------------------------------------------------------------------------- **/ @@ -18,6 +18,7 @@ #define __ROGUE_PROTOCOLS_RSSI_SERVER_H__ #include #include +#include namespace rogue { namespace protocols { diff --git a/src/rogue/interfaces/memory/Master.cpp b/src/rogue/interfaces/memory/Master.cpp index ef9548e0d..e7659d4f3 100755 --- a/src/rogue/interfaces/memory/Master.cpp +++ b/src/rogue/interfaces/memory/Master.cpp @@ -153,8 +153,13 @@ uint32_t rim::Master::reqTransaction(uint64_t address, uint32_t size, void *data uint32_t rim::Master::reqTransactionPy(uint64_t address, boost::python::object p, uint32_t size, uint32_t offset, uint32_t type) { rim::TransactionPtr tran = rim::Transaction::create(sumTime_); - if ( PyObject_GetBuffer(p.ptr(),&(tran->pyBuf_),PyBUF_SIMPLE) < 0 ) - throw(rogue::GeneralError("Master::reqTransactionPy","Python Buffer Error")); + if ( (type == rim::Read) || (type == rim::Verify) ) { + if ( PyObject_GetBuffer(p.ptr(),&(tran->pyBuf_),PyBUF_CONTIG) < 0 ) + throw(rogue::GeneralError("Master::reqTransactionPy","Python Buffer Contig Error")); + } else { + if ( PyObject_GetBuffer(p.ptr(),&(tran->pyBuf_),PyBUF_SIMPLE) < 0 ) + throw(rogue::GeneralError("Master::reqTransactionPy","Python Buffer SImple Error")); + } if ( size == 0 ) tran->size_ = tran->pyBuf_.len; else tran->size_ = size; @@ -238,7 +243,7 @@ void rim::Master::copyBits(boost::python::object dst, uint32_t dstLsb, boost::py uint32_t rem; uint32_t bytes; - if ( PyObject_GetBuffer(dst.ptr(),&dstBuf,PyBUF_SIMPLE) < 0 ) + if ( PyObject_GetBuffer(dst.ptr(),&dstBuf,PyBUF_CONTIG) < 0 ) throw(rogue::GeneralError("Master::copyBits","Python Buffer Error")); if ( (dstLsb + size) > (dstBuf.len*8) ) { @@ -305,7 +310,7 @@ void rim::Master::setBits(boost::python::object dst, uint32_t lsb, uint32_t size uint32_t rem; uint32_t bytes; - if ( PyObject_GetBuffer(dst.ptr(),&dstBuf,PyBUF_SIMPLE) < 0 ) + if ( PyObject_GetBuffer(dst.ptr(),&dstBuf,PyBUF_CONTIG) < 0 ) throw(rogue::GeneralError("Master::setBits","Python Buffer Error")); if ( (lsb + size) > (dstBuf.len*8) ) { diff --git a/src/rogue/interfaces/memory/Transaction.cpp b/src/rogue/interfaces/memory/Transaction.cpp index 14f304763..33d18ff1f 100755 --- a/src/rogue/interfaces/memory/Transaction.cpp +++ b/src/rogue/interfaces/memory/Transaction.cpp @@ -232,8 +232,8 @@ rim::Transaction::iterator rim::Transaction::end() { void rim::Transaction::setData ( boost::python::object p, uint32_t offset ) { Py_buffer pyBuf; - if ( PyObject_GetBuffer(p.ptr(),&pyBuf,PyBUF_CONTIG) < 0 ) - throw(rogue::GeneralError("Transaction::writePy","Python Buffer Error In Frame")); + if ( PyObject_GetBuffer(p.ptr(),&pyBuf,PyBUF_SIMPLE) < 0 ) + throw(rogue::GeneralError("Transaction::setData","Python Buffer Error In Frame")); uint32_t count = pyBuf.len; @@ -252,8 +252,8 @@ void rim::Transaction::setData ( boost::python::object p, uint32_t offset ) { void rim::Transaction::getData ( boost::python::object p, uint32_t offset ) { Py_buffer pyBuf; - if ( PyObject_GetBuffer(p.ptr(),&pyBuf,PyBUF_SIMPLE) < 0 ) - throw(rogue::GeneralError("Transaction::readPy","Python Buffer Error In Frame")); + if ( PyObject_GetBuffer(p.ptr(),&pyBuf,PyBUF_CONTIG) < 0 ) + throw(rogue::GeneralError("Transaction::getData","Python Buffer Error In Frame")); uint32_t count = pyBuf.len; diff --git a/src/rogue/interfaces/stream/Frame.cpp b/src/rogue/interfaces/stream/Frame.cpp index d741132f5..65826301b 100755 --- a/src/rogue/interfaces/stream/Frame.cpp +++ b/src/rogue/interfaces/stream/Frame.cpp @@ -9,12 +9,12 @@ * Stream frame container * Some concepts borrowed from CPSW by Till Straumann * ---------------------------------------------------------------------------- - * This file is part of the rogue software platform. It is subject to - * the license terms in the LICENSE.txt file found in the top-level directory - * of this distribution and at: - * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. - * No part of the rogue software platform, including this file, may be - * copied, modified, propagated, or distributed except according to the terms + * This file is part of the rogue software platform. It is subject to + * the license terms in the LICENSE.txt file found in the top-level directory + * of this distribution and at: + * https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. + * No part of the rogue software platform, including this file, may be + * copied, modified, propagated, or distributed except according to the terms * contained in the LICENSE.txt file. * ---------------------------------------------------------------------------- **/ @@ -130,7 +130,7 @@ void ris::Frame::setSizeDirty() { /* * Get size of buffers that can hold - * payload data. This function + * payload data. This function * returns the full buffer size minus * the head and tail reservation. */ @@ -151,7 +151,7 @@ uint32_t ris::Frame::getAvailable() { /* * Get real payload size without header - * This is the count of real data in the + * This is the count of real data in the * packet, minus the portion reserved for * the head. */ @@ -162,7 +162,7 @@ uint32_t ris::Frame::getPayload() { /* * Set payload size (not including header) - * If passed size is less then current, + * If passed size is less then current, * the frame payload size will be decreased. */ void ris::Frame::setPayload(uint32_t pSize) { @@ -193,7 +193,7 @@ void ris::Frame::setPayload(uint32_t pSize) { } } - if ( lSize != 0 ) + if ( lSize != 0 ) throw(rogue::GeneralError::create("Frame::setPayload", "Attempt to set payload to size %i in frame with size %i", pSize,size_)); @@ -345,7 +345,7 @@ ris::FrameIterator ris::Frame::endWrite() { void ris::Frame::readPy ( boost::python::object p, uint32_t offset ) { Py_buffer pyBuf; - if ( PyObject_GetBuffer(p.ptr(),&pyBuf,PyBUF_SIMPLE) < 0 ) + if ( PyObject_GetBuffer(p.ptr(),&pyBuf,PyBUF_CONTIG) < 0 ) throw(rogue::GeneralError("Frame::readPy","Python Buffer Error In Frame")); uint32_t size = getPayload(); @@ -368,7 +368,7 @@ void ris::Frame::readPy ( boost::python::object p, uint32_t offset ) { void ris::Frame::writePy ( boost::python::object p, uint32_t offset ) { Py_buffer pyBuf; - if ( PyObject_GetBuffer(p.ptr(),&pyBuf,PyBUF_CONTIG) < 0 ) + if ( PyObject_GetBuffer(p.ptr(),&pyBuf,PyBUF_SIMPLE) < 0 ) throw(rogue::GeneralError("Frame::writePy","Python Buffer Error In Frame")); uint32_t size = getSize(); @@ -382,7 +382,7 @@ void ris::Frame::writePy ( boost::python::object p, uint32_t offset ) { minPayload(offset+count); ris::FrameIterator beg = this->begin() + offset; - ris::toFrame(beg, count, (uint8_t *)pyBuf.buf); + ris::toFrame(beg, count, (uint8_t *)pyBuf.buf); PyBuffer_Release(&pyBuf); } @@ -428,10 +428,10 @@ void ris::Frame::putNumpy ( boost::python::object p, uint32_t offset ) { } - // Cast to an array object and check that the numpy array + // Cast to an array object and check that the numpy array // data buffer is write-able and contiguous // The write routine can only deal with contiguous buffers. - PyArrayObject *arr = reinterpret_cast(obj); + PyArrayObject *arr = reinterpret_cast(obj); int flags = PyArray_FLAGS (arr); bool ctg = flags & (NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS); if ( !ctg ) { @@ -456,7 +456,7 @@ void ris::Frame::putNumpy ( boost::python::object p, uint32_t offset ) { // Write the numpy data to the array ris::FrameIterator beg = this->begin() + offset; - ris::toFrame (beg, count, src); + ris::toFrame (beg, count, src); // If were forced to make a temporary copy, release it if (!ctg) { @@ -502,7 +502,7 @@ void ris::Frame::debug() { ris::Frame::BufferIterator it; uint32_t idx = 0; - printf("Frame Info. BufferCount: %i, Size: %i, Available: %i, Payload: %i, Channel: %i, Error: 0x%x, Flags: 0x%x\n", + printf("Frame Info. BufferCount: %i, Size: %i, Available: %i, Payload: %i, Channel: %i, Error: 0x%x, Flags: 0x%x\n", bufferCount(), getSize(), getAvailable(), getPayload(), getChannel(), getError(), getFlags()); for (it = buffers_.begin(); it != buffers_.end(); ++it) { diff --git a/templates/RogueConfig.cmake.in b/templates/RogueConfig.cmake.in index 1a188f244..8001017f8 100644 --- a/templates/RogueConfig.cmake.in +++ b/templates/RogueConfig.cmake.in @@ -6,12 +6,12 @@ # Description: # Rogue export file to be overridden by Cmake. # ---------------------------------------------------------------------------- -# This file is part of the rogue software platform. It is subject to -# the license terms in the LICENSE.txt file found in the top-level directory -# of this distribution and at: -# https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. -# No part of the rogue software platform, including this file, may be -# copied, modified, propagated, or distributed except according to the terms +# This file is part of the rogue software package. It is subject to +# the license terms in the LICENSE.txt file found in the top-level directory +# of this distribution and at: +# https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +# No part of the rogue software package, including this file, may be +# copied, modified, propagated, or distributed except according to the terms # contained in the LICENSE.txt file. # ---------------------------------------------------------------------------- @@ -26,9 +26,9 @@ set(NO_EPICS @NO_EPICS@) ##################################### # Boost + Python ##################################### -if ( NOT NO_PYTHON ) - find_package(PythonInterp 3.6 QUIET REQUIRED) - find_package(PythonLibs 3.6 QUIET REQUIRED) +if ( NOT NO_PYTHON ) + find_package(PythonInterp 3 QUIET REQUIRED) + find_package(PythonLibs 3 QUIET REQUIRED) # Find Numpy execute_process( @@ -44,36 +44,43 @@ if ( NOT NO_PYTHON ) endif() set(Boost_USE_MULTITHREADED ON) + set(Boost_NO_BOOST_CMAKE ON) - # Boost may need help on SLAC machines - set(BOOST_ROOT:PATHNAME $ENV{BOOST_PATH}) + # Hint for boost on anaconda + if (DEFINED ENV{CONDA_PREFIX}) + set(BOOST_ROOT $ENV{CONDA_PREFIX}) - # First try standard suffix for boost - message("Looking for boost/python3") - find_package(Boost 1.58 QUIET COMPONENTS system thread python3) + # SLAC AFS custom path + elseif (DEFINED ENV{BOOST_PATH}) + set(BOOST_ROOT $ENV{BOOST_PATH}) + endif() + + # libboost_python3.7 style libraries + message("Looking for libboost_python${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}") + FIND_PACKAGE(Boost 1.58 QUIET COMPONENTS python${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}) - # Next try boost/python38 + # libboost_python3 style libraries if (NOT Boost_FOUND) - message("Looking for boost/python38") - find_package(Boost 1.58 QUIET COMPONENTS system thread python38) + message("Looking for libboost_python${PYTHON_VERSION_MAJOR}") + FIND_PACKAGE(Boost 1.58 QUIET COMPONENTS python${PYTHON_VERSION_MAJOR}) endif() - # Next try boost/python37 + # libboost_python style libraries if (NOT Boost_FOUND) - message("Looking for boost/python37") - find_package(Boost 1.58 QUIET COMPONENTS system thread python37) + message("Looking for libboost_python") + FIND_PACKAGE(Boost 1.58 QUIET COMPONENTS system thread python) endif() - # Next try boost/python-py36 + # libboost_python-py37 style libraries if (NOT Boost_FOUND) - message("Looking for boost/python-py36") - find_package(Boost 1.58 QUIET COMPONENTS system thread python-py36) + message("Looking for libboost_python-py${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}") + FIND_PACKAGE(Boost 1.58 QUIET COMPONENTS python-py${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}) endif() - # Next try boost/python36 + # libboost_python3-py37 style libraries if (NOT Boost_FOUND) - message("Looking for boost/python36") - find_package(Boost 1.58 QUIET COMPONENTS system thread python36) + message("Looking for libboost_python3-py${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}") + FIND_PACKAGE(Boost 1.58 QUIET COMPONENTS python3-py${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}) endif() # Nothing worked @@ -93,12 +100,12 @@ find_package(BZip2 QUIET REQUIRED) ##################################### # ZeroMQ ##################################### -# First try with Cmake packages +# First try with cmake packages find_package(ZeroMQ QUIET) # ZeroMQ does not always support cmake, use brute force if (NOT ZeroMQ_FOUND) - + # Convert LD_LIBRARY PATH for search if(DEFINED ENV{LD_LIBRARY_PATH}) string(REPLACE ":" ";" HINT_PATHS $ENV{LD_LIBRARY_PATH}) @@ -107,12 +114,12 @@ if (NOT ZeroMQ_FOUND) endif() # See if zmq library is in LD_LIBRARY_PATH - find_library(ZeroMQ_LIBRARY - NAMES zmq + find_library(ZeroMQ_LIBRARY + NAMES zmq PATHS ${HINT_PATHS}) # Found it - if (ZeroMQ_LIBRARY) + if (ZeroMQ_LIBRARY) # Get the base directory get_filename_component(ZMQ_LIBDIR ${ZeroMQ_LIBRARY} DIRECTORY) @@ -142,7 +149,7 @@ if((NOT NO_PYTHON) AND (NOT NO_EPICS) AND DEFINED ENV{EPICS_BASE}) if(DEFINED ENV{EPICS_HOST_ARCH}) set(EPICS_ARCH $ENV{EPICS_HOST_ARCH}) else() - execute_process(COMMAND ${EPICS_BASE_DIR}/startup/EpicsHostArch + execute_process(COMMAND ${EPICS_BASE_DIR}/startup/EpicsHostArch OUTPUT_VARIABLE EPICS_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE) string(REGEX REPLACE "\n$" "" EPICS_ARCH "${EPICS_ARCH}") endif() @@ -164,25 +171,26 @@ if((NOT NO_PYTHON) AND (NOT NO_EPICS) AND DEFINED ENV{EPICS_BASE}) set(EPICS_INCLUDES ${EPICS_PCAS_DIR}/include ${EPICS_BASE_DIR}/include - ${EPICS_BASE_DIR}/include/compiler/gcc + ${EPICS_BASE_DIR}/include/compiler/gcc ${EPICS_BASE_DIR}/include/os/Darwin) - set(EPICS_LIBRARIES ${EPICS_PCAS_DIR}/lib/${EPICS_ARCH}/libcas.dylib + set(EPICS_LIBRARIES ${EPICS_PCAS_DIR}/lib/${EPICS_ARCH}/libcas.dylib ${EPICS_PCAS_DIR}/lib/${EPICS_ARCH}/libgdd.dylib - ${EPICS_BASE_DIR}/lib/${EPICS_ARCH}/libca.dylib + ${EPICS_BASE_DIR}/lib/${EPICS_ARCH}/libca.dylib ${EPICS_BASE_DIR}/lib/${EPICS_ARCH}/libCom.dylib ) else() set(EPICS_INCLUDES ${EPICS_PCAS_DIR}/include ${EPICS_BASE_DIR}/include - ${EPICS_BASE_DIR}/include/compiler/gcc + ${EPICS_BASE_DIR}/include/compiler/gcc ${EPICS_BASE_DIR}/include/os/Linux) - set(EPICS_LIBRARIES ${EPICS_PCAS_DIR}/lib/${EPICS_ARCH}/libcas.so + set(EPICS_LIBRARIES ${EPICS_PCAS_DIR}/lib/${EPICS_ARCH}/libcas.so ${EPICS_PCAS_DIR}/lib/${EPICS_ARCH}/libgdd.so - ${EPICS_BASE_DIR}/lib/${EPICS_ARCH}/libca.so + ${EPICS_BASE_DIR}/lib/${EPICS_ARCH}/libca.so ${EPICS_BASE_DIR}/lib/${EPICS_ARCH}/libCom.so ) endif() + else() set(DO_EPICS_V3 0) endif() @@ -246,9 +254,9 @@ if (NO_PYTHON) message("-- Compiling without boost & python!") else() message("-- Found boost: ${Boost_INCLUDE_DIRS}") + message("-- Found boost: ${Boost_LIBRARIES}") message("") message("-- Found python: ${PYTHON_LIBRARIES}") - message("") message("-- Found numpy: ${Python3_NumPy_INCLUDE_DIRS}") endif() @@ -256,6 +264,7 @@ message("") if (DO_EPICS_V3) message("-- Found EPICS: ${EPICS_BASE_DIR}") + message("") message("-- Found PCAS: ${EPICS_PCAS_DIR}") else() message("-- EPICS V3 not included!") diff --git a/tests/test_epics.py b/tests/test_epics.py index a5b1d6eca..b37c92924 100644 --- a/tests/test_epics.py +++ b/tests/test_epics.py @@ -79,11 +79,13 @@ def test_local_root(): # Test list method root.epics.list() + time.sleep(1) # Test RW a variable holding an scalar value pv_name=device_epics_prefix+':var' test_value=314 caput(pv_name, test_value) + time.sleep(1) test_result=caget(pv_name) if test_result != test_value: raise AssertionError('pv_name={}: test_value={}; test_result={}'.format(\ @@ -93,6 +95,7 @@ def test_local_root(): pv_name=device_epics_prefix+':var_float' test_value=5.67 caput(pv_name, test_value) + time.sleep(1) test_result=round(caget(pv_name),2) if test_result != test_value: raise AssertionError('pv_name={}: test_value={}; test_result={}'.format(\ diff --git a/tests/test_hub.py b/tests/test_hub.py new file mode 100644 index 000000000..945182638 --- /dev/null +++ b/tests/test_hub.py @@ -0,0 +1,291 @@ +#!/usr/bin/env python3 +#----------------------------------------------------------------------------- +# This file is part of the rogue software platform. It is subject to +# the license terms in the LICENSE.txt file found in the top-level directory +# of this distribution and at: +# https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +# No part of the rogue software platform, including this file, may be +# copied, modified, propagated, or distributed except according to the terms +# contained in the LICENSE.txt file. +#----------------------------------------------------------------------------- + +# This test file tests and demonstrates the ability to have virtual address space +# directly in a device using the hub override calls. In this example the real address +# space contains two registers, one to issue commands over SPI. The data field for these +# commands are: +# Bit 31 = read/write bit. Set to '1' for reads +# bits 30:20 = address field +# bits 19:00 = data field, ignored on read +# +# The second register is a read back register to get the results of the previous +# read command. +# +# The remaining registers in this device are virtual and read or write accesses to them +# are converted to multiple transactions using the above two handshake registers. + +import pyrogue as pr +import rogue.interfaces.memory +import threading +import random + +class HubTestDev(pr.Device): + + # Read address space of the device. + WRITE_ADDR = 0x000 + READ_ADDR = 0x004 + + # Any addresses above this value are treated as vritual + OFFSET_ADDR = 0x100 + MAX_RETRIES = 5 + + def __init__(self,**kwargs): + super().__init__(**kwargs) + + self._lock = threading.Lock() + + # Write register to initiating commands. The data field takes the following + # Format: + # Bit 31 = read/write bit. Set to '1' for reads + # bits 30:20 = address field + # bits 19:00 = data field, ignored on read + self.add(pr.RemoteVariable( + name = "Write", + offset = self.WRITE_ADDR, + bitSize = 32, + bitOffset = 0x00, + base = pr.UInt, + mode = "RW", + )) + + # Read register to get read command results. The data returned will contain + # the following data: + # Bit 31 = read/write bit. Set to '1' for reads + # bits 30:20 = address field + # bits 19:00 = data field + self.add(pr.RemoteVariable( + name = "Read", + offset = self.READ_ADDR, + bitSize = 32, + bitOffset = 0x00, + base = pr.UInt, + mode = "RO", + )) + + # Virtual registers + for i in range(10): + self.add(pr.RemoteVariable( + name = f"Reg[{i}]", + offset = self.OFFSET_ADDR + (4 * i), + bitSize = 32, + bitOffset = 0x00, + base = pr.UInt, + mode = "RW", + )) + + # Return the command field from the read data + @classmethod + def cmd_address(cls, data): # returns address data + return((data & 0x7FFF0000) >> 20) + + # Return the data field from the read data + @classmethod + def cmd_data(cls, data): # returns data + return(data & 0xFFFFF) + + # Build the data field for a write command + @classmethod + def cmd_make(cls, read, address, data): + return((read << 31) | ((address << 20) & 0x7FF00000) | (data & 0xFFFFF)) + + # Helper function to initiate outbound write transactions and wait for the result + # Returns error string or "" for no error + def _wrapWriteTransaction(self, data): + self._clearError() + dataBytes = data.to_bytes(4,'little',signed=False) + id = self._reqTransaction(self.WRITE_ADDR, dataBytes, 4, 0, rogue.interfaces.memory.Write) + self._waitTransaction(id) + return self._getError() + + # Helper function to initiate outbound read transactions and wait for the result + # Returns data,error where error is "" for no error + def _wrapReadTransaction(self): + self._clearError() + dataBytes = bytearray(4) + id = self._reqTransaction(self.READ_ADDR, dataBytes, 4, 0, rogue.interfaces.memory.Read) + self._waitTransaction(id) + + return int.from_bytes(dataBytes, 'little', signed=False), self._getError() + + # Execute write to the passed virtual address + def _doVirtualWrite(self,address,data): + return self._wrapWriteTransaction(self.cmd_make(read=0, address=(address - self.OFFSET_ADDR), data=data)) + + # Execute read from the passed virtual address, retry until data is ready + def _doVirtualRead(self,address): + writeData = self.cmd_make(read=1, address=(address - self.OFFSET_ADDR), data=0) + + rsp = self._wrapWriteTransaction(writeData) + + if rsp != "": + return None, rsp + + for _ in range(self.MAX_RETRIES): + rsp = self._wrapWriteTransaction(writeData) + + if rsp != "": + return None, rsp + + data, rsp = self._wrapReadTransaction() + + if rsp != "": + return None, rsp + + if self.cmd_address(data) == (address - self.OFFSET_ADDR): + return self.cmd_data(data), "" + + return None,"Indirect Read Timeout" + + # Intercept transactions + def _doTransaction(self,transaction): + with self._lock: + + addr = transaction.address() + + # Read transactions to non virtual space are passed through + if addr < self.OFFSET_ADDR: + super()._doTransaction(transaction) + else: + + with transaction.lock(): + + # Write transaction + if transaction.type() == rogue.interfaces.memory.Write or \ + transaction.type() == rogue.interfaces.memory.Post: + + cmdDataBytes = bytearray(transaction.size()) + transaction.getData(cmdDataBytes,0) + rsp = self._doVirtualWrite(addr,int.from_bytes(cmdDataBytes,byteorder='little', signed=False)) + + if rsp != "": + transaction.error(rsp) + else: + transaction.done() + + # Read or read/verity transaction + else: + + data, error = self._doVirtualRead(addr) + + if error != "": + transaction.error(error) + else: + transaction.setData(data.to_bytes(4,'little',signed=False),0) + transaction.done() + + +# Device which emulates the SPI interface under tests. +class TestEmulate(rogue.interfaces.memory.Slave): + + def __init__(self, *, minWidth=4, maxSize=0xFFFFFFFF): + rogue.interfaces.memory.Slave.__init__(self,4,4) + self._minWidth = minWidth + self._maxSize = maxSize + self._data = {} + self._addr = 0 + self._echo = 0 + self._read = 0 + self._wd = 0 + + def _checkRange(self, address, size): + return 0 + + def _doMaxAccess(self): + return(self._maxSize) + + def _doMinAccess(self): + return(self._minWidth) + + def _doTransaction(self,transaction): + address = transaction.address() + size = transaction.size() + type = transaction.type() + + if size == 4 and address == 0: + if type == rogue.interfaces.memory.Write: + ba = bytearray(4) + transaction.getData(ba,0) + self._wd = int.from_bytes(ba,'little',signed=False) + + self._addr = (self._wd >> 20) & 0x7FF + data = (self._wd & 0xFFFFF) + self._read = (self._wd >> 31) & 0x1 + + if self._addr not in self._data: + self._data[self._addr] = 0 + + if self._read == 0: + self._data[self._addr] = data + + #print(f"Indirect write addr={self._addr:#x}, data={data:#x}, read={self._read}") + + elif type == rogue.interfaces.memory.Verify or type == rogue.interfaces.memory.Read: + ba = self._wd.to_bytes(4,'little',signed=False) + transaction.setData(ba,0) + + transaction.done() + + elif size == 4 and address == 4 and type == rogue.interfaces.memory.Read: + data = self._data[self._addr] + + ret = (self._read << 31) + (self._addr << 20) + data + + ba = ret.to_bytes(4,'little',signed=False) + + #print(f"Indirect read addr={self._addr:#x}, read={self._read}, ret={ret:#x}") + transaction.setData(ba,0) + transaction.done() + + else: + transaction.error(f"Invalid transaction. Addr:{address:#x}, size:{size}, type:{type}") + +class DummyTree(pr.Root): + + def __init__(self): + pr.Root.__init__(self, + name='dummyTree', + description="Dummy tree for example", + timeout=2.0, + pollEn=False, + serverPort=None) + + # Use a memory space emulator + self.sim = TestEmulate() + + self.add(HubTestDev( + offset = 0x0, + memBase = self.sim, + )) + +def test_hub(): + + with DummyTree() as root: + + test = [int(random.random()*100) for i in range(10)] + + for i in range(10): + root.HubTestDev.Reg[i].set(test[i]) + + for i in range(10): + val = root.HubTestDev.Reg[i].get() + if test[i] != val: + raise AssertionError(f'read mismatch at reg {i}. Got {val} exp {test[i]}') + + root.HubTestDev.Write.set(root.HubTestDev.cmd_make(1,5*4,0)) + val = root.HubTestDev.cmd_data(root.HubTestDev.Read.get()) + + if test[5] != val: + raise AssertionError(f'read mismatch at reg 5. Got {val} exp {test[5]}') + + +if __name__ == "__main__": + test_hub()