Skip to content
Snippets Groups Projects
FeedingFanOut.h 4.38 KiB
Newer Older
/*
 * FeedingFanOut.h
 *
 *  Created on: Jun 15, 2016
 *      Author: Martin Hierholzer
 */

#ifndef CHIMERATK_FEEDING_FAN_OUT_H
#define CHIMERATK_FEEDING_FAN_OUT_H

#include <mtca4u/NDRegisterAccessor.h>

#include "ApplicationException.h"

namespace ChimeraTK {

  
  template<typename UserType>
  class FeedingFanOut : public mtca4u::NDRegisterAccessor<UserType> {

    public:

      /** Add a slave to the FanOut. Only sending end-points of a consuming node may be added. */
      void addSlave(boost::shared_ptr<mtca4u::NDRegisterAccessor<UserType>> slave) {
        if(!slave->isWriteable()) {
          throw ApplicationExceptionWithID<ApplicationExceptionID::illegalParameter>(
              "FeedingFanOut::addSlave() has been called with a receiving implementation!");
        }
        if(slaves.size() == 0) {    // first slave: initialise buffers  @todo TODO FIXME first slave could be a trigger receiver!
          mtca4u::NDRegisterAccessor<UserType>::buffer_2D.resize( slave->getNumberOfChannels() );
          for(size_t i=0; i<slave->getNumberOfChannels(); i++) {
            mtca4u::NDRegisterAccessor<UserType>::buffer_2D[i].resize( slave->getNumberOfSamples() );
          }
        }
        else {
          // check if array shape is compatible, unless the receiver is a trigger node, so no data is expected
          if( slave->getNumberOfSamples() != 0 && 
              ( slave->getNumberOfChannels() != slaves.front()->getNumberOfChannels() ||
                slave->getNumberOfSamples() != slaves.front()->getNumberOfSamples()      ) ) {
            std::string what = "FeedingFanOut::addSlave(): Trying to add a slave '";
            what += slave->getName();
            what += "' with incompatible array shape! Name of first slave: ";
            what += slaves.front()->getName();
            throw ApplicationExceptionWithID<ApplicationExceptionID::illegalParameter>(what.c_str());
          }
        }
        slaves.push_back(slave);
      }

      bool isReadable() const override {
        return false;
      }
      
      bool isReadOnly() const override {
        return false;
      }
      
      bool isWriteable() const override {
        return true;
      }
      
      void doReadTransfer() override {
        throw std::logic_error("Read operation called on write-only variable.");
      }
      
      bool doReadTransferNonBlocking() override {
        throw std::logic_error("Read operation called on write-only variable.");
      }
      
      void postRead() override {
        throw std::logic_error("Read operation called on write-only variable.");
      }

      void write() override {
        boost::shared_ptr<mtca4u::NDRegisterAccessor<UserType>> firstSlave;   // will have the data for the other slaves after swapping
        for(auto &slave : slaves) {               // send out copies to slaves
          if(slave->getNumberOfSamples() != 0) {  // do not send copy if no data is expected (e.g. trigger)
            if(!firstSlave) {                     // in case of first slave, swap instead of copy
              firstSlave = slave;
              firstSlave->accessChannel(0).swap(mtca4u::NDRegisterAccessor<UserType>::buffer_2D[0]);
            }
            else {                                // not the first slave: copy the data from the first slave
              slave->accessChannel(0) = firstSlave->accessChannel(0);
            }
          }
          slave->write();
        }
        // swap back the data from the first slave so we still have it available
        if(firstSlave) {
          firstSlave->accessChannel(0).swap(mtca4u::NDRegisterAccessor<UserType>::buffer_2D[0]);
        }
        return;
      }
      
      bool isSameRegister(const boost::shared_ptr<const mtca4u::TransferElement>& e) const override {
        // only true if the very instance of the transfer element is the same
        return e.get() == this;
      }
      
      std::vector<boost::shared_ptr<mtca4u::TransferElement> > getHardwareAccessingElements() override {
        return { boost::enable_shared_from_this<mtca4u::TransferElement>::shared_from_this() };
      }
      
      void replaceTransferElement(boost::shared_ptr<mtca4u::TransferElement>) override {
        // You can't replace anything here. Just do nothing.
      }
      
    protected:

      std::list<boost::shared_ptr<mtca4u::NDRegisterAccessor<UserType>>> slaves;

  };

} /* namespace ChimeraTK */

#endif /* CHIMERATK_FEEDING_FAN_OUT_H */