diff --git a/config/dummydevice.map b/config/dummydevice.map index 61c02a68407ce710f9ebda3f24e733a9ee07278e..a675be4ef654049173c3f719e2fb9569c97fc82f 100644 --- a/config/dummydevice.map +++ b/config/dummydevice.map @@ -1,6 +1,6 @@ # name n_words address n_bytes BAR n_bits n_fractionalBits signed access -UNIO0.BIT_TEC1091_ENABLE 1 4576 4 1 1 0 0 RW -UNIO0.BIT_TEC1091_CMD_LOOP_START 1 4580 4 1 1 0 0 RW -UNIO0.BIT_TEC1091_CMD_LOOP_DONE 1 4584 4 1 1 0 0 RO -UNIO0.AREA_TEC1091_CMD 256 5120 1024 1 32 0 0 RW - +# note: addresses are hardcoded in the TecDummy! +UNIO0.BIT_TEC1091_ENABLE 1 0 4 0 1 0 0 RW +UNIO0.BIT_TEC1091_CMD_LOOP_START 1 4 4 0 1 0 0 RW +UNIO0.BIT_TEC1091_CMD_LOOP_DONE 1 8 4 0 1 0 0 RO +UNIO0.AREA_TEC1091_CMD 256 12 1024 0 32 0 0 RW diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 65207ab23e97e69b709b63e4a30b317e27ceb0cc..24b7356060da3c6a0818bad05956a90b00e5a4c8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,11 +5,16 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.5.1) # Add BOOST dependencies FIND_PACKAGE(Boost COMPONENTS thread system unit_test_framework REQUIRED) -# The tests also require the server headers (TODO Potentially, module includes are also needed) +# The tests also require the server headers include_directories(${CMAKE_SOURCE_DIR}/server/include) +# build library with dummy device etc. +include_directories(include) +aux_source_directory(src testlibrary_sources) +add_library(${PROJECT_NAME}testlib ${testlibrary_sources}) + # Add all tests residing in the "tests" directory -aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} testExecutables) +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/executable_src testExecutables) foreach( testExecutableSrcFile ${testExecutables}) #NAME_WE means the base name without path and (longest) extension get_filename_component(excutableName ${testExecutableSrcFile} NAME_WE) @@ -19,7 +24,7 @@ foreach( testExecutableSrcFile ${testExecutables}) PROPERTIES LINK_FLAGS "${CMAKE_LINK_FLAGS}" ) - target_link_libraries(${excutableName} ${PROJECT_NAME}lib ${ChimeraTK-ApplicationCore_LIBRARIES} ${Adapter_LIBRARIES} ) + target_link_libraries(${excutableName} ${PROJECT_NAME}lib ${ChimeraTK-ApplicationCore_LIBRARIES} ${Adapter_LIBRARIES} ${PROJECT_NAME}testlib) add_test( NAME ${excutableName} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${excutableName} diff --git a/tests/testTemplateModule.cc b/tests/executable_src/testTecModule.cc similarity index 100% rename from tests/testTemplateModule.cc rename to tests/executable_src/testTecModule.cc diff --git a/tests/include/TecDummy.h b/tests/include/TecDummy.h new file mode 100644 index 0000000000000000000000000000000000000000..b46de590dbb8feb433c6e3059da2fbccbaac9269 --- /dev/null +++ b/tests/include/TecDummy.h @@ -0,0 +1,36 @@ +#pragma once + +#include <ChimeraTK/DummyBackend.h> +#include <ChimeraTK/BackendFactory.h> +#include <ChimeraTK/DummyRegisterAccessor.h> + +struct TecDummy : ChimeraTK::DummyBackend { + TecDummy(std::string mapFileName) : DummyBackend(mapFileName) {} + ~TecDummy() override; + + // hardcoded addresses used by the dummy, need to match addresses of map file + constexpr static uint8_t TecDummy_bar{0}; + constexpr static uint32_t TecDummy_address_loopDone{8}; + + // Accessors for the registers + ChimeraTK::DummyRegisterAccessor<uint32_t> reg_loopStart{this, "UNIO0", "BIT_TEC1091_CMD_LOOP_START"}; + ChimeraTK::DummyRegisterAccessor<uint32_t> reg_loopDone{this, "UNIO0", "BIT_TEC1091_CMD_LOOP_DONE"}; + ChimeraTK::DummyRegisterAccessor<uint32_t> reg_command{this, "UNIO0", "AREA_TEC1091_CMD"}; + + static boost::shared_ptr<DeviceBackend> createInstance(std::string, std::map<std::string, std::string> parameters) { + return boost::shared_ptr<DeviceBackend>(new TecDummy(parameters["map"])); + } + + void read(uint8_t bar, uint32_t address, int32_t* data, size_t sizeInBytes) override; + + // In this function the TEC device is actually simulated. + std::string dataProcessing(const std::string& command); + + class BackendRegisterer { + public: + BackendRegisterer(); + }; + static BackendRegisterer backendRegisterer; +}; + +TecDummy::BackendRegisterer TecDummy::backendRegisterer; diff --git a/tests/src/TecDummy.cc b/tests/src/TecDummy.cc new file mode 100644 index 0000000000000000000000000000000000000000..d4dfe04848fa40d1fe75049b6dee32127592c14c --- /dev/null +++ b/tests/src/TecDummy.cc @@ -0,0 +1,48 @@ +#include "TecDummy.h" + +/*********************************************************************************************************************/ + +TecDummy::BackendRegisterer::BackendRegisterer() { + std::cout << "TecDummy::BackendRegisterer: registering backend type TecDummy" << std::endl; + ChimeraTK::BackendFactory::getInstance().registerBackendType("TecDummy", &TecDummy::createInstance); +} + +/*********************************************************************************************************************/ + +void TecDummy::read(uint8_t bar, uint32_t address, int32_t* data, size_t sizeInBytes) { + DummyBackend::read(bar, address, data, sizeInBytes); + if(bar != TecDummy_bar || address != TecDummy_address_loopDone) return; + if(reg_loopStart != 1) return; + + // convert command into string + // FIXME: this can be done better if the DummyRegisterRawAccessor would allow us to use the raw pointer to this... + std::string commandString(reg_command.getNumberOfElements() * 4, 0); + for(size_t i = 0; i < reg_command.getNumberOfElements(); ++i) { + uint32_t word = reg_command[i]; + std::memcpy(&(commandString[4 * i]), &word, 4); + } + + // perform data processing + auto reply = dataProcessing(commandString); + + // convert reply back into byte stream + for(size_t i = 0; i < reply.length(); ++i) { + uint32_t word; + std::memcpy(&word, &(reply[4 * i]), 4); + reg_command[i] = word; + } + + reg_loopDone = 1; +} + +/*********************************************************************************************************************/ + +std::string TecDummy::dataProcessing(const std::string& command) { + // Place data processing code here. Parse data from the "command" dummy accessor and place the reply on the same + // accessor. Just return this function, the done flag is automatically set by the caller. Remove this comment after + // implementation. + std::cout << "TecDummy::dataProcessing() command = " << command << std::endl; + return "MY REPLY"; +} + +/*********************************************************************************************************************/