Skip to content
Snippets Groups Projects
Select Git revision
  • a8f652c49bb389dfdf606f5df996e4290475537c
  • master default protected
  • L2SS-1914-fix_job_dispatch
  • TMSS-3170
  • TMSS-3167
  • TMSS-3161
  • TMSS-3158-Front-End-Only-Allow-Changing-Again
  • TMSS-3133
  • TMSS-3319-Fix-Templates
  • test-fix-deploy
  • TMSS-3134
  • TMSS-2872
  • defer-state
  • add-custom-monitoring-points
  • TMSS-3101-Front-End-Only
  • TMSS-984-choices
  • SDC-1400-Front-End-Only
  • TMSS-3079-PII
  • TMSS-2936
  • check-for-max-244-subbands
  • TMSS-2927---Front-End-Only-PXII
  • Before-Remove-TMSS
  • LOFAR-Release-4_4_318 protected
  • LOFAR-Release-4_4_317 protected
  • LOFAR-Release-4_4_316 protected
  • LOFAR-Release-4_4_315 protected
  • LOFAR-Release-4_4_314 protected
  • LOFAR-Release-4_4_313 protected
  • LOFAR-Release-4_4_312 protected
  • LOFAR-Release-4_4_311 protected
  • LOFAR-Release-4_4_310 protected
  • LOFAR-Release-4_4_309 protected
  • LOFAR-Release-4_4_308 protected
  • LOFAR-Release-4_4_307 protected
  • LOFAR-Release-4_4_306 protected
  • LOFAR-Release-4_4_304 protected
  • LOFAR-Release-4_4_303 protected
  • LOFAR-Release-4_4_302 protected
  • LOFAR-Release-4_4_301 protected
  • LOFAR-Release-4_4_300 protected
  • LOFAR-Release-4_4_299 protected
41 results

