diff --git a/MAC/APL/PIC/RSPDriver/src/RSPDriver.cc b/MAC/APL/PIC/RSPDriver/src/RSPDriver.cc index 1947e49d271912961ebbd5db287666317635438d..6b6bf05fb9b43f776e2d0029bc1469b14322917b 100644 --- a/MAC/APL/PIC/RSPDriver/src/RSPDriver.cc +++ b/MAC/APL/PIC/RSPDriver/src/RSPDriver.cc @@ -216,9 +216,6 @@ RSPDriver::RSPDriver(string name) : , m_ppshandle(0) #endif { -#ifdef HAVE_SYS_TIMEPPS_H - memset(&m_ppsinfo, 0, sizeof(pps_info_t)); -#endif LOG_INFO(Version::getInfo<RSPDriverVersion>("RSPDriver")); // first initialize the global settins @@ -245,6 +242,11 @@ RSPDriver::RSPDriver(string name) : exit(EXIT_FAILURE); } +#ifdef HAVE_SYS_TIMEPPS_H + memset(&m_ppsinfo, 0, sizeof(pps_info_t)); + itsPPSdelay = globalParameterSet()->getInt("RSPDriver.PPS_DELAY", 0); +#endif + // Register protocols for debugging LOG_DEBUG("Registering protocols"); registerProtocol(RSP_PROTOCOL, RSP_PROTOCOL_STRINGS); @@ -1018,91 +1020,92 @@ GCFEvent::TResult RSPDriver::enabled(GCFEvent& event, GCFPortInterface& port) case RSP_GETSPLITTER: rsp_getSplitter(event,port); break; case F_TIMER: { - if (&port == &m_boardPorts[0]) { - // - // If SYNC_MODE == SOFTWARE|FAST then run the scheduler - // directly on the software timer. - // - if ( (GET_CONFIG("RSPDriver.SYNC_MODE", i) == SYNC_SOFTWARE) - || (GET_CONFIG("RSPDriver.SYNC_MODE", i) == SYNC_FAST)) { - (void)clock_tick(m_acceptor); // force clock tick - } - else if (GET_CONFIG("RSPDriver.SYNC_MODE", i) == SYNC_PPS) { - GCFTimerEvent timer; + if (&port == &m_boardPorts[0]) { + // If SYNC_MODE == SOFTWARE|FAST then run the scheduler + // directly on the software timer. + if ( (GET_CONFIG("RSPDriver.SYNC_MODE", i) == SYNC_SOFTWARE) + || (GET_CONFIG("RSPDriver.SYNC_MODE", i) == SYNC_FAST)) { + (void)clock_tick(m_acceptor); // force clock tick + } + else if (GET_CONFIG("RSPDriver.SYNC_MODE", i) == SYNC_PPS) { + GCFTimerEvent timer; #ifdef HAVE_SYS_TIMEPPS_H - const GCFTimerEvent* timeout = static_cast<const GCFTimerEvent*>(&event); - pps_info_t prevppsinfo = m_ppsinfo; - - if ( fetchPPS() < 0 ) { - - LOG_WARN_STR("Error fetching PPS: " << strerror(errno)); - - // print time, ugly - char timestr[32]; - strftime(timestr, 32, "%T", gmtime(&timeout->sec)); - LOG_INFO(formatString("TICK: time=%s.%06d UTC (not PPS)", timestr, timeout->usec)); - - timer.sec = timeout->sec; - timer.usec = timeout->usec; - timer.id = 0; - timer.arg = 0; - - m_boardPorts[0].setTimer((long)1); // next event after exactly 1 second - - } else { - - // print time of day, ugly - char timestr[32]; - strftime(timestr, 32, "%T", gmtime(&timeout->sec)); - LOG_INFO(formatString("TICK: time=%s.%06d UTC (timeout)", timestr, timeout->usec)); - - // print time of day, ugly - strftime(timestr, 32, "%T", gmtime(&m_ppsinfo.assert_timestamp.tv_sec)); - LOG_INFO(formatString("TICK: PPS_time=%s.%06d UTC", timestr, m_ppsinfo.assert_timestamp.tv_nsec / 1000)); - - /* construct a timer event */ - timer.sec = m_ppsinfo.assert_timestamp.tv_sec; - timer.usec = m_ppsinfo.assert_timestamp.tv_nsec / 1000; - timer.id = 0; - timer.arg = 0; - - /* check for missed PPS */ - if (prevppsinfo.assert_sequence + 1 != m_ppsinfo.assert_sequence) { - LOG_WARN_STR("Missed " << m_ppsinfo.assert_sequence - prevppsinfo.assert_sequence - 1 << " PPS events."); - } - } - m_boardPorts[0].setTimer(0.95); // next event in just under 1 second + const GCFTimerEvent* timeout = static_cast<const GCFTimerEvent*>(&event); + pps_info_t prevppsinfo = m_ppsinfo; + + if ( fetchPPS() < 0 ) { + LOG_WARN_STR("Error fetching PPS: " << strerror(errno)); + + // print time, ugly + char timestr[32]; + strftime(timestr, 32, "%T", gmtime(&timeout->sec)); + LOG_INFO(formatString("TICK: time=%s.%06d UTC (not PPS)", timestr, timeout->usec)); + + timer.sec = timeout->sec; + timer.usec = timeout->usec; + timer.id = 0; + timer.arg = 0; + + m_boardPorts[0].setTimer((long)1); // next event after exactly 1 second + } + else { // fetching PPS went ok + // print time of day, ugly + char timestr[32]; + strftime(timestr, 32, "%T", gmtime(&m_ppsinfo.assert_timestamp.tv_sec)); + LOG_INFO(formatString("TICK: PPS_time=%s.%06d UTC", timestr, m_ppsinfo.assert_timestamp.tv_nsec / 1000)); + + /* construct a timer event */ + timer.sec = m_ppsinfo.assert_timestamp.tv_sec; + timer.usec = m_ppsinfo.assert_timestamp.tv_nsec / 1000; + timer.id = 0; + timer.arg = 0; + + /* check for missed PPS */ + if (prevppsinfo.assert_sequence + 1 != m_ppsinfo.assert_sequence) { + LOG_WARN_STR("Missed " << m_ppsinfo.assert_sequence - prevppsinfo.assert_sequence - 1 << " PPS events."); + } + + // delay the driver some number of microseconds after it receives the PPS tick + // this may be needed to synchronized the driver properly to the hardware + if (itsPPSdelay) { + usleep(itsPPSdelay); + // update values of timer event + timer.usec += itsPPSdelay; + if (timer.usec >= 1000000) { // crossing second boundary? + timer.sec++; + timer.usec -= 1000000; + } + + // print time of day, ugly + strftime(timestr, 32, "%T", gmtime(&timer.sec)); + LOG_INFO(formatString("TICK: start=%s.%06d UTC", timestr, timer.usec)); + } + } // fetching PPS + m_boardPorts[0].setTimer(0.95); // next event in just under 1 second #else - m_boardPorts[0].setTimer((long)1); // next event in one (software) second + m_boardPorts[0].setTimer((long)1); // next event in one (software) second #endif - // delay the driver some number of microseconds after it receives the PPS tick - // this may be needed to synchronized the driver properly to the hardware - if (GET_CONFIG("RSPDriver.PPS_DELAY", i) > 0) { - usleep(GET_CONFIG("RSPDriver.PPS_DELAY", i)); - } - - /* run the scheduler with the timer event */ - status = m_scheduler.run(timer, port); - Sequencer::getInstance().run(timer, port); - } - } - else if (&port == &m_acceptor) { - // print average number of updates - cerr << "Updates per second = " << m_update_counter << endl; + /* run the scheduler with the timer event */ + status = m_scheduler.run(timer, port); + Sequencer::getInstance().run(timer, port); + } // syncmode = PPS + } // port = boardports[0] + else if (&port == &m_acceptor) { + // print average number of updates + cerr << "Updates per second = " << m_update_counter << endl; + + if (m_update_counter > 0) { + m_n_updates += m_update_counter; + m_elapsed++; + cerr << "Average number of updates per second = " << (double)m_n_updates / m_elapsed << endl; + } - if (m_update_counter > 0) { - m_n_updates += m_update_counter; - m_elapsed++; - - cerr << "Average number of updates per second = " << (double)m_n_updates / m_elapsed << endl; - } - - m_update_counter = 0; - } - } - break; + m_update_counter = 0; + } + } + break; case F_DISCONNECTED: { LOG_INFO(formatString("DISCONNECTED: port '%s'", port.getName().c_str())); diff --git a/MAC/APL/PIC/RSPDriver/src/RSPDriver.h b/MAC/APL/PIC/RSPDriver/src/RSPDriver.h index ca5ad537c44ada42aa7ec376de1fb5a020c62c8c..b88a93045a00eccc6f6b19bb02d080207d6c5ae1 100644 --- a/MAC/APL/PIC/RSPDriver/src/RSPDriver.h +++ b/MAC/APL/PIC/RSPDriver/src/RSPDriver.h @@ -46,170 +46,151 @@ namespace LOFAR { using GCF::TM::GCFETHRawPort; namespace RSP { - class RSPDriver : public GCFTask - { - public: - /** - * The constructor of the RSPDriver task. - * @param name The name of the task. The name is used for looking - * up connection establishment information using the GTMNameService and - * GTMTopologyService classes. - */ - RSPDriver(string name); - virtual ~RSPDriver(); - - /** - * Add all required synchronization actions. - */ - void addAllSyncActions(); - - /** - * Open or close all ports to boards. - */ - void openBoards(); - - /** - * Fetch PPS - * This method retries on EINTR or EAGAIN - */ - int fetchPPS(); - - /** - * @return true if ready to transition to the enabled - * state. - */ - bool isEnabled(); - - /** - * The initial state. This state is used to connect the client - * and board ports. When they are both connected a transition - * to the enabled state is made. - */ - GCFEvent::TResult initial(GCFEvent& event, GCFPortInterface &port); - - /** - * Delete the client ports on the m_dead_clients. - */ - void undertaker(); - - /** - * The enabled state. In this state the task can receive - * commands. - */ - GCFEvent::TResult enabled(GCFEvent& event, GCFPortInterface &port); - - /** - * Is this port connected to a board? - */ - bool isBoardPort(GCFPortInterface& port); - - /** - * Handle a F_DATAIN on the clock port. - */ - GCFEvent::TResult clock_tick(GCFPortInterface& port); - - /*@{*/ - /** - * Handlers for the different events. - */ - void rsp_setweights(GCFEvent& event, GCFPortInterface &port); - void rsp_getweights(GCFEvent& event, GCFPortInterface &port); - - void rsp_setsubbands (GCFEvent& event, GCFPortInterface &port); - void rsp_getsubbands (GCFEvent& event, GCFPortInterface &port); - void rsp_subsubbands (GCFEvent& event, GCFPortInterface &port); - void rsp_unsubsubbands(GCFEvent& event, GCFPortInterface &port); - - void rsp_setrcu (GCFEvent& event, GCFPortInterface &port); - void rsp_getrcu (GCFEvent& event, GCFPortInterface &port); - void rsp_subrcu (GCFEvent& event, GCFPortInterface &port); - void rsp_unsubrcu(GCFEvent& event, GCFPortInterface &port); - - void rsp_sethba (GCFEvent& event, GCFPortInterface &port); - void rsp_gethba (GCFEvent& event, GCFPortInterface &port); - void rsp_readhba (GCFEvent& event, GCFPortInterface &port); - void rsp_subhba (GCFEvent& event, GCFPortInterface &port); - void rsp_unsubhba(GCFEvent& event, GCFPortInterface &port); - - void rsp_setrsu (GCFEvent& event, GCFPortInterface &port); - - void rsp_setwg(GCFEvent& event, GCFPortInterface &port); - void rsp_getwg(GCFEvent& event, GCFPortInterface &port); - - void rsp_substatus (GCFEvent& event, GCFPortInterface &port); - void rsp_unsubstatus(GCFEvent& event, GCFPortInterface &port); - void rsp_getstatus (GCFEvent& event, GCFPortInterface &port); - - void rsp_substats (GCFEvent& event, GCFPortInterface &port); - void rsp_unsubstats(GCFEvent& event, GCFPortInterface &port); - void rsp_getstats (GCFEvent& event, GCFPortInterface &port); - - void rsp_subxcstats (GCFEvent& event, GCFPortInterface &port); - void rsp_unsubxcstats(GCFEvent& event, GCFPortInterface &port); - void rsp_getxcstats (GCFEvent& event, GCFPortInterface &port); - - void rsp_getversions(GCFEvent& event, GCFPortInterface &port); - - void rsp_getconfig(GCFEvent& event, GCFPortInterface &port); - - void rsp_setclock(GCFEvent& event, GCFPortInterface &port); - void rsp_getclock(GCFEvent& event, GCFPortInterface &port); - void rsp_subclock(GCFEvent& event, GCFPortInterface &port); - void rsp_unsubclock(GCFEvent& event, GCFPortInterface &port); - - void rsp_subtdstatus (GCFEvent& event, GCFPortInterface &port); - void rsp_unsubtdstatus(GCFEvent& event, GCFPortInterface &port); - void rsp_gettdstatus (GCFEvent& event, GCFPortInterface &port); - - void rsp_getregisterstate(GCFEvent& event, GCFPortInterface &port); - void rsp_subregisterstate(GCFEvent& event, GCFPortInterface &port); - void rsp_unsubregisterstate(GCFEvent& event, GCFPortInterface &port); - - void rsp_settbb(GCFEvent& event, GCFPortInterface &port); - void rsp_gettbb(GCFEvent& event, GCFPortInterface &port); - - void rsp_setbypass(GCFEvent& event, GCFPortInterface &port); - void rsp_getbypass(GCFEvent& event, GCFPortInterface &port); - - void rsp_getspustatus(GCFEvent& event, GCFPortInterface &port); - - void rsp_setRawBlock(GCFEvent& event, GCFPortInterface &port); - void rsp_getRawBlock(GCFEvent& event, GCFPortInterface &port); - - void rsp_setSplitter(GCFEvent& event, GCFPortInterface &port); - void rsp_getSplitter(GCFEvent& event, GCFPortInterface &port); - /*@}*/ - - private: - // define some constants - // mode of operation - static const int32 MODE_NORMAL = 0; // control all RSPboards - static const int32 MODE_SUBSTATION = 1; // control only one RSPboard - - // Synchronisation mode - static const int32 SYNC_SOFTWARE = 1; // generated by software timer - static const int32 SYNC_FAST = 2; // as fast as possible - static const int32 SYNC_PPS = 3; // PPS on /dev/pps0 - - // ports - GCFTCPPort m_acceptor; // listen for clients on this port - GCFETHRawPort* m_boardPorts; // array of ports, one for each RSP board - std::list<GCFPortInterface*> m_client_list; // list of clients - std::list<GCFPortInterface*> m_dead_clients; // list of clients to cleanup +class RSPDriver : public GCFTask +{ +public: + // The constructor of the RSPDriver task. + // @param name The name of the task. The name is used for looking + // up connection establishment information using the GTMNameService and + // GTMTopologyService classes. + RSPDriver(string name); + virtual ~RSPDriver(); - Scheduler m_scheduler; - int m_update_counter; // nr of updates completed in one second - int m_n_updates; // number of completed updates - int m_elapsed; // elapsed number of seconds + // Add all required synchronization actions. + void addAllSyncActions(); + + // Open or close all ports to boards. + void openBoards(); + + // Fetch PPS + // This method retries on EINTR or EAGAIN + int fetchPPS(); + + // @return true if ready to transition to the enabled + // state. + bool isEnabled(); + + // The initial state. This state is used to connect the client + // and board ports. When they are both connected a transition + // to the enabled state is made. + GCFEvent::TResult initial(GCFEvent& event, GCFPortInterface &port); + + // Delete the client ports on the m_dead_clients. + void undertaker(); + + // The enabled state. In this state the task can receive + // commands. + GCFEvent::TResult enabled(GCFEvent& event, GCFPortInterface &port); + + // Is this port connected to a board? + bool isBoardPort(GCFPortInterface& port); + + // Handle a F_DATAIN on the clock port. + GCFEvent::TResult clock_tick(GCFPortInterface& port); + + /*@{*/ + // Handlers for the different events. + void rsp_setweights(GCFEvent& event, GCFPortInterface &port); + void rsp_getweights(GCFEvent& event, GCFPortInterface &port); + + void rsp_setsubbands (GCFEvent& event, GCFPortInterface &port); + void rsp_getsubbands (GCFEvent& event, GCFPortInterface &port); + void rsp_subsubbands (GCFEvent& event, GCFPortInterface &port); + void rsp_unsubsubbands(GCFEvent& event, GCFPortInterface &port); + + void rsp_setrcu (GCFEvent& event, GCFPortInterface &port); + void rsp_getrcu (GCFEvent& event, GCFPortInterface &port); + void rsp_subrcu (GCFEvent& event, GCFPortInterface &port); + void rsp_unsubrcu(GCFEvent& event, GCFPortInterface &port); + + void rsp_sethba (GCFEvent& event, GCFPortInterface &port); + void rsp_gethba (GCFEvent& event, GCFPortInterface &port); + void rsp_readhba (GCFEvent& event, GCFPortInterface &port); + void rsp_subhba (GCFEvent& event, GCFPortInterface &port); + void rsp_unsubhba(GCFEvent& event, GCFPortInterface &port); + + void rsp_setrsu (GCFEvent& event, GCFPortInterface &port); + + void rsp_setwg(GCFEvent& event, GCFPortInterface &port); + void rsp_getwg(GCFEvent& event, GCFPortInterface &port); + + void rsp_substatus (GCFEvent& event, GCFPortInterface &port); + void rsp_unsubstatus(GCFEvent& event, GCFPortInterface &port); + void rsp_getstatus (GCFEvent& event, GCFPortInterface &port); + + void rsp_substats (GCFEvent& event, GCFPortInterface &port); + void rsp_unsubstats(GCFEvent& event, GCFPortInterface &port); + void rsp_getstats (GCFEvent& event, GCFPortInterface &port); + + void rsp_subxcstats (GCFEvent& event, GCFPortInterface &port); + void rsp_unsubxcstats(GCFEvent& event, GCFPortInterface &port); + void rsp_getxcstats (GCFEvent& event, GCFPortInterface &port); + + void rsp_getversions(GCFEvent& event, GCFPortInterface &port); + + void rsp_getconfig(GCFEvent& event, GCFPortInterface &port); + + void rsp_setclock(GCFEvent& event, GCFPortInterface &port); + void rsp_getclock(GCFEvent& event, GCFPortInterface &port); + void rsp_subclock(GCFEvent& event, GCFPortInterface &port); + void rsp_unsubclock(GCFEvent& event, GCFPortInterface &port); + + void rsp_subtdstatus (GCFEvent& event, GCFPortInterface &port); + void rsp_unsubtdstatus(GCFEvent& event, GCFPortInterface &port); + void rsp_gettdstatus (GCFEvent& event, GCFPortInterface &port); + + void rsp_getregisterstate(GCFEvent& event, GCFPortInterface &port); + void rsp_subregisterstate(GCFEvent& event, GCFPortInterface &port); + void rsp_unsubregisterstate(GCFEvent& event, GCFPortInterface &port); + + void rsp_settbb(GCFEvent& event, GCFPortInterface &port); + void rsp_gettbb(GCFEvent& event, GCFPortInterface &port); + + void rsp_setbypass(GCFEvent& event, GCFPortInterface &port); + void rsp_getbypass(GCFEvent& event, GCFPortInterface &port); + + void rsp_getspustatus(GCFEvent& event, GCFPortInterface &port); + + void rsp_setRawBlock(GCFEvent& event, GCFPortInterface &port); + void rsp_getRawBlock(GCFEvent& event, GCFPortInterface &port); + + void rsp_setSplitter(GCFEvent& event, GCFPortInterface &port); + void rsp_getSplitter(GCFEvent& event, GCFPortInterface &port); + /*@}*/ + +private: + // define some constants + // mode of operation + static const int32 MODE_NORMAL = 0; // control all RSPboards + static const int32 MODE_SUBSTATION = 1; // control only one RSPboard + + // Synchronisation mode + static const int32 SYNC_SOFTWARE = 1; // generated by software timer + static const int32 SYNC_FAST = 2; // as fast as possible + static const int32 SYNC_PPS = 3; // PPS on /dev/pps0 + + //# ----- data members ----- + + // ports + GCFTCPPort m_acceptor; // listen for clients on this port + GCFETHRawPort* m_boardPorts; // array of ports, one for each RSP board + std::list<GCFPortInterface*> m_client_list; // list of clients + std::list<GCFPortInterface*> m_dead_clients; // list of clients to cleanup + + Scheduler m_scheduler; + int m_update_counter; // nr of updates completed in one second + int m_n_updates; // number of completed updates + int m_elapsed; // elapsed number of seconds #ifdef HAVE_SYS_TIMEPPS_H - int m_ppsfd; // file descriptor for PPS device - pps_handle_t m_ppshandle; // handle to PPS API interface - pps_info_t m_ppsinfo; // most recent ppsinfo + int m_ppsfd; // file descriptor for PPS device + pps_handle_t m_ppshandle; // handle to PPS API interface + pps_info_t m_ppsinfo; // most recent ppsinfo + int itsPPSdelay; // nr of usec to wait after PPS was received. #endif - }; - - }; }; - + + } // namespace RSP +} // namespace LOFAR + #endif /* RSPDRIVERTASK_H_ */