// $Header: https://oberon.oapd.inaf.it/shins/trunk/shins/src/tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/ServiceWorker.h 3830 2022-02-18 18:47:26Z depa $
#pragma once

#include <Basda/Device.h>
#include "tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/Device.h"
#include "tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/DeviceFactory.h"

#include "tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/BcuSkeleton.h"
#include "tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/OverallDiagnosticRecordBuffer.h"
#include "tiptilt_ctrl/bcu/Interface/Sharknir/Bcu/ActiveDiagnosticsCollector.h"

#include "tiptilt_ctrl/bcu/util/ClockPtr.h"

#include <Nice/Util/Sync.h>

#include <map>


namespace Sharknir { namespace Bcu {

struct SharknirBcuSlopeDiagnosticRecord;

  class ServiceWorker : public Sharknir::BcuServiceWorkerSkeleton
  {
       struct DeviceAsyncImpl: Basda::DeviceAsync
       {
          virtual int asyncWait(const Nice::Time & _t);
          virtual int asyncStatus(const std::string & _s, int _d);
          ServiceWorker * m_worker;
       };
       DeviceAsyncImpl m_deviceAsync;

    public:
      ServiceWorker(const Nice::JointPtr & _config,
              const OverallDiagnosticRecordBufferPtr& diagnosticsBuffer,
              const Sharknir::util::ClockPtr& clock);

      /** @note overridden */
      virtual ~ServiceWorker();

      /** @note overridden */
      virtual void init();

      /** @note overridden */
      virtual void deinit();

      /** @note overridden */
      virtual void activate();

      /** @note overridden */
      virtual void deactivate();

      /** @note overridden */
      virtual void terminate();

      /** @note overridden */
      virtual void stop();

      /** @note overridden */
      virtual void abort();

      /** @note overridden */
      virtual void idleOnline();

      /** @note overridden */

      /**
       * @brief      Reset the BCU
       *
       * @param[in]  firstDsp  The first dsp
       * @param[in]  lastDsp   The last dsp
       * @param[in]  address   The address
       * @param[in]  buffer    The buffer
       */
      virtual void resetDevices(int firstDsp, int lastDsp, int address,
              const Nice::SeqInt& buffer);

      /** @note overridden */
      virtual void writeDsp(int firstDsp, int lastDsp, int address,
              const Nice::SeqInt& buffer);

      /** @note overridden */
      void writeSdram(int firstDsp, int lastDsp, int address,
              const Nice::SeqInt& buffer);

      /** @note overridden */
      virtual void writeSram(int firstDsp, int lastDsp, int address,
              const Nice::SeqInt& buffer);

    virtual void writeDMIF(int firstDsp, int lastDsp, int address,
                           const Nice::SeqInt& buffer);

    virtual void writeShMRam(int firstDsp, int lastDsp, int address,
                             const Nice::SeqInt& buffer);
      /** @note overridden */
      // virtual void writeDspFloat(int firstDsp, int lastDsp, int address,
      //   const Nice::SeqFloat& buffer);

      // /** @note overridden */
      // void writeSdramFloat(int firstDsp, int lastDsp, int address,
      //         const Nice::SeqFloat& buffer);

      // /** @note overridden */
      // virtual void writeSramFloat(int firstDsp, int lastDsp, int address,
      //   const Nice::SeqFloat& buffer);

      /** @note overridden */
      virtual Nice::SeqInt readDsp(int dspIndex, int address,
              int lengthInDword);

      /** @note overridden */
      virtual Nice::SeqInt readSdram(int dspIndex, int address,
              int lenghtInDword);

      virtual Nice::SeqInt readDiags(int dspIndex, int address, int lenghtInDword);

      /** @note overridden */
      virtual Nice::SeqInt readSram(int dspIndex, int address, int lenghtInDword);

      /** @note overridden */
      virtual Nice::SeqInt readShMRam(int dspIndex, int address, int lenghtInDword);



      /** @note overridden */
      virtual void uploadDspCode(int firstDsp, int lastDsp,
              const std::string& dspProgramPathOnServer);

      /** @note overridden */
      virtual void enableMasterDiagnostics(Nice::U16 decimationFactor,
              const std::string& remoteHostIpv4Address,
              const std::string& remoteHostMacAddress,
              Nice::U16 remoteHostUdpPort);


      /** @note overridden */
      virtual SeqOverallDiagnosticRecord
          getPastOverallDiagnosticRecordsInOnePass(int nRecords);

      /** @note overridden */
      virtual SeqOverallDiagnosticRecord
          getFutureOverallDiagnosticRecordsInOnePass(
              int nFutureRecords, Nice::Time timeout);

     /** @note overridden */
     virtual SeqOverallDiagnosticRecord
         getPastCcdOverallDiagnosticRecordsInOnePass(int nMaxRecords);

     /** @note overridden */
     virtual SeqOverallDiagnosticRecord
         getPastSlopeOverallDiagnosticRecordsInOnePass(int nMaxRecords);

      /** @note overridden */
      virtual SeqOverallDiagnosticRecord
          getFutureCcdOverallDiagnosticRecordsInOnePass(int nMaxRecords,
                  Nice::Time timeout);

      /** @note overridden */
      virtual SeqOverallDiagnosticRecord
          getFutureSlopeOverallDiagnosticRecordsInOnePass(int nMaxRecords,
                  Nice::Time timeout);

      /** @note overridden */
      virtual void createPastOverallDiagnosticRecordSnapshot(
              const std::string& cookie, int nRecords);

      /** @note overridden */
      virtual void freePastOverallDiagnosticRecordSnapshot(
              const std::string& cookie);

      /** @note overridden */
      virtual SeqOverallDiagnosticRecord
          getPastOverallDiagnosticRecordsFromSnapshot(
              const std::string& cookie, int startRecordIndex, int nRecords);

      /** @note overridden */
      virtual void createPastSlopeOverallDiagnosticRecordSnapshot(
    		  const std::string& COOKIE, int nRecords);

      /** @note overridden */
      void freePastSlopeOverallDiagnosticRecordSnapshot(
    		  const std::string& cookie);

      /** @note overridden */
      virtual SeqOverallDiagnosticRecord
	      getPastSlopeOverallDiagnosticRecordsFromSnapshot(
	    	  const std::string& cookie, int startRecordIndex, int nRecords);

      /** @note overridden */
      virtual void createFutureOverallDiagnosticRecordSnapshot(
              const std::string& cookie, int nRecords, Nice::Time timeout);

      /** @note overridden */
      virtual void freeFutureOverallDiagnosticRecordSnapshot(
              const std::string& cookie);

      /** @note overridden */
      virtual SeqOverallDiagnosticRecord
          getFutureOverallDiagnosticRecordsFromSnapshot(
              const std::string & cookie, int startRecordIndex, int nRecords);

      /** @note overridden */
      virtual void createFutureSlopeOverallDiagnosticRecordSnapshot(
             const std::string& cookie, int nRecords, Nice::Time timeout);

      /** @note overridden */
      virtual SeqOverallDiagnosticRecord
	      getFutureSlopeOverallDiagnosticRecordsFromSnapshot(
	          const std::string& cookie, int startRecordIndex, int nRecords);

      /** @note overridden */
      virtual void freeFutureSlopeOverallDiagnosticRecordSnapshot(
          const std::string& cookie);

      void setDeviceFactory(const Sharknir::Bcu::DeviceFactoryPtr& f);

      void setActiveDiagnosticsCollector(
              const ActiveDiagnosticsCollectorPtr& collector);

      void setMaxNumOfTolerableCommunicationGlitches(
              unsigned nReplyFailures);

      static std::string STARTED_UP_MESSAGE()
      {
          return "up and running";
      }

      struct PropertyValue
      {
          static std::string unknown()
          {
              return "?";
          }

          static std::string on()
          {
              return "On";
          }

          static std::string off()
          {
              return "Off";
          }
      };

      struct FrameCounterSnapshot
      {
          FrameCounter frameCounter;
          Nice::Date timestamp;
      };
      SHARKNIR_DECLARE_BOOST_SP(FrameCounterSnapshot);

  protected:
    virtual bool isStateTransitionRequested(int timeoutInMilliseconds);
    virtual void updateProperties();
    virtual void warnThatTemperatureExceedsLimit(
            const std::string& propertyName, double temperatureInC);
    void setDiagnosticsSnapshotTimeout(const Nice::Time&);

    OverallDiagnosticRecordBufferPtr diagnosticsBuffer_;


  private:
    struct TipTiltFrameCounterSnapshot
    {
        TipTiltFrameCounterSnapshot(const uint32_t fc,
                const Nice::Date& date) : frameCounter(fc), timestamp(date)
        {
        }

        const uint32_t frameCounter;
        const Nice::Date timestamp;
    };
    SHARKNIR_DECLARE_BOOST_SP(TipTiltFrameCounterSnapshot);

    struct OverallDiagnosticRecordSeqSnapshot
    {
        Nice::Date timestamp_;
        SeqOverallDiagnosticRecordPtr overallRecords_;
    };
    typedef std::string Cookie;
    typedef std::map<Cookie, OverallDiagnosticRecordSeqSnapshot>
            DiagnosticsSnapshotMap;

    void initializeCounterProperties();
    void updateDiagnosticsProperties();
    void updateSlopeRecordParametersFrom(const SharknirBcuSlopeDiagnosticRecord*);
    void updateParameteSelectorWord(const uint32_t paramSelector);
    void updateSlopeDiagnostics();
    void updateNaFrameCounter(const SharknirBcuSlopeDiagnosticRecord *);
    void updateFlaoFrameCounter(const SharknirBcuSlopeDiagnosticRecord *);
    void updateTipTiltDiagnostics(const SharknirBcuSlopeDiagnosticRecord *);
    void updateTipTiltFrameCounter(const SharknirBcuSlopeDiagnosticRecord *);
    void updateTipTiltReceivingRate(const SharknirBcuSlopeDiagnosticRecord *);
    void updateFrameRateProperty(const OverallDiagnosticRecord& record);
    void updateLastestPnCCDImage();
    void putCcdPixelsIntoProperty(const OverallDiagnosticRecord& record);
    void updateDiagnosticsCounterProperties();
    void updateDiagnosticsCounterProperty(const std::string& propertyName,
                                          const size_t counter);
    void updateTemperatureProperty(const std::string& propertyName,
            double tempInC);
    void addDummyCcdImageProperty();
    void setDeviceAsUnreachable();
    void invalidateTemperatureProperty(const std::string& propertyName);

    void writeToBcu(Basda::Microgate::OpCode opcode,
        int firstDsp, int lastDsp, int32_t address,
        const Nice::SeqInt& buffer,
        const std::string& operationDescription,
        const std::string& propertyName);

      Nice::SeqInt readFromBcu(Basda::Microgate::OpCode opcode, int dspIndex,
        int32_t address, unsigned lengthInDword,
        const std::string& opDescription,
        const std::string& propertyName);

      DevicePtr getDevice();
      void checkNumOfRequestedOverallDiagnosticRecords(int nRecords);
      void checkDiagnosticRecordAvailability(const int nRecords);
      void collectDiagnosticsSnapshotGarbage();
      void addRecordsToSnapshot(const Cookie&,
              const SeqOverallDiagnosticRecordPtr& records);
      SeqOverallDiagnosticRecord getOverallDiagnosticRecordsFromSnapshot(
        const Cookie& cookie, const int startRecordIndex, const int nRecords);
      void freeOverallDiagnosticRecordSnapshot(const Cookie& cookie);
      void keepHouse();

      DevicePtr device_;
      DeviceFactoryPtr deviceFactory_;
      Nice::Mutex deviceMutex_;
      ActiveDiagnosticsCollectorPtr activeDispatcher_;
      Sharknir::util::ClockPtr clock_;
      FrameCounterSnapshotPtr latestFrameCounterSnapshot_;
      TipTiltFrameCounterSnapshotPtr latestTipTiltFCSnapshot_;
      DiagnosticsSnapshotMap diagnosticsSnapshots_;
      Nice::Time diagnosticsSnapshotTimeout_;
      unsigned nMaxConsecutiveCommunicationGlitches_;
      unsigned communicationGlitchCount_;
  };

typedef IceUtil::Handle<ServiceWorker> ServiceWorkerPtr;
}
}