Sequencer.cc

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    Sequencer.cc 28.28 KiB
    //#  Sequencer.cc: implementation of the Sequencer class
    //#
    //#  Copyright (C) 2002-2004
    //#  ASTRON (Netherlands Foundation for Research in Astronomy)
    //#  P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl
    //#
    //#  This program is free software; you can redistribute it and/or modify
    //#  it under the terms of the GNU General Public License as published by
    //#  the Free Software Foundation; either version 2 of the License, or
    //#  (at your option) any later version.
    //#
    //#  This program is distributed in the hope that it will be useful,
    //#  but WITHOUT ANY WARRANTY; without even the implied warranty of
    //#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    //#  GNU General Public License for more details.
    //#
    //#  You should have received a copy of the GNU General Public License
    //#  along with this program; if not, write to the Free Software
    //#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    //#
    //#  $Id$
    
    #include <lofar_config.h>
    #include <Common/LofarLogger.h>
    #include <APL/RSP_Protocol/EPA_Protocol.ph>
    
    #include <APL/RTCCommon/PSAccess.h>
    
    #include "Sequencer.h"
    #include "Cache.h"
    #include "StationSettings.h"
    
    using namespace blitz;
    namespace LOFAR {
        using namespace GCF::TM;
        using namespace EPA_Protocol;
        using namespace RTC;
        namespace RSP {
    
    #define STARTUP_WAIT   10
    #define TDWRITE_WAIT   1
    #define TDREAD_TIMEOUT 3
    #define RSUCLEAR_WAIT  5
    #define WRITE_TIMEOUT  3
    #define WRITE_ALL_TIMEOUT  5
    
    
    /*
     * Implements the following sequences:
     *  from idle state:
     * - SEQ_STARTUP, starts on sequence disableClock
     * - SEQ_SETCLOCK, starts on sequence writeClock
     * - SEQ_RSPCLEAR, starts on sequence RSUclear
     *
     *  idle_state  <--------------------------------------------,
     *   |  |  |                                                 |
     *   |  |  '-> disableClock_state <-------------------.      |   STARTUP_WAIT
     *   |  |      writePLL_state     ---> writeError ----'      |   WRITE_TIMEOUT
     *   |  '----> writeClock_state   <-------------------.      |   STARTUP_WAIT
     *   |         readClock_state    ---> readError -----'      |   TDREAD_TIMEOUT
     *   |  ,------- ok <------------'                           |
     *   '--C----> RSUclear_state     <----------------------,   |   RSUCLEAR_WAIT
     *      |----> RCUdisable_state -----> writeError -------|   |   WRITE_TIMEOUT
     *      | ,----- ok <-----------' '--> ok & finalState---C---'
     *      | '--> setBlocksync_state  --> writeError -------|       WRITE_TIMEOUT
     *      |      RADwrite_state      --> writeError -------|       WRITE_TIMEOUT
     *      |      PPSsync_state       --> writeError -------|       WRITE_TIMEOUT
     *      |      RCUenable_state     --> writeError -------|       WRITE_TIMEOUT
     *      |      CDOenable_state     --> writeError -------|       WRITE_TIMEOUT
     *      |      writeSDO_state      --> writeError -------'       WRITE_TIMEOUT
     *      |                          --> finalState=True --,
     *      |                                                |
     *      '------------------------------------------------'
     *
     */
    
    /*
     * Implements the following sequences:
     * from idle state:
     * - SEQ_STARTUP, starts on sequence disableClock
     * - SEQ_SETCLOCK, starts on sequence writeClock
     * - SEQ_RSPCLEAR, starts on sequence RSUclear
     *
     *  idle_state  <--------------------------------------------,
     *   |  |  |                                                 |
     *   |  |  '-> disableClock_state <-------------------.      |   STARTUP_WAIT
     *   |  |      writePLL_state     ---> writeError ----'      |   WRITE_TIMEOUT
     *   |  '----> writeClock_state   <-------------------.      |   STARTUP_WAIT
     *   |         readClock_state    ---> readError -----'      |   TDREAD_TIMEOUT
     *   |  ,------- ok <------------'                           |
     *   '--C----> RSUclear_state     <----------------------,   |   RSUCLEAR_WAIT
     *      |----> RCUdisable_state -----> writeError -------|   |   WRITE_TIMEOUT
     *      | ,----- ok <-----------' '--> ok & finalState---C---'
     *      | '--> setAll_state        --> writeError -------|       WRITE_TIMEOUT
     *      |      - Blocksync                               |
     *      |      - RADwrite                                |
     *      |      - PPSsync                                 |
     *      |      - CDOenable                               |
     *      |      - SDObitmode                              |
     *      |      - SDOselect                               |
     *      |      - SDOenable                               |
     *      |      RCUenable_state     --> writeError -------'       WRITE_TIMEOUT
     *      |                          --> finalState=True --,
     *      |                                                |
     *      '------------------------------------------------'
     *
     */
    
    
    /**
     * Instance pointer for the Cache singleton class.
     */
    Sequencer* Sequencer::m_instance = 0;
    
    Sequencer::Sequencer() :
        GCFFsm       ((State)&Sequencer::idle_state),
        itsIdle      (true),
        itsCurSeq    (SEQ_NONE),
        itsClockRequest (0),
        itsFinalState(false)
    { }
    
    Sequencer& Sequencer::getInstance()
    {
        if (!m_instance) {
            m_instance = new Sequencer;
        }
        return *m_instance;
    }
    
    Sequencer::~Sequencer()
    {}
    
    void Sequencer::run(GCFEvent& event, GCFPortInterface& port)
    {
        this->doEvent(event, port);
    }
    
    bool Sequencer::isActive() const
    {
        return (!itsIdle);
    }
    
    GCFEvent::TResult Sequencer::idle_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_INIT:
        break;
    
        case F_ENTRY: {
            LOG_INFO("Entering Sequencer::idle_state");
            itsIdle = true;
        }
        break;
    
        case F_TIMER: {
            if (GET_CONFIG("RSPDriver.DISABLE_INIT", i) == 0) {
                if (itsCurSeq == SEQ_STARTUP) {
                    LOG_DEBUG(">> Start sequencer *startup*");
                    TRAN(Sequencer::disableClock_state);
                }
                else if (itsCurSeq == SEQ_SETCLOCK) {
                    LOG_DEBUG(">> Start sequencer *setclock*");
                    Cache::getInstance().reset();
                    TRAN(Sequencer::clearClock_state);
                }
                else if (itsCurSeq == SEQ_RSPCLEAR) {
                    LOG_DEBUG(">> Start sequencer *rspclear*");
                    TRAN(Sequencer::RSUclear_state);
                }
            }
        }
        break;
    
        case F_EXIT: {
            LOG_DEBUG("Leaving Sequencer::idle_state");
            itsIdle       = false;
            itsFinalState = false;
        }
        break;
    
        default:
        break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    //
    // disableClock_state(event, port)
    //
    // before switching clock, goto 125 MHz (both clocks off)
    // this prevents locking of firmware
    //
    GCFEvent::TResult Sequencer::disableClock_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY: {
            LOG_INFO("Entering Sequencer::disableClock_state");
    
            // save clock
            itsClockRequest = Cache::getInstance().getBack().getClock();
    
            // set clock to internal board clock (125MHz)
            Cache::getInstance().getBack().getClock() = 125;
            Cache::getInstance().getFront().getClock() = 125;
    
            Cache::getInstance().getState().tdwrite().reset();
            Cache::getInstance().getState().tdwrite().write();
            itsTimer = 0;
            break;
        }
    
        case F_TIMER:
            if (itsTimer++ > STARTUP_WAIT && Cache::getInstance().getState().tdwrite().isMatchAll(RegisterState::IDLE)) {
                TRAN(Sequencer::readDisabledClock_state);
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::disableClock_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    //
    // readClock_state(event, port)
    //
    GCFEvent::TResult Sequencer::readDisabledClock_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY:
            LOG_INFO("Entering Sequencer::readDisabledClock_state");
            Cache::getInstance().getState().tdread().reset();
            Cache::getInstance().getState().tdread().read();
            itsTimer = 0;
            break;
    
        case F_TIMER:
            if (Cache::getInstance().getState().tdread().getMatchCount(RegisterState::READ_ERROR) > 0) {
                if (itsTimer++ > TDREAD_TIMEOUT) {
                    LOG_WARN("Failed to verify setting of clock. Retrying...");
                    TRAN(Sequencer::disableClock_state);
                } else {
                    // read again
                    Cache::getInstance().getState().tdread().reset();
                    Cache::getInstance().getState().tdread().read();
                }
            }
            else if (Cache::getInstance().getState().tdread().isMatchAll(RegisterState::IDLE)) {
                LOG_DEBUG_STR(formatString("disabled clock freq = %d MHz", Cache::getInstance().getBack().getClock()));
                if (Cache::getInstance().getBack().getClock() == 125) {
                    TRAN(Sequencer::writePLL_state);
                }
                else {
                    TRAN(Sequencer::disableClock_state);
                }
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::readDisabledClock_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    
    //
    // writePLL_state(event, port)
    //
    GCFEvent::TResult Sequencer::writePLL_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY: {
            LOG_INFO("Entering Sequencer::writePLL_state");
    
            // setting clock to 0, will result in programming the PLL
            Cache::getInstance().getBack().getClock() = 0;
            Cache::getInstance().getFront().getClock() = 0;
    
            // signal that the register has changed
            Cache::getInstance().getState().tdwrite().reset();
            Cache::getInstance().getState().tdwrite().write();
            itsTimer = 0;
            break;
        }
    
        case F_TIMER:
            if (itsTimer++ > TDWRITE_WAIT && Cache::getInstance().getState().tdwrite().isMatchAll(RegisterState::IDLE)) {
                TRAN(Sequencer::readPLL_state);
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::writePLL_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    //
    // readPLL_state(event, port)
    //
    GCFEvent::TResult Sequencer::readPLL_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY: {
            LOG_INFO("Entering Sequencer::readPLL_state");
    
            //TODO:
    
            // signal that the register has changed
            Cache::getInstance().getState().tdread().reset();
            Cache::getInstance().getState().tdread().read();
            itsTimer = 0;
            break;
        }
    
        case F_TIMER:
            if (Cache::getInstance().getState().tdread().getMatchCount(RegisterState::READ_ERROR) > 0) {
                if (itsTimer++ > TDREAD_TIMEOUT) {
                    LOG_WARN("Failed to verify setting of pll. Retrying...");
                    TRAN(Sequencer::writePLL_state);
                } else {
                    // read again
                    Cache::getInstance().getState().tdread().reset();
                    Cache::getInstance().getState().tdread().read();
                }
            }
            else if (Cache::getInstance().getState().tdread().isMatchAll(RegisterState::IDLE)) {
                Cache::getInstance().getBack().getClock() = 200; //itsClockRequest;
                Cache::getInstance().getFront().getClock() = 200; //itsClockRequest;
                TRAN(Sequencer::writeClock_state);
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::readPLL_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    
    //
    // clearClock_state(event, port)
    //
    GCFEvent::TResult Sequencer::clearClock_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY:
            LOG_INFO("Entering Sequencer::clearClock_state");
            Cache::getInstance().getState().tdclear().reset();
            Cache::getInstance().getState().tdclear().write();
            break;
    
        case F_TIMER:
            if (Cache::getInstance().getState().tdclear().isMatchAll(RegisterState::IDLE)) {
                TRAN(Sequencer::writeClock_state);
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::clearClock_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    //
    // writeClock_state(event, port)
    //
    GCFEvent::TResult Sequencer::writeClock_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY:
            LOG_INFO("Entering Sequencer::writeClock_state");
            Cache::getInstance().getState().tdwrite().reset();
            Cache::getInstance().getState().tdwrite().write();
            itsTimer = 0;
            break;
    
        case F_TIMER:
            if (itsTimer++ > STARTUP_WAIT && Cache::getInstance().getState().tdwrite().isMatchAll(RegisterState::IDLE)) {
                TRAN(Sequencer::readClock_state);
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::writeClock_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    //
    // readClock_state(event, port)
    //
    GCFEvent::TResult Sequencer::readClock_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY:
            LOG_INFO("Entering Sequencer::readClock_state");
            Cache::getInstance().getState().tdread().reset();
            Cache::getInstance().getState().tdread().read();
            itsTimer = 0;
            break;
    
        case F_TIMER:
            if (Cache::getInstance().getState().tdread().getMatchCount(RegisterState::READ_ERROR) > 0) {
                if (itsTimer++ > TDREAD_TIMEOUT) {
                    LOG_WARN("Failed to verify setting of clock. Retrying...");
                    TRAN(Sequencer::writeClock_state);
                } else {
                    // read again
                    Cache::getInstance().getState().tdread().reset();
                    Cache::getInstance().getState().tdread().read();
                }
            }
            else if (Cache::getInstance().getState().tdread().isMatchAll(RegisterState::IDLE)) {
                TRAN(Sequencer::RCUdisable_state);
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::readClock_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    //
    // RCUdisable_state(event, port)
    //
    GCFEvent::TResult Sequencer::RCUdisable_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY:
            LOG_INFO("Entering Sequencer::RCUdisable_state");
            enableRCUs(false);
            itsTimer = 0;
            break;
    
        case F_TIMER:
            if (itsTimer++ > WRITE_TIMEOUT && Cache::getInstance().getState().rcusettings().getMatchCount(RegisterState::WRITE) > 0) {
                LOG_WARN("Failed to disable receivers. Retrying...");
                itsFinalState = false;
                TRAN(Sequencer::clearClock_state);
            } else if (Cache::getInstance().getState().rcusettings().isMatchAll(RegisterState::IDLE)) {
                if (itsFinalState) {
                    stopSequence();
                    LOG_DEBUG("<< Stop sequencer");
                    TRAN(Sequencer::idle_state);
                }
                else {
                    //TRAN(Sequencer::setBlocksync_state);
                    TRAN(Sequencer::setAll_state);
                }
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::RCUdisable_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    //
    // RSUclear(event, port)
    //
    GCFEvent::TResult Sequencer::RSUclear_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY: {
            LOG_INFO("Entering Sequencer::RSUclear_state");
    
            // Change the register to set the clear flag
            RSUSettings::ResetControl rsumode;
            rsumode.setClear(true);
            for (int rsp = 0; rsp < StationSettings::instance()->nrRspBoards(); rsp++) {
                Cache::getInstance().getBack().getRSUSettings()()(rsp) = rsumode;
            }
    
            // signal that the register has changed
            Cache::getInstance().getState().rsuclear().reset();
            Cache::getInstance().getState().rsuclear().write();
    
            itsTimer = 0;
            break;
        }
    
        case F_TIMER:
            if (itsTimer++ > RSUCLEAR_WAIT && Cache::getInstance().getState().rsuclear().isMatchAll(RegisterState::IDLE)) {
                //TRAN(Sequencer::setBlocksync_state);
                TRAN(Sequencer::setAll_state);
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::RSUclear_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    //
    // setAll_state(event, port)
    //
    GCFEvent::TResult Sequencer::setAll_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY:
            LOG_INFO("Entering Sequencer::setAll_state");
            Cache::getInstance().getState().bs().reset();
            Cache::getInstance().getState().bs().write();
            Cache::getInstance().getState().rad().reset();
            Cache::getInstance().getState().rad().write();
            Cache::getInstance().getState().crcontrol().reset();
            Cache::getInstance().getState().crcontrol().read();
            Cache::getInstance().getState().cdo().reset();
            Cache::getInstance().getState().cdo().write();
            if (StationSettings::instance()->hasAartfaac()) {
                Cache::getInstance().getState().sdoState().reset();
                Cache::getInstance().getState().sdoState().write();
                Cache::getInstance().getState().sdoSelectState().reset();
                Cache::getInstance().getState().sdoSelectState().write();
    
                for (int blp_nr = 0; blp_nr < StationSettings::instance()->nrBlps(); blp_nr += 4) {
                    Cache::getInstance().getState().bypasssettings().reset(blp_nr);
                    Cache::getInstance().getState().bypasssettings().write(blp_nr);
                }
            }
            itsTimer = 0;
            break;
    
        case F_TIMER:
            if (itsTimer++ > WRITE_ALL_TIMEOUT) {
                if (Cache::getInstance().getState().bs().getMatchCount(RegisterState::WRITE) > 0) {
                    LOG_WARN("Failed to set BS (blocksync) register. Retrying...");
                    Cache::getInstance().getState().bs().reset();
                }
                if (Cache::getInstance().getState().rad().getMatchCount(RegisterState::WRITE) > 0) {
                    LOG_WARN("Failed to write RAD settings register. Retrying...");
                }
                if (Cache::getInstance().getState().crcontrol().getMatchCount(RegisterState::WRITE) > 0) {
                    LOG_WARN("Failed to write PPSsync settings register. Retrying...");
                    stringstream    ss;
                    Cache::getInstance().getState().crcontrol().print(ss);
                    LOG_DEBUG_STR("PPSsync failure state: " << ss);
                }
                if (Cache::getInstance().getState().cdo().getMatchCount(RegisterState::WRITE) > 0) {
                    LOG_WARN("Failed to enable receivers. Retrying...");
                }
    /*
                if (StationSettings::instance()->hasAartfaac()) {
                    if (Cache::getInstance().getState().sdoState().getMatchCount(RegisterState::WRITE) > 0) {
                        LOG_WARN("Failed to set SDO state. Retrying...");
                    }
                    if (Cache::getInstance().getState().sdoSelectState().getMatchCount(RegisterState::WRITE) > 0) {
                        LOG_WARN("Failed to set SDO select. Retrying...");
                    }
                    if (Cache::getInstance().getState().bypasssettings().getMatchCount(RegisterState::WRITE) > 0) {
                        LOG_WARN("Failed to set SDO settings. Retrying...");
                    }
                }
    */
                TRAN(Sequencer::RSUclear_state);
            }
            else if (Cache::getInstance().getState().bs().isMatchAll(RegisterState::IDLE)
                  && Cache::getInstance().getState().rad().isMatchAll(RegisterState::IDLE)
                  && Cache::getInstance().getState().crcontrol().isMatchAll(RegisterState::IDLE)
                  && Cache::getInstance().getState().cdo().isMatchAll(RegisterState::IDLE) ) {
    
                    TRAN(Sequencer::RCUenable_state);
    /*
                if (StationSettings::instance()->hasAartfaac()) {
                    if ( Cache::getInstance().getState().sdoState().isMatchAll(RegisterState::IDLE)
                      && Cache::getInstance().getState().sdoSelectState().isMatchAll(RegisterState::IDLE)
                      && Cache::getInstance().getState().bypasssettings().isMatchAll(RegisterState::IDLE) ) {
                        TRAN(Sequencer::RCUenable_state);
                    }
                }
                else {
                    TRAN(Sequencer::RCUenable_state);
                }
    */
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::setAll_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    
    //
    // setBlocksync_state(event, port)
    //
    GCFEvent::TResult Sequencer::setBlocksync_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY:
            LOG_INFO("Entering Sequencer::setBlocksync_state");
            Cache::getInstance().getState().bs().reset();
            Cache::getInstance().getState().bs().write();
            itsTimer = 0;
            break;
    
        case F_TIMER:
            if (itsTimer++ > WRITE_TIMEOUT &&
                    Cache::getInstance().getState().bs().getMatchCount(RegisterState::WRITE) > 0) {
                LOG_WARN("Failed to set BS (blocksync) register. Retrying...");
                Cache::getInstance().getState().bs().reset();
                TRAN(Sequencer::RSUclear_state);
            }
            else if (Cache::getInstance().getState().bs().isMatchAll(RegisterState::IDLE)) {
                TRAN(Sequencer::RADwrite_state);
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::setBlocksync_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    //
    // RADwrite_state(event, port)
    //
    GCFEvent::TResult Sequencer::RADwrite_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY:
            LOG_INFO("Entering Sequencer::RADwrite_state");
            Cache::getInstance().getState().rad().reset();
            Cache::getInstance().getState().rad().write();
            itsTimer = 0;
            break;
    
        case F_TIMER:
            if (itsTimer++ > WRITE_TIMEOUT &&
                    Cache::getInstance().getState().rad().getMatchCount(RegisterState::WRITE) > 0) {
                LOG_WARN("Failed to write RAD settings register. Retrying...");
                TRAN(Sequencer::RSUclear_state);
            }
            else if (Cache::getInstance().getState().rad().isMatchAll(RegisterState::IDLE)) {
                TRAN(Sequencer::PPSsync_state);
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::RADwrite_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    //
    // PPSsync_state(event, port)
    //
    GCFEvent::TResult Sequencer::PPSsync_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY:
            LOG_INFO("Entering Sequencer::PPSsync_state");
            Cache::getInstance().getState().crcontrol().reset(); // set to IDLE
            Cache::getInstance().getState().crcontrol().read();  // set to READ
            // Note: we set the state to read iso write so that the CRSync action knows it a new start.
            //       It will send a 'reset' to the registers first and than change the state to write during
            //       the repeated writes till all APs have the right delay.
            itsTimer = 0;
            break;
    
        case F_TIMER:
            if (itsTimer++ > WRITE_TIMEOUT &&
                    Cache::getInstance().getState().crcontrol().getMatchCount(RegisterState::WRITE) > 0) {
                LOG_WARN("Failed to write PPSsync settings register. Retrying...");
                stringstream    ss;
                Cache::getInstance().getState().crcontrol().print(ss);
                LOG_DEBUG_STR("PPSsync failure state: " << ss);
                TRAN(Sequencer::RSUclear_state);
            }
            else if (Cache::getInstance().getState().crcontrol().isMatchAll(RegisterState::IDLE)) {
                TRAN(Sequencer::RCUenable_state);
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::PPSsync_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    //
    // enableRCUs [private]
    //
    void Sequencer::enableRCUs(bool on)
    {
        RCUSettings::Control control;
        control.setEnable(on ? 1 : 0);
    
        Cache::getInstance().getFront().getRCUSettings()() = control;
        Cache::getInstance().getBack().getRCUSettings()() = control;
    
        Cache::getInstance().getState().rcusettings().reset();
        Cache::getInstance().getState().rcusettings().write();
    }
    
    //
    // RCUenable_state(event, port)
    //
    GCFEvent::TResult Sequencer::RCUenable_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        static bool waitForOddSecond(false);
    
        switch (event.signal) {
        case F_ENTRY: {
            LOG_INFO("Entering Sequencer::RCUenable_state");
            itsTimer = 0;
    
            // command may only be executed on even seconds for RTCP
            // since the timestamp is always one second ahead we have
            // to wait of an odd second (to end in the even second).
            if (time(0) % 2 == 0) {
                waitForOddSecond = true;
                LOG_INFO("Wait for even second before enabling RCUs");
                break;
            }
    
            waitForOddSecond = false;
            LOG_INFO("Entry at even second, enabling RCUs immediately");
            enableRCUs(true);
        }
        break;
    
        case F_TIMER: {
            if (waitForOddSecond) {
                if (time(0) % 2 == 0) {
                    LOG_INFO("Still waiting for even second, missed pps?");
                    break;
                }
                waitForOddSecond = false;
                LOG_INFO("Enabling RCUs delayed till even second");
                enableRCUs(true);
                break;
            }
    
            // Command are sent, wait for command to complete.
            if (itsTimer++ > WRITE_TIMEOUT &&
                Cache::getInstance().getState().rcusettings().getMatchCount(RegisterState::WRITE) > 0) {
                LOG_WARN("Failed to enable receivers. Retrying...");
                TRAN(Sequencer::RSUclear_state);
            } else if (Cache::getInstance().getState().rcusettings().isMatchAll(RegisterState::IDLE)) {
                itsFinalState = true;
                TRAN(Sequencer::RCUdisable_state);
                //TRAN(Sequencer::CDOenable_state);
            }
        }
        break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::RCUenable_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    //
    // CDOenable_state(event, port)
    //
    GCFEvent::TResult Sequencer::CDOenable_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY:
            LOG_INFO("Entering Sequencer::CDOenable_state");
            Cache::getInstance().getState().cdo().reset();
            Cache::getInstance().getState().cdo().write();
            itsTimer = 0;
            break;
    
        case F_TIMER:
            if (itsTimer++ > WRITE_TIMEOUT &&
                    Cache::getInstance().getState().cdo().getMatchCount(RegisterState::WRITE) > 0) {
                LOG_WARN("Failed to enable receivers. Retrying...");
                TRAN(Sequencer::RSUclear_state);
            } else if (Cache::getInstance().getState().cdo().isMatchAll(RegisterState::IDLE)) {
                if (StationSettings::instance()->hasAartfaac()) {
                    TRAN(Sequencer::setSDOwrite_state);
                }
                else {
                    itsFinalState = true;
                    TRAN(Sequencer::RCUdisable_state);
                }
            }
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::CDOenable_state");
            break;
    
        default:
            break;
        }
    
        return (GCFEvent::HANDLED);
    }
    
    //
    // setSDOwrite_state(event, port)
    //
    GCFEvent::TResult Sequencer::setSDOwrite_state(GCFEvent& event, GCFPortInterface& /*port*/)
    {
        switch (event.signal) {
        case F_ENTRY:
            LOG_INFO("Entering Sequencer::setSDOwrite_state");
    
            Cache::getInstance().getState().sdoState().reset();
            Cache::getInstance().getState().sdoState().write();
            Cache::getInstance().getState().sdoSelectState().reset();
            Cache::getInstance().getState().sdoSelectState().write();
    
            for (int blp_nr = 0; blp_nr < StationSettings::instance()->nrBlps(); blp_nr += 4) {
                Cache::getInstance().getState().bypasssettings().reset(blp_nr);
                Cache::getInstance().getState().bypasssettings().write(blp_nr);
            }
            itsFinalState = true;
            TRAN(Sequencer::RCUdisable_state);
            break;
    
        case F_TIMER:
            break;
    
        case F_EXIT:
            LOG_DEBUG("Leaving Sequencer::setSDOwrite_state");
            break;
    
        default:
            break;
        }
        return (GCFEvent::HANDLED);
    }
    
    
      } // namespace RSP
    } // namespace LOFAR