Skip to content
Snippets Groups Projects
Commit 4d1e2d62 authored by Martin Killenberg's avatar Martin Killenberg
Browse files

changed DoocsFactory to not create unnecessary decorators of the wrong type...

changed DoocsFactory to not create unnecessary decorators of the wrong type when auto-creating variables. Test for spectra still failing
parent 6fda867c
No related branches found
No related tags found
No related merge requests found
...@@ -45,6 +45,9 @@ namespace ChimeraTK { ...@@ -45,6 +45,9 @@ namespace ChimeraTK {
boost::shared_ptr<D_fct> autoCreate( std::shared_ptr<PropertyDescription> const & propertyDescription); boost::shared_ptr<D_fct> autoCreate( std::shared_ptr<PropertyDescription> const & propertyDescription);
template <class IMPL_T, class DOOCS_SCALAR_T, class DOOCS_PRIMARY_T, class DOOCS_ARRAY_T, class DOOCS_ARRAY_PRIMITIVE_T>
boost::shared_ptr<D_fct> typedCreateScalarOrArray( ProcessVariable & processVariable, AutoPropertyDescription const & propertyDescription, DecoratorType decoratorType, ArrayDescription::DataType arrayDataType);
}; };
......
...@@ -113,77 +113,68 @@ namespace ChimeraTK { ...@@ -113,77 +113,68 @@ namespace ChimeraTK {
return doocsPV; return doocsPV;
} }
// fixme: some of the variables needed here are redundant and can be sovled with mpl and/or fusion maps
template <class IMPL_T, class DOOCS_SCALAR_T, class DOOCS_PRIMITIVE_T, class DOOCS_ARRAY_T, class DOOCS_ARRAY_PRIMITIVE_T>
boost::shared_ptr<D_fct> DoocsPVFactory::typedCreateScalarOrArray( ProcessVariable & processVariable, AutoPropertyDescription const & autoPropertyDescription, DecoratorType decoratorType, ArrayDescription::DataType arrayDataType){
// We have to convert to the original NDRegisterAccessor to determine the number of samples.
// We cannot use a decorator because scalar and array DOOCS_PRIMITIVE_T can be different,
// and once a decorator is created you cannot get the other type any more.
auto & ndAccessor = dynamic_cast<mtca4u::NDRegisterAccessor<IMPL_T> &>(processVariable);
auto nSamples = ndAccessor.getNumberOfSamples();
if (nSamples == 1){
return createDoocsScalar<DOOCS_PRIMITIVE_T, DOOCS_SCALAR_T>(autoPropertyDescription, decoratorType);
}else{
return typedCreateDoocsArray<DOOCS_ARRAY_PRIMITIVE_T, DOOCS_ARRAY_T>(ArrayDescription(autoPropertyDescription, arrayDataType));
}
}
boost::shared_ptr<D_fct> DoocsPVFactory::autoCreate( std::shared_ptr<PropertyDescription> const & propertyDescription ){ boost::shared_ptr<D_fct> DoocsPVFactory::autoCreate( std::shared_ptr<PropertyDescription> const & propertyDescription ){
// do auto creation // do auto creation
auto autoPropertyDescription = std::static_pointer_cast<AutoPropertyDescription>(propertyDescription); auto autoPropertyDescription = std::static_pointer_cast<AutoPropertyDescription>(propertyDescription);
auto pvName = autoPropertyDescription->source; auto pvName = autoPropertyDescription->source;
auto processVariable = _controlSystemPVManager->getProcessVariable(pvName); auto processVariable = _controlSystemPVManager->getProcessVariable(pvName);
std::type_info const & valueType = processVariable->getValueType(); std::type_info const & valueType = processVariable->getValueType();
// We use an int accessor decorator just to have some type.
// All we need to do here is to determine the number of samples. No need to write an if/then/else
// on the type, or a boot::fustion::for_each, which is in the decorator factory.
// Unfortynately we need different impl_type -> doocs_type decision for scalars and arrays,
// so we have to know this here.
auto intDecoratedPV = ChimeraTK::getDecorator<int>( *processVariable );
auto nSamples = intDecoratedPV->getNumberOfSamples();
/* TODO: /* TODO:
- create functions "createDoocsArray" and "createDoocsSpectrum" - create functions "createDoocsArray" and "createDoocsSpectrum"
- first use spectrum here for 1D, then switch to array (tests need to be adapted) - first use spectrum here for 1D, then switch to array (tests need to be adapted)
- create spectrum, array and d_int/float/double upon request from 1d (scalar for D_array and 1D) - create spectrum, array and d_int/float/double upon request from 1d (scalar for D_array and 1D)
*/ */
// Unfortunately we need a big if/else block to hard-code the template
// parameter. The value type in only known at run time, // fixme: make this a boost::foreach in the data types provided by DeviceAccess.
// but the template parameter has to be known at compile time. // This will detect uncovered new data types at compile time, not only at run time
if (nSamples == 1){ if (valueType == typeid(int8_t)) {
if (valueType == typeid(int8_t)) { return typedCreateScalarOrArray<int8_t, D_int, int32_t, D_bytearray, int8_t>(*processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion, ArrayDescription::DataType::Byte);
return createDoocsScalar<int32_t, D_int>(*autoPropertyDescription, DecoratorType::C_style_conversion); }else if (valueType == typeid(uint8_t)) {
} else if (valueType == typeid(uint8_t)) { return typedCreateScalarOrArray<uint8_t, D_int, int32_t, D_bytearray, int8_t>(*processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion, ArrayDescription::DataType::Byte);
return createDoocsScalar<int32_t, D_int>(*autoPropertyDescription, DecoratorType::C_style_conversion);
} else if (valueType == typeid(int16_t)) { } else if (valueType == typeid(int16_t)) {
return createDoocsScalar<int32_t, D_int>(*autoPropertyDescription, DecoratorType::C_style_conversion); return typedCreateScalarOrArray<int16_t, D_int, int32_t, D_shortarray, int16_t>(*processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion, ArrayDescription::DataType::Short);
} else if (valueType == typeid(uint16_t)) { } else if (valueType == typeid(uint16_t)) {
return createDoocsScalar<int32_t, D_int>(*autoPropertyDescription, DecoratorType::C_style_conversion); return typedCreateScalarOrArray<uint16_t, D_int, int32_t, D_shortarray, int16_t>(*processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion, ArrayDescription::DataType::Short);
} else if (valueType == typeid(int32_t)) { } else if (valueType == typeid(int32_t)) {
return createDoocsScalar<int32_t, D_int>(*autoPropertyDescription, DecoratorType::C_style_conversion); return typedCreateScalarOrArray<int32_t, D_int, int32_t, D_intarray, int32_t>(*processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion, ArrayDescription::DataType::Int);
} else if (valueType == typeid(uint32_t)) { } else if (valueType == typeid(uint32_t)) {
return createDoocsScalar<int32_t, D_int>(*autoPropertyDescription, DecoratorType::C_style_conversion); return typedCreateScalarOrArray<uint32_t, D_int, int32_t, D_intarray, int32_t>(*processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion, ArrayDescription::DataType::Int);
} else if (valueType == typeid(float)) { } else if (valueType == typeid(int64_t)) {
return createDoocsScalar<float, D_float>(*autoPropertyDescription, DecoratorType::C_style_conversion); // there is no scalar int64 representation in doocs, so we always create an array, also for length = 1
} else if (valueType == typeid(double)) { return typedCreateDoocsArray<long long int, D_longarray>(ArrayDescription(*autoPropertyDescription, ArrayDescription::DataType::Long));
return createDoocsScalar<double, D_double>(*autoPropertyDescription, DecoratorType::range_checking); } else if (valueType == typeid(uint64_t)) {
} else if (valueType == typeid(std::string)) { return typedCreateDoocsArray<long long int, D_longarray>(ArrayDescription(*autoPropertyDescription, ArrayDescription::DataType::Long));
return createDoocsScalar<std::string, D_string>(*autoPropertyDescription, DecoratorType::range_checking); } else if (valueType == typeid(float)) {
} else { return typedCreateScalarOrArray<float, D_float, float, D_floatarray, float>(*processVariable, *autoPropertyDescription, DecoratorType::range_checking, ArrayDescription::DataType::Float);
throw std::invalid_argument("unsupported value type"); } else if (valueType == typeid(double)) {
} return typedCreateScalarOrArray<double, D_double, double, D_doublearray, double>(*processVariable, *autoPropertyDescription, DecoratorType::range_checking, ArrayDescription::DataType::Double);
}else{ //nSamples > 1 } else if (valueType == typeid(std::string)) {
if (valueType == typeid(int8_t)) { // FIXME returning scalar also for arrays. This should result in an error
return typedCreateDoocsArray<int8_t, D_bytearray>(ArrayDescription(*autoPropertyDescription, ArrayDescription::DataType::Byte)); return createDoocsScalar<std::string, D_string>(*autoPropertyDescription, DecoratorType::range_checking);
} else if (valueType == typeid(uint8_t)) { } else {
return typedCreateDoocsArray<int8_t, D_bytearray>(ArrayDescription(*autoPropertyDescription, ArrayDescription::DataType::Byte)); throw std::invalid_argument("unsupported value type");
} else if (valueType == typeid(int16_t)) {
return typedCreateDoocsArray<int16_t, D_shortarray>(ArrayDescription(*autoPropertyDescription, ArrayDescription::DataType::Byte));
} else if (valueType == typeid(uint16_t)) {
return typedCreateDoocsArray<int16_t, D_shortarray>(ArrayDescription(*autoPropertyDescription, ArrayDescription::DataType::Byte));
} else if (valueType == typeid(int32_t)) {
return typedCreateDoocsArray<int32_t, D_intarray>(ArrayDescription(*autoPropertyDescription, ArrayDescription::DataType::Byte));
} else if (valueType == typeid(uint32_t)) {
return typedCreateDoocsArray<int32_t, D_intarray>(ArrayDescription(*autoPropertyDescription, ArrayDescription::DataType::Byte));
} else if (valueType == typeid(int64_t)) {
return typedCreateDoocsArray<long long int, D_longarray>(ArrayDescription(*autoPropertyDescription, ArrayDescription::DataType::Byte));
} else if (valueType == typeid(uint64_t)) {
return typedCreateDoocsArray<long long int, D_longarray>(ArrayDescription(*autoPropertyDescription, ArrayDescription::DataType::Byte));
} else if (valueType == typeid(float)) {
return typedCreateDoocsArray<float, D_floatarray>(ArrayDescription(*autoPropertyDescription, ArrayDescription::DataType::Byte));
} else if (valueType == typeid(double)) {
return typedCreateDoocsArray<double, D_doublearray>(ArrayDescription(*autoPropertyDescription, ArrayDescription::DataType::Byte));
} else {
throw std::invalid_argument("unsupported value type");
}
} }
} }
template<class DOOCS_PRIMITIVE_T, class DOOCS_T> template<class DOOCS_PRIMITIVE_T, class DOOCS_T>
......
...@@ -4,8 +4,6 @@ namespace ChimeraTK{ ...@@ -4,8 +4,6 @@ namespace ChimeraTK{
void DoocsUpdater::addVariable( mtca4u::TransferElement & variable, std::function<void ()> updaterFunction){ void DoocsUpdater::addVariable( mtca4u::TransferElement & variable, std::function<void ()> updaterFunction){
_elementsToRead.push_back( std::reference_wrapper< mtca4u::TransferElement > (variable) ); _elementsToRead.push_back( std::reference_wrapper< mtca4u::TransferElement > (variable) );
std::cout << "adding callback function to " << variable.getName() << " at "
<< &variable << std::endl;
_toDoocsUpdateMap[&variable].push_back(updaterFunction); _toDoocsUpdateMap[&variable].push_back(updaterFunction);
} }
...@@ -15,8 +13,6 @@ namespace ChimeraTK{ ...@@ -15,8 +13,6 @@ namespace ChimeraTK{
// Currently this is consistent behaviour in the location update, and needed // Currently this is consistent behaviour in the location update, and needed
// for consistent testing. // for consistent testing.
if (mapElem.first->readLatest()){ if (mapElem.first->readLatest()){
std::cout << "callbacks for " << mapElem.first->getName() << std::endl;
std::cout << "vector has a size of " << mapElem.second.size() << std::endl;
for (auto & updaterFunc : mapElem.second){ for (auto & updaterFunc : mapElem.second){
updaterFunc(); updaterFunc();
} }
......
...@@ -25,7 +25,8 @@ using boost::shared_ptr; ...@@ -25,7 +25,8 @@ using boost::shared_ptr;
// use boost meta-programming to use test case templates // use boost meta-programming to use test case templates
// The list of types is an mpl type // The list of types is an mpl type
typedef boost::mpl::list<int32_t, uint32_t, typedef boost::mpl::list<int64_t, uint64_t,
int32_t, uint32_t,
int16_t, uint16_t, int16_t, uint16_t,
int8_t, uint8_t, int8_t, uint8_t,
float, double> simple_test_types; float, double> simple_test_types;
...@@ -179,7 +180,13 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( testCreateArray, T, simple_test_types ){ ...@@ -179,7 +180,13 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( testCreateArray, T, simple_test_types ){
shared_ptr<DevicePVManager> devManager = pvManagers.second; shared_ptr<DevicePVManager> devManager = pvManagers.second;
static const size_t arraySize = 10; static const size_t arraySize = 10;
// PVs can only get one decorator, so we have to put one array for each decorator/doocs type we want to test
devManager->createProcessArray<T>(deviceToControlSystem,"A/fromDeviceArray1",arraySize); devManager->createProcessArray<T>(deviceToControlSystem,"A/fromDeviceArray1",arraySize);
devManager->createProcessArray<T>(deviceToControlSystem,"A/fromDeviceArray2",arraySize);
devManager->createProcessArray<T>(deviceToControlSystem,"A/fromDeviceArray3",arraySize);
devManager->createProcessArray<T>(deviceToControlSystem,"A/fromDeviceArray4",arraySize);
devManager->createProcessArray<T>(deviceToControlSystem,"A/fromDeviceArray5",arraySize);
devManager->createProcessArray<T>(deviceToControlSystem,"A/fromDeviceArray6",arraySize);
// we need this later anyway, do we make a temporary variable // we need this later anyway, do we make a temporary variable
auto pvNames = ChimeraTK::getAllVariableNames( csManager ); auto pvNames = ChimeraTK::getAllVariableNames( csManager );
...@@ -188,12 +195,12 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( testCreateArray, T, simple_test_types ){ ...@@ -188,12 +195,12 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( testCreateArray, T, simple_test_types ){
DoocsPVFactory factory(&myEqFct, updater, csManager); DoocsPVFactory factory(&myEqFct, updater, csManager);
testArrayIsCorrectType<D_bytearray>(factory, ArrayDescription::DataType::Byte); testArrayIsCorrectType<D_bytearray>(factory, ArrayDescription::DataType::Byte, "fromDeviceArray1");
testArrayIsCorrectType<D_shortarray>(factory, ArrayDescription::DataType::Short); testArrayIsCorrectType<D_shortarray>(factory, ArrayDescription::DataType::Short, "fromDeviceArray2");
testArrayIsCorrectType<D_intarray>(factory, ArrayDescription::DataType::Int); testArrayIsCorrectType<D_intarray>(factory, ArrayDescription::DataType::Int, "fromDeviceArray3");
testArrayIsCorrectType<D_longarray>(factory, ArrayDescription::DataType::Long); testArrayIsCorrectType<D_longarray>(factory, ArrayDescription::DataType::Long, "fromDeviceArray4");
testArrayIsCorrectType<D_floatarray>(factory, ArrayDescription::DataType::Float); testArrayIsCorrectType<D_floatarray>(factory, ArrayDescription::DataType::Float, "fromDeviceArray5");
testArrayIsCorrectType<D_doublearray>(factory, ArrayDescription::DataType::Double); testArrayIsCorrectType<D_doublearray>(factory, ArrayDescription::DataType::Double, "fromDeviceArray6");
} }
BOOST_AUTO_TEST_CASE( testAutoCreateArray ){ BOOST_AUTO_TEST_CASE( testAutoCreateArray ){
...@@ -233,13 +240,12 @@ BOOST_AUTO_TEST_CASE( testAutoCreateArray ){ ...@@ -233,13 +240,12 @@ BOOST_AUTO_TEST_CASE( testAutoCreateArray ){
testArrayIsCorrectType<D_doublearray>(factory, ArrayDescription::DataType::Auto, "toDeviceDoubleArray"); testArrayIsCorrectType<D_doublearray>(factory, ArrayDescription::DataType::Auto, "toDeviceDoubleArray");
} }
BOOST_AUTO_TEST_CASE( testErrorHandling ){ BOOST_AUTO_TEST_CASE( testInt64Scalar ){
std::pair< shared_ptr<ControlSystemPVManager>, std::pair< shared_ptr<ControlSystemPVManager>,
shared_ptr<DevicePVManager> > pvManagers = createPVManager(); shared_ptr<DevicePVManager> > pvManagers = createPVManager();
shared_ptr<ControlSystemPVManager> csManager = pvManagers.first; shared_ptr<ControlSystemPVManager> csManager = pvManagers.first;
shared_ptr<DevicePVManager> devManager = pvManagers.second; shared_ptr<DevicePVManager> devManager = pvManagers.second;
// int64 is not supported yet
devManager->createProcessArray<int64_t>(controlSystemToDevice,"I/toDeviceInt",1); devManager->createProcessArray<int64_t>(controlSystemToDevice,"I/toDeviceInt",1);
DoocsUpdater updater; DoocsUpdater updater;
...@@ -248,17 +254,11 @@ BOOST_AUTO_TEST_CASE( testErrorHandling ){ ...@@ -248,17 +254,11 @@ BOOST_AUTO_TEST_CASE( testErrorHandling ){
ProcessVariable::SharedPtr processScalar = ProcessVariable::SharedPtr processScalar =
csManager->getProcessArray<int64_t>("I/toDeviceInt"); csManager->getProcessArray<int64_t>("I/toDeviceInt");
// Intentionally put the int64 scalar to the int32 create function.
// Unfortunately BOOST_CHECK cannot deal with multiple template parameters,
// so we have to trick it
auto description = std::make_shared<AutoPropertyDescription>("I/toDeviceInt", "I", "toDeviceInt"); auto description = std::make_shared<AutoPropertyDescription>("I/toDeviceInt", "I", "toDeviceInt");
try{ factory.create( description ); auto variable64 = factory.create( description );
// In a working unit test this line should not be hit, so er exclude it // 64 bit integer scalars become D_longarrays because there is no 64 bit scalar representation in Doocs
// from the coverage report. BOOST_CHECK( boost::dynamic_pointer_cast<D_longarray>(variable64) );
BOOST_ERROR( "createDoocsScalar did not throw as expected");//LCOV_EXCL_LINE
}catch(std::invalid_argument &e){
BOOST_CHECK( std::string("unsupported value type") == e.what() );
}
} }
// After you finished all test you have to end the test suite. // After you finished all test you have to end the test suite.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment