diff --git a/include/DoocsPVFactory.h b/include/DoocsPVFactory.h index 6287afe5d0a9811f762a50d7b5812cfd286fc9b1..082f78c60bc79efb67fb42ea8883db11ac9918a6 100644 --- a/include/DoocsPVFactory.h +++ b/include/DoocsPVFactory.h @@ -54,7 +54,7 @@ namespace ChimeraTK { boost::shared_ptr<D_fct> autoCreate(std::shared_ptr<PropertyDescription> const& propertyDescription); template<class DOOCS_SCALAR_T, class DOOCS_PRIMARY_T, class DOOCS_ARRAY_T, class DOOCS_ARRAY_PRIMITIVE_T> - boost::shared_ptr<D_fct> typedCreateScalarOrArray(std::type_index valueType, ProcessVariable& processVariable, + boost::shared_ptr<D_fct> typedCreateScalarOrArray(const std::type_info& valueType, ProcessVariable& processVariable, AutoPropertyDescription const& propertyDescription, DecoratorType decoratorType); }; diff --git a/src/DoocsPVFactory.cc b/src/DoocsPVFactory.cc index 1ad217ea6ba5c6a7a613ab7122e8fab1ed543068..aec76e47a74fac61f48f5dfe4b1dabae86142847 100644 --- a/src/DoocsPVFactory.cc +++ b/src/DoocsPVFactory.cc @@ -307,96 +307,47 @@ namespace ChimeraTK { boost::dynamic_pointer_cast<DoocsIfff>(doocsPV)->publishZeroMQ(); } - if(not ifffDescription.isWriteable){ + if(not ifffDescription.isWriteable) { doocsPV->set_ro_access(); } return doocsPV; } - static std::map<std::type_index, std::function<unsigned int(ProcessVariable&)>> castingMap{ - {typeid(uint8_t), - [](auto& pv) { return dynamic_cast<ChimeraTK::NDRegisterAccessor<uint8_t>&>(pv).getNumberOfSamples(); }}, - {typeid(int8_t), - [](auto& pv) -> auto {return dynamic_cast<ChimeraTK::NDRegisterAccessor<int8_t>&>(pv).getNumberOfSamples(); -} // namespace ChimeraTK -} -, - {typeid(uint16_t), - [](auto& pv) { return dynamic_cast<ChimeraTK::NDRegisterAccessor<uint16_t>&>(pv).getNumberOfSamples(); }}, - {typeid(int16_t), - [](auto& pv) -> auto {return dynamic_cast<ChimeraTK::NDRegisterAccessor<int16_t>&>(pv).getNumberOfSamples(); -} -} -, - {typeid(uint32_t), - [](auto& pv) -> auto {return dynamic_cast<ChimeraTK::NDRegisterAccessor<uint32_t>&>(pv).getNumberOfSamples(); -} -} -, - {typeid(int32_t), - [](auto& pv) -> auto {return dynamic_cast<ChimeraTK::NDRegisterAccessor<int32_t>&>(pv).getNumberOfSamples(); -} -} -, - {typeid(uint64_t), - [](auto& pv) -> auto {return dynamic_cast<ChimeraTK::NDRegisterAccessor<uint64_t>&>(pv).getNumberOfSamples(); -} -} -, - {typeid(int64_t), - [](auto& pv) -> auto {return dynamic_cast<ChimeraTK::NDRegisterAccessor<int64_t>&>(pv).getNumberOfSamples(); -} -} -, - {typeid(float), - [](auto& pv) -> auto {return dynamic_cast<ChimeraTK::NDRegisterAccessor<float>&>(pv).getNumberOfSamples(); -} -} -, - {typeid(double), - [](auto& pv) -> auto {return dynamic_cast<ChimeraTK::NDRegisterAccessor<double>&>(pv).getNumberOfSamples(); -} -} -, - {typeid(std::string), - [](auto& pv) -> auto {return dynamic_cast<ChimeraTK::NDRegisterAccessor<std::string>&>(pv).getNumberOfSamples(); -} -} -, -} -; - -// fixme: some of the variables needed here are redundant and can be sovled with -// mpl and/or fusion maps -template<class DOOCS_SCALAR_T, class DOOCS_PRIMITIVE_T, class DOOCS_ARRAY_T, class DOOCS_ARRAY_PRIMITIVE_T> -boost::shared_ptr<D_fct> DoocsPVFactory::typedCreateScalarOrArray(std::type_index valueType, - ProcessVariable& processVariable, AutoPropertyDescription const& autoPropertyDescription, - DecoratorType decoratorType) { - // 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 nSamples = castingMap[valueType](processVariable); - - if(nSamples == 1) { - return createDoocsScalar<DOOCS_PRIMITIVE_T, DOOCS_SCALAR_T>(autoPropertyDescription, decoratorType); - } - else { - return typedCreateDoocsArray<DOOCS_ARRAY_PRIMITIVE_T, DOOCS_ARRAY_T>( - AutoPropertyDescription(autoPropertyDescription)); + // fixme: some of the variables needed here are redundant and can be sovled with + // mpl and/or fusion maps + template<class DOOCS_SCALAR_T, class DOOCS_PRIMITIVE_T, class DOOCS_ARRAY_T, class DOOCS_ARRAY_PRIMITIVE_T> + boost::shared_ptr<D_fct> DoocsPVFactory::typedCreateScalarOrArray(const std::type_info& valueType, + ProcessVariable& processVariable, AutoPropertyDescription const& autoPropertyDescription, + DecoratorType decoratorType) { + // 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. + + size_t nSamples; + callForType(valueType, [&](auto t) { + using T = decltype(t); + nSamples = dynamic_cast<ChimeraTK::NDRegisterAccessor<T>&>(processVariable).getNumberOfSamples(); + }); + + if(nSamples == 1) { + return createDoocsScalar<DOOCS_PRIMITIVE_T, DOOCS_SCALAR_T>(autoPropertyDescription, decoratorType); + } + else { + return typedCreateDoocsArray<DOOCS_ARRAY_PRIMITIVE_T, DOOCS_ARRAY_T>( + AutoPropertyDescription(autoPropertyDescription)); + } } -} -boost::shared_ptr<D_fct> DoocsPVFactory::autoCreate(std::shared_ptr<PropertyDescription> const& propertyDescription) { - // do auto creation - auto autoPropertyDescription = std::static_pointer_cast<AutoPropertyDescription>(propertyDescription); + boost::shared_ptr<D_fct> DoocsPVFactory::autoCreate(std::shared_ptr<PropertyDescription> const& propertyDescription) { + // do auto creation + auto autoPropertyDescription = std::static_pointer_cast<AutoPropertyDescription>(propertyDescription); - auto pvName = autoPropertyDescription->source; - auto processVariable = _controlSystemPVManager->getProcessVariable(pvName); + auto pvName = autoPropertyDescription->source; + auto processVariable = _controlSystemPVManager->getProcessVariable(pvName); - std::type_info const& valueType = processVariable->getValueType(); - /* TODO: + std::type_info const& valueType = processVariable->getValueType(); + /* TODO: - create functions "createDoocsArray" and "createDoocsSpectrum" - first use spectrum here for 1D, then switch to array (tests need to be adapted) @@ -404,154 +355,154 @@ boost::shared_ptr<D_fct> DoocsPVFactory::autoCreate(std::shared_ptr<PropertyDesc (scalar for D_array and 1D) */ - if(autoPropertyDescription->dataType == AutoPropertyDescription::DataType::Auto) { - autoPropertyDescription->deriveType(valueType); - } + if(autoPropertyDescription->dataType == AutoPropertyDescription::DataType::Auto) { + autoPropertyDescription->deriveType(valueType); + } - switch(autoPropertyDescription->dataType) { - case AutoPropertyDescription::DataType::Byte: - return typedCreateScalarOrArray<D_int, int32_t, D_bytearray, uint8_t>( - valueType, *processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion); - case AutoPropertyDescription::DataType::Short: - return typedCreateScalarOrArray<D_int, int32_t, D_shortarray, int16_t>( - valueType, *processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion); - case AutoPropertyDescription::DataType::Int: - return typedCreateScalarOrArray<D_int, int32_t, D_intarray, int32_t>( - valueType, *processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion); - case AutoPropertyDescription::DataType::Long: - return typedCreateDoocsArray<int64_t, D_longarray>(AutoPropertyDescription(*autoPropertyDescription)); - case AutoPropertyDescription::DataType::Float: - return typedCreateScalarOrArray<D_float, float, D_floatarray, float>( - valueType, *processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion); - case AutoPropertyDescription::DataType::Double: - return typedCreateScalarOrArray<D_double, double, D_doublearray, double>( - valueType, *processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion); - case AutoPropertyDescription::DataType::Auto: - if(valueType == typeid(std::string)) { - return typedCreateScalarOrArray<D_textUnifier, std::string, std::nullptr_t, std::nullptr_t>( - valueType, *processVariable, *autoPropertyDescription, DecoratorType::limiting); - } - throw std::logic_error("DoocsPVFactory does not implement a data type it should!"); + switch(autoPropertyDescription->dataType) { + case AutoPropertyDescription::DataType::Byte: + return typedCreateScalarOrArray<D_int, int32_t, D_bytearray, uint8_t>( + valueType, *processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion); + case AutoPropertyDescription::DataType::Short: + return typedCreateScalarOrArray<D_int, int32_t, D_shortarray, int16_t>( + valueType, *processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion); + case AutoPropertyDescription::DataType::Int: + return typedCreateScalarOrArray<D_int, int32_t, D_intarray, int32_t>( + valueType, *processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion); + case AutoPropertyDescription::DataType::Long: + return typedCreateDoocsArray<int64_t, D_longarray>(AutoPropertyDescription(*autoPropertyDescription)); + case AutoPropertyDescription::DataType::Float: + return typedCreateScalarOrArray<D_float, float, D_floatarray, float>( + valueType, *processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion); + case AutoPropertyDescription::DataType::Double: + return typedCreateScalarOrArray<D_double, double, D_doublearray, double>( + valueType, *processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion); + case AutoPropertyDescription::DataType::Auto: + if(valueType == typeid(std::string)) { + return typedCreateScalarOrArray<D_textUnifier, std::string, std::nullptr_t, std::nullptr_t>( + valueType, *processVariable, *autoPropertyDescription, DecoratorType::limiting); + } + throw std::logic_error("DoocsPVFactory does not implement a data type it should!"); + } + + // Make compiler happy + throw std::logic_error("Should not be reached"); } - // Make compiler happy - throw std::logic_error("Should not be reached"); -} + template<class DOOCS_PRIMITIVE_T, class DOOCS_T> + boost::shared_ptr<D_fct> DoocsPVFactory::typedCreateDoocsArray(AutoPropertyDescription const& propertyDescription) { + auto processVariable = _controlSystemPVManager->getProcessVariable(propertyDescription.source); -template<class DOOCS_PRIMITIVE_T, class DOOCS_T> -boost::shared_ptr<D_fct> DoocsPVFactory::typedCreateDoocsArray(AutoPropertyDescription const& propertyDescription) { - auto processVariable = _controlSystemPVManager->getProcessVariable(propertyDescription.source); + // the DoocsProcessScalar needs the real ProcessScalar type, not just + // ProcessVariable + boost::shared_ptr<NDRegisterAccessor<DOOCS_PRIMITIVE_T>> processArray; + if(typeid(DOOCS_PRIMITIVE_T) == processVariable->getValueType()) { + processArray = boost::dynamic_pointer_cast<ChimeraTK::NDRegisterAccessor<DOOCS_PRIMITIVE_T>>(processVariable); + } + else { + processArray = getDecorator<DOOCS_PRIMITIVE_T>(processVariable, DecoratorType::C_style_conversion); + } - // the DoocsProcessScalar needs the real ProcessScalar type, not just - // ProcessVariable - boost::shared_ptr<NDRegisterAccessor<DOOCS_PRIMITIVE_T>> processArray; - if(typeid(DOOCS_PRIMITIVE_T) == processVariable->getValueType()) { - processArray = boost::dynamic_pointer_cast<ChimeraTK::NDRegisterAccessor<DOOCS_PRIMITIVE_T>>(processVariable); - } - else { - processArray = getDecorator<DOOCS_PRIMITIVE_T>(processVariable, DecoratorType::C_style_conversion); - } + ///@todo FIXME Add the decorator type as option to the array description, and + /// only use C_style_conversion as default + boost::shared_ptr<D_fct> doocsPV( + new DoocsProcessArray<DOOCS_T, DOOCS_PRIMITIVE_T>(_eqFct, propertyDescription.name, processArray, _updater)); - ///@todo FIXME Add the decorator type as option to the array description, and - /// only use C_style_conversion as default - boost::shared_ptr<D_fct> doocsPV( - new DoocsProcessArray<DOOCS_T, DOOCS_PRIMITIVE_T>(_eqFct, propertyDescription.name, processArray, _updater)); + // set read only mode if configures in the xml file or for output variables + if(!processVariable->isWriteable() || !propertyDescription.isWriteable) { + doocsPV->set_ro_access(); + } - // set read only mode if configures in the xml file or for output variables - if(!processVariable->isWriteable() || !propertyDescription.isWriteable) { - doocsPV->set_ro_access(); - } + // publish via ZeroMQ if configured in the xml file + if(propertyDescription.publishZMQ) { + boost::dynamic_pointer_cast<DoocsProcessArray<DOOCS_T, DOOCS_PRIMITIVE_T>>(doocsPV)->publishZeroMQ(); + } - // publish via ZeroMQ if configured in the xml file - if(propertyDescription.publishZMQ) { - boost::dynamic_pointer_cast<DoocsProcessArray<DOOCS_T, DOOCS_PRIMITIVE_T>>(doocsPV)->publishZeroMQ(); - } + // set data matching mode (need to call before setMacroPulseNumberSource, as the mode is checked there) + boost::dynamic_pointer_cast<DoocsProcessArray<DOOCS_T, DOOCS_PRIMITIVE_T>>(doocsPV) + ->_consistencyGroup.setMatchingMode(propertyDescription.dataMatching); - // set data matching mode (need to call before setMacroPulseNumberSource, as the mode is checked there) - boost::dynamic_pointer_cast<DoocsProcessArray<DOOCS_T, DOOCS_PRIMITIVE_T>>(doocsPV) - ->_consistencyGroup.setMatchingMode(propertyDescription.dataMatching); - - // set macro pulse number source, if configured - if(propertyDescription.macroPulseNumberSource.size() > 0) { - auto mpnSource = _controlSystemPVManager->getProcessVariable(propertyDescription.macroPulseNumberSource); - auto mpnDecorated = getDecorator<int64_t>(mpnSource, DecoratorType::C_style_conversion); - if(mpnDecorated->getNumberOfSamples() != 1) { - throw ChimeraTK::logic_error("The property '" + mpnDecorated->getName() + - "' is used as a macro pulse number source, but it has an array " - "length of " + - std::to_string(mpnDecorated->getNumberOfSamples()) + ". Length must be exactly 1"); - } - if(!mpnDecorated->isReadable()) { - throw ChimeraTK::logic_error("The property '" + mpnDecorated->getName() + - "' is used as a macro pulse number source, but it is not readable."); - } - boost::dynamic_pointer_cast<DoocsProcessArray<DOOCS_T, DOOCS_PRIMITIVE_T>>(doocsPV)->setMacroPulseNumberSource( - mpnDecorated); - } + // set macro pulse number source, if configured + if(propertyDescription.macroPulseNumberSource.size() > 0) { + auto mpnSource = _controlSystemPVManager->getProcessVariable(propertyDescription.macroPulseNumberSource); + auto mpnDecorated = getDecorator<int64_t>(mpnSource, DecoratorType::C_style_conversion); + if(mpnDecorated->getNumberOfSamples() != 1) { + throw ChimeraTK::logic_error("The property '" + mpnDecorated->getName() + + "' is used as a macro pulse number source, but it has an array " + "length of " + + std::to_string(mpnDecorated->getNumberOfSamples()) + ". Length must be exactly 1"); + } + if(!mpnDecorated->isReadable()) { + throw ChimeraTK::logic_error("The property '" + mpnDecorated->getName() + + "' is used as a macro pulse number source, but it is not readable."); + } + boost::dynamic_pointer_cast<DoocsProcessArray<DOOCS_T, DOOCS_PRIMITIVE_T>>(doocsPV)->setMacroPulseNumberSource( + mpnDecorated); + } - return doocsPV; -} - -// template specialisation for cases with no matching DOOCS array type (e.g. -// string) -template<> -boost::shared_ptr<D_fct> DoocsPVFactory::typedCreateDoocsArray<std::nullptr_t, std::nullptr_t>( - AutoPropertyDescription const&) { - throw std::invalid_argument("Type not supported as an array"); -} - -boost::shared_ptr<D_fct> DoocsPVFactory::createDoocsArray( - std::shared_ptr<AutoPropertyDescription> const& propertyDescription) { - if(propertyDescription->dataType == AutoPropertyDescription::DataType::Auto) { - // leave the desision which array to produce to the auto creation algorithm. - // We need it there anyway - // FIXME: This does not produce arrays of length 1 because it will produce a - // scalar - return autoCreate(propertyDescription); - } - else if(propertyDescription->dataType == AutoPropertyDescription::DataType::Byte) { - return typedCreateDoocsArray<uint8_t, D_bytearray>(*propertyDescription); - } - else if(propertyDescription->dataType == AutoPropertyDescription::DataType::Short) { - return typedCreateDoocsArray<int16_t, D_shortarray>(*propertyDescription); - } - else if(propertyDescription->dataType == AutoPropertyDescription::DataType::Int) { - return typedCreateDoocsArray<int32_t, D_intarray>(*propertyDescription); - } - else if(propertyDescription->dataType == AutoPropertyDescription::DataType::Long) { - return typedCreateDoocsArray<int64_t, D_longarray>(*propertyDescription); - } - else if(propertyDescription->dataType == AutoPropertyDescription::DataType::Float) { - return typedCreateDoocsArray<float, D_floatarray>(*propertyDescription); - } - else if(propertyDescription->dataType == AutoPropertyDescription::DataType::Double) { - return typedCreateDoocsArray<double, D_doublearray>(*propertyDescription); - } - else { - throw std::logic_error("DoocsPVFactory does not implement a data type it should!"); + return doocsPV; } -} -boost::shared_ptr<D_fct> DoocsPVFactory::create(std::shared_ptr<PropertyDescription> const& propertyDescription) { - auto& requestedType = propertyDescription->type(); - if(requestedType == typeid(AutoPropertyDescription)) { - return autoCreate(propertyDescription); - } - else if(requestedType == typeid(SpectrumDescription)) { - return createDoocsSpectrum(*std::static_pointer_cast<SpectrumDescription>(propertyDescription)); - } - else if(requestedType == typeid(XyDescription)) { - return createXy(*std::static_pointer_cast<XyDescription>(propertyDescription)); - } - else if(requestedType == typeid(IfffDescription)) { - return createIfff(*std::static_pointer_cast<IfffDescription>(propertyDescription)); + // template specialisation for cases with no matching DOOCS array type (e.g. + // string) + template<> + boost::shared_ptr<D_fct> DoocsPVFactory::typedCreateDoocsArray<std::nullptr_t, std::nullptr_t>( + AutoPropertyDescription const&) { + throw std::invalid_argument("Type not supported as an array"); } - else if(requestedType == typeid(AutoPropertyDescription)) { - return createDoocsArray(std::static_pointer_cast<AutoPropertyDescription>(propertyDescription)); + + boost::shared_ptr<D_fct> DoocsPVFactory::createDoocsArray( + std::shared_ptr<AutoPropertyDescription> const& propertyDescription) { + if(propertyDescription->dataType == AutoPropertyDescription::DataType::Auto) { + // leave the desision which array to produce to the auto creation algorithm. + // We need it there anyway + // FIXME: This does not produce arrays of length 1 because it will produce a + // scalar + return autoCreate(propertyDescription); + } + else if(propertyDescription->dataType == AutoPropertyDescription::DataType::Byte) { + return typedCreateDoocsArray<uint8_t, D_bytearray>(*propertyDescription); + } + else if(propertyDescription->dataType == AutoPropertyDescription::DataType::Short) { + return typedCreateDoocsArray<int16_t, D_shortarray>(*propertyDescription); + } + else if(propertyDescription->dataType == AutoPropertyDescription::DataType::Int) { + return typedCreateDoocsArray<int32_t, D_intarray>(*propertyDescription); + } + else if(propertyDescription->dataType == AutoPropertyDescription::DataType::Long) { + return typedCreateDoocsArray<int64_t, D_longarray>(*propertyDescription); + } + else if(propertyDescription->dataType == AutoPropertyDescription::DataType::Float) { + return typedCreateDoocsArray<float, D_floatarray>(*propertyDescription); + } + else if(propertyDescription->dataType == AutoPropertyDescription::DataType::Double) { + return typedCreateDoocsArray<double, D_doublearray>(*propertyDescription); + } + else { + throw std::logic_error("DoocsPVFactory does not implement a data type it should!"); + } } - else { - throw std::invalid_argument("Sorry, your type is not supported yet."); + + boost::shared_ptr<D_fct> DoocsPVFactory::create(std::shared_ptr<PropertyDescription> const& propertyDescription) { + auto& requestedType = propertyDescription->type(); + if(requestedType == typeid(AutoPropertyDescription)) { + return autoCreate(propertyDescription); + } + else if(requestedType == typeid(SpectrumDescription)) { + return createDoocsSpectrum(*std::static_pointer_cast<SpectrumDescription>(propertyDescription)); + } + else if(requestedType == typeid(XyDescription)) { + return createXy(*std::static_pointer_cast<XyDescription>(propertyDescription)); + } + else if(requestedType == typeid(IfffDescription)) { + return createIfff(*std::static_pointer_cast<IfffDescription>(propertyDescription)); + } + else if(requestedType == typeid(AutoPropertyDescription)) { + return createDoocsArray(std::static_pointer_cast<AutoPropertyDescription>(propertyDescription)); + } + else { + throw std::invalid_argument("Sorry, your type is not supported yet."); + } } -} } // namespace ChimeraTK