Index: trunk/libffado/src/libieee1394/CycleTimerHelper.cpp =================================================================== --- trunk/libffado/src/libieee1394/CycleTimerHelper.cpp (revision 752) +++ trunk/libffado/src/libieee1394/CycleTimerHelper.cpp (revision 752) @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2005-2007 by Pieter Palmers + * + * This file is part of FFADO + * FFADO = Free Firewire (pro-)audio drivers for linux + * + * FFADO is based upon FreeBoB + * + * 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 3 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, see . + * + */ + +#include "CycleTimerHelper.h" +#include "ieee1394service.h" +#include "libutil/PosixThread.h" + +#define DLL_BANDWIDTH (0.01) +#define DLL_PI (3.141592653589793238) +#define DLL_SQRT2 (1.414213562373095049) +#define DLL_OMEGA (2.0*DLL_PI*DLL_BANDWIDTH) +#define DLL_COEFF_B (DLL_SQRT2 * DLL_OMEGA) +#define DLL_COEFF_C (DLL_OMEGA * DLL_OMEGA) + +IMPL_DEBUG_MODULE( CycleTimerHelper, CycleTimerHelper, DEBUG_LEVEL_NORMAL ); + +CycleTimerHelper::CycleTimerHelper(Ieee1394Service &parent, unsigned int update_period_us) + : m_Parent ( parent ) + , m_ticks_per_update ( ((uint64_t)TICKS_PER_SECOND) * ((uint64_t)update_period_us) / 1000000ULL ) + , m_usecs_per_update ( update_period_us ) + , m_avg_wakeup_delay ( 0.0 ) + , m_dll_e2 ( 0.0 ) + , m_current_time_usecs ( 0 ) + , m_next_time_usecs ( 0 ) + , m_current_time_ticks ( 0 ) + , m_next_time_ticks ( 0 ) + , m_first_run ( true ) + , m_Thread ( NULL ) + , m_realtime ( false ) + , m_priority ( 0 ) +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Create %p...\n", this); +} + +CycleTimerHelper::CycleTimerHelper(Ieee1394Service &parent, unsigned int update_period_us, bool rt, int prio) + : m_Parent ( parent ) + , m_ticks_per_update ( ((uint64_t)TICKS_PER_SECOND) * ((uint64_t)update_period_us) / 1000000ULL ) + , m_usecs_per_update ( update_period_us ) + , m_avg_wakeup_delay ( 0.0 ) + , m_dll_e2 ( 0.0 ) + , m_current_time_usecs ( 0 ) + , m_next_time_usecs ( 0 ) + , m_current_time_ticks ( 0 ) + , m_next_time_ticks ( 0 ) + , m_first_run ( true ) + , m_Thread ( NULL ) + , m_realtime ( rt ) + , m_priority ( prio ) +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Create %p...\n", this); +} + +CycleTimerHelper::~CycleTimerHelper() +{ + if (m_Thread) { + m_Thread->Stop(); + delete m_Thread; + } +} + +bool +CycleTimerHelper::Start() +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Start %p...\n", this); + m_Thread = new Util::PosixThread(this, m_realtime, m_priority, + PTHREAD_CANCEL_DEFERRED); + if(!m_Thread) { + debugFatal("Could not create update thread\n"); + } + if(!m_Thread) { + debugFatal("No thread\n"); + return false; + } + if (m_Thread->Start() != 0) { + debugFatal("Could not start update thread\n"); + return false; + } + return true; +} + +bool +CycleTimerHelper::Init() +{ + debugOutput( DEBUG_LEVEL_VERBOSE, "Initialize %p...\n", this); + pthread_mutex_init(&m_compute_vars_lock, NULL); + return true; +} + +bool +CycleTimerHelper::setThreadParameters(bool rt, int priority) { + debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) (rt=%d, prio=%d)...\n", this, rt, priority); + if (priority > 98) priority = 98; // cap the priority + m_realtime = rt; + m_priority = priority; + + if (m_Thread) { + if (m_realtime) { + m_Thread->AcquireRealTime(m_priority); + } else { + m_Thread->DropRealTime(); + } + } + return true; +} + +float +CycleTimerHelper::getRate() +{ + float rate = (float)(diffTicks((uint64_t)m_next_time_ticks, (uint64_t)m_current_time_ticks)); + rate /= (float)(m_next_time_usecs - m_current_time_usecs); + return rate; +} + +float +CycleTimerHelper::getNominalRate() +{ + float rate = ((double)TICKS_PER_SECOND) / 1000000.0; + return rate; +} + +bool +CycleTimerHelper::Execute() +{ + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "Execute %p...\n", this); + uint32_t cycle_timer; + uint64_t local_time; + if(!m_Parent.readCycleTimerReg(&cycle_timer, &local_time)) { + debugError("Could not read cycle timer register\n"); + return false; + } + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, " read : CTR: %11lu, local: %17llu\n", + cycle_timer, local_time); + + double usecs_late; + if (m_first_run) { + usecs_late = 0.0; + m_dll_e2 = m_ticks_per_update; + m_current_time_usecs = local_time; + m_next_time_usecs = m_current_time_usecs + m_usecs_per_update; + m_current_time_ticks = CYCLE_TIMER_TO_TICKS( cycle_timer ); + m_next_time_ticks = addTicks( (uint64_t)m_current_time_ticks, (uint64_t)m_dll_e2); + debugOutput( DEBUG_LEVEL_VERBOSE, " First run\n"); + debugOutput( DEBUG_LEVEL_VERBOSE, " usecs/update: %lu, ticks/update: %lu, m_dll_e2: %f\n", + m_usecs_per_update, m_ticks_per_update, m_dll_e2); + debugOutput( DEBUG_LEVEL_VERBOSE, " usecs current: %f, next: %f\n", m_current_time_usecs, m_next_time_usecs); + debugOutput( DEBUG_LEVEL_VERBOSE, " ticks current: %f, next: %f\n", m_current_time_ticks, m_next_time_ticks); + m_first_run = false; + } else { + + double diff = m_next_time_usecs - m_current_time_usecs; + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, " usecs: local: %11llu current: %f next: %f, diff: %f\n", + local_time, m_current_time_usecs, m_next_time_usecs, diff); + + uint64_t cycle_timer_ticks = CYCLE_TIMER_TO_TICKS(cycle_timer); + usecs_late = ((double)local_time) - (m_next_time_usecs); + + // we update the x-axis values + m_current_time_usecs = m_next_time_usecs; + m_next_time_usecs = (local_time - usecs_late) + m_usecs_per_update; + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, " usecs: current: %f next: %f usecs_late=%f\n", + m_current_time_usecs, m_next_time_usecs, usecs_late); + + // and the y-axis values + double diff_ticks = diffTicks(cycle_timer_ticks, (int64_t)m_next_time_ticks); + m_current_time_ticks = m_next_time_ticks; + m_next_time_ticks = addTicks((uint64_t)m_current_time_ticks, + (uint64_t)((DLL_COEFF_B * diff_ticks) + m_dll_e2)); + m_dll_e2 += DLL_COEFF_C * diff_ticks; + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, " ticks: current: %f next: %f diff=%f\n", + m_current_time_ticks, m_next_time_ticks, diff_ticks); + + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, " state: local: %11llu, dll_e2: %f, rate: %f\n", + local_time, m_dll_e2, getRate()); + } + + // track the average wakeup delay + m_avg_wakeup_delay += 0.01 * usecs_late; + + // FIXME: priority inversion! + pthread_mutex_lock(&m_compute_vars_lock); + m_current_vars.ticks = m_current_time_ticks; + m_current_vars.usecs = m_current_time_usecs; + m_current_vars.rate = getRate(); + pthread_mutex_unlock(&m_compute_vars_lock); + + // wait for the next update period + int64_t time_to_sleep = (int64_t)m_next_time_usecs - m_Parent.getCurrentTimeAsUsecs(); + time_to_sleep -= (int64_t)m_avg_wakeup_delay; + //int64_t time_to_sleep = m_usecs_per_update; + if (time_to_sleep > 0) { + debugOutput( DEBUG_LEVEL_VERY_VERBOSE, " sleeping %lld usecs (avg delay: %f)\n", time_to_sleep, m_avg_wakeup_delay); + usleep(time_to_sleep); + } + return true; +} + +uint32_t +CycleTimerHelper::getCycleTimerTicks() +{ + uint64_t now = m_Parent.getCurrentTimeAsUsecs(); + return getCycleTimerTicks(now); +} + +uint32_t +CycleTimerHelper::getCycleTimerTicks(uint64_t now) +{ + uint32_t retval; + struct compute_vars my_vars; + + // reduce lock contention + pthread_mutex_lock(&m_compute_vars_lock); + my_vars = m_current_vars; + pthread_mutex_unlock(&m_compute_vars_lock); + + double time_diff = now - my_vars.usecs; + double y_step_in_ticks = time_diff * my_vars.rate; + int64_t y_step_in_ticks_int = (int64_t)y_step_in_ticks; + uint64_t offset_in_ticks_int = (uint64_t)my_vars.ticks; + + if (y_step_in_ticks_int > 0) { + retval = addTicks(offset_in_ticks_int, y_step_in_ticks_int); + } else { + debugWarning("y_step_in_ticks_int <= 0: %lld\n", y_step_in_ticks_int); + retval = substractTicks(offset_in_ticks_int, -y_step_in_ticks_int); + } + + return retval; +} + +uint32_t +CycleTimerHelper::getCycleTimer() +{ + return TICKS_TO_CYCLE_TIMER(getCycleTimerTicks()); +} + +uint32_t +CycleTimerHelper::getCycleTimer(uint64_t now) +{ + return TICKS_TO_CYCLE_TIMER(getCycleTimerTicks(now)); +} + +void +CycleTimerHelper::setVerboseLevel(int l) +{ + setDebugLevel(l); +} Index: trunk/libffado/src/libieee1394/CycleTimerHelper.h =================================================================== --- trunk/libffado/src/libieee1394/CycleTimerHelper.h (revision 752) +++ trunk/libffado/src/libieee1394/CycleTimerHelper.h (revision 752) @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2005-2007 by Pieter Palmers + * + * This file is part of FFADO + * FFADO = Free Firewire (pro-)audio drivers for linux + * + * FFADO is based upon FreeBoB + * + * 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 3 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, see . + * + */ + +#include "libutil/Thread.h" +#include "cycletimer.h" + +/** + * Implements a DLL based mechanism to track the cycle timer + * register of the Ieee1394Service pointed to by the 'parent'. + * + * A DLL mechanism is performance-wise better suited, since it + * does not require an OS call. Hence we run a thread to update + * the DLL at regular time intervals, and then use the DLL to + * generate a cycle timer estimate for the parent to pass on + * to it's clients. + * + * The idea is to make reading the cycle timer real-time safe, + * which isn't (necessarily)the case for the direct raw1394 call, + * since it's a kernel call that could block (although the current + * implementation is RT safe). + * + * This also allows us to run on systems not having the + * raw1394_read_cycle_timer kernel call. We can always do a normal + * read of our own cycle timer register, but that's not very accurate. + * The accuracy is improved by this DLL mechanism. Still not as good + * as when using the raw1394_read_cycle_timer call, but anyway. + * + * On the long run this code will also allow us to map system time + * on to 1394 time for the current host controller, hence enabling + * different clock domains to operate together. + */ +#ifndef __CYCLETIMERTHREAD_H__ +#define __CYCLETIMERTHREAD_H__ + +#include "debugmodule/debugmodule.h" + +class Ieee1394Service; +namespace Util { + class TimeSource; + class Thread; +} + +class CycleTimerHelper : public Util::RunnableInterface +{ +public: + CycleTimerHelper(Ieee1394Service &, unsigned int); + CycleTimerHelper(Ieee1394Service &, unsigned int, bool rt, int prio); + ~CycleTimerHelper(); + + virtual bool Init(); + virtual bool Execute(); + + bool setThreadParameters(bool rt, int priority); + bool Start(); + + /** + * @brief get the current cycle timer value (in ticks) + * @note thread safe + */ + uint32_t getCycleTimerTicks(); + + /** + * @brief get the cycle timer value for a specific time instant (in ticks) + * @note thread safe + */ + uint32_t getCycleTimerTicks(uint64_t now); + + /** + * @brief get the current cycle timer value (in CTR format) + * @note thread safe + */ + uint32_t getCycleTimer(); + + /** + * @brief get the cycle timer value for a specific time instant (in CTR format) + * @note thread safe + */ + uint32_t getCycleTimer(uint64_t now); + + float getRate(); + float getNominalRate(); + + void setVerboseLevel(int l); + +private: + Ieee1394Service &m_Parent; + // parameters + uint32_t m_ticks_per_update; + uint32_t m_usecs_per_update; + + float m_avg_wakeup_delay; + + // state variables + double m_dll_e2; + + double m_current_time_usecs; + double m_next_time_usecs; + double m_current_time_ticks; + double m_next_time_ticks; + bool m_first_run; + + // cached vars used for computation + struct compute_vars { + double usecs; + double ticks; + double rate; + }; + + struct compute_vars m_current_vars; + pthread_mutex_t m_compute_vars_lock; + + // Threading + Util::Thread * m_Thread; + bool m_realtime; + unsigned int m_priority; + + // debug stuff + DECLARE_DEBUG_MODULE; +}; +#endif Index: trunk/libffado/src/libieee1394/ieee1394service.cpp =================================================================== --- trunk/libffado/src/libieee1394/ieee1394service.cpp (revision 750) +++ trunk/libffado/src/libieee1394/ieee1394service.cpp (revision 752) @@ -27,4 +27,5 @@ #include "cycletimer.h" #include "IsoHandlerManager.h" +#include "CycleTimerHelper.h" #include @@ -32,4 +33,6 @@ #include +#include "libutil/SystemTimeSource.h" + #include #include @@ -42,11 +45,19 @@ #define FFADO_MAX_FIREWIRE_PORTS 16 +#define ISOMANAGER_PRIO_INCREASE 5 +#define CYCLETIMER_HELPER_PRIO_INCREASE 6 + IMPL_DEBUG_MODULE( Ieee1394Service, Ieee1394Service, DEBUG_LEVEL_NORMAL ); Ieee1394Service::Ieee1394Service() - : m_handle( 0 ), m_resetHandle( 0 ), m_rtHandle( 0 ) + : m_handle( 0 ), m_resetHandle( 0 ), m_util_handle( 0 ) , m_port( -1 ) , m_threadRunning( false ) - , m_isoManager( new IsoHandlerManager( *this ) ) + , m_realtime ( false ) + , m_base_priority ( 0 ) + , m_pIsoManager( new IsoHandlerManager( *this ) ) + , m_pCTRHelper ( new CycleTimerHelper( *this, 1000 ) ) + , m_have_new_ctr_read ( false ) + , m_pTimeSource ( new Util::SystemTimeSource() ) { pthread_mutex_init( &m_mutex, 0 ); @@ -63,7 +74,33 @@ } +Ieee1394Service::Ieee1394Service(bool rt, int prio) + : m_handle( 0 ), m_resetHandle( 0 ), m_util_handle( 0 ) + , m_port( -1 ) + , m_threadRunning( false ) + , m_realtime ( rt ) + , m_base_priority ( prio ) + , m_pIsoManager( new IsoHandlerManager( *this, rt, prio + ISOMANAGER_PRIO_INCREASE ) ) + , m_pCTRHelper ( new CycleTimerHelper( *this, 1000, rt, prio + CYCLETIMER_HELPER_PRIO_INCREASE ) ) + , m_have_new_ctr_read ( false ) + , m_pTimeSource ( new Util::SystemTimeSource() ) +{ + pthread_mutex_init( &m_mutex, 0 ); + + for (unsigned int i=0; i<64; i++) { + m_channels[i].channel=-1; + m_channels[i].bandwidth=-1; + m_channels[i].alloctype=AllocFree; + m_channels[i].xmit_node=0xFFFF; + m_channels[i].xmit_plug=-1; + m_channels[i].recv_node=0xFFFF; + m_channels[i].recv_plug=-1; + } +} + Ieee1394Service::~Ieee1394Service() { - delete m_isoManager; + delete m_pCTRHelper; + delete m_pIsoManager; + delete m_pTimeSource; stopRHThread(); for ( arm_handler_vec_t::iterator it = m_armHandlers.begin(); @@ -85,6 +122,6 @@ raw1394_destroy_handle( m_resetHandle ); } - if ( m_rtHandle ) { - raw1394_destroy_handle( m_rtHandle ); + if ( m_util_handle ) { + raw1394_destroy_handle( m_util_handle ); } } @@ -137,7 +174,7 @@ return false; } - - m_rtHandle = raw1394_new_handle_on_port( port ); - if ( !m_rtHandle ) { + + m_util_handle = raw1394_new_handle_on_port( port ); + if ( !m_util_handle ) { if ( !errno ) { debugFatal("libraw1394 not compatible\n"); @@ -156,8 +193,16 @@ err=raw1394_read_cycle_timer(m_handle, &cycle_timer, &local_time); if(err) { - debugError("raw1394_read_cycle_timer failed.\n"); - debugError(" Error: %s\n", strerror(err)); - debugError(" Your system doesn't seem to support the raw1394_read_cycle_timer call\n"); - return false; + debugOutput(DEBUG_LEVEL_VERBOSE, "raw1394_read_cycle_timer failed.\n"); + debugOutput(DEBUG_LEVEL_VERBOSE, " Error descr: %s\n", strerror(err)); + debugWarning("==================================================================\n"); + debugWarning(" This system doesn't support the raw1394_read_cycle_timer call. \n"); + debugWarning(" Fallback to indirect CTR read method. \n"); + debugWarning(" FFADO should work, but achieving low-latency might be a problem. \n"); + debugWarning(" Upgrade the kernel to version 2.6.21 or higher to solve this. \n"); + debugWarning("==================================================================\n"); + m_have_new_ctr_read = false; + } else { + debugOutput(DEBUG_LEVEL_NORMAL, "This system supports the raw1394_read_cycle_timer call, using it.\n"); + m_have_new_ctr_read = true; } @@ -190,5 +235,5 @@ raw1394_set_userdata( m_handle, this ); raw1394_set_userdata( m_resetHandle, this ); - raw1394_set_userdata( m_rtHandle, this ); + raw1394_set_userdata( m_util_handle, this ); raw1394_set_bus_reset_handler( m_resetHandle, this->resetHandlerLowLevel ); @@ -197,10 +242,20 @@ this->armHandlerLowLevel ); - if(!m_isoManager) { + if(!m_pCTRHelper) { + debugFatal("No CycleTimerHelper available, bad!\n"); + return false; + } + m_pCTRHelper->setVerboseLevel(getDebugLevel()); + if(!m_pCTRHelper->Start()) { + debugFatal("Could not start CycleTimerHelper\n"); + return false; + } + + if(!m_pIsoManager) { debugFatal("No IsoHandlerManager available, bad!\n"); return false; } - m_isoManager->setVerboseLevel(getDebugLevel()); - if(!m_isoManager->init()) { + m_pIsoManager->setVerboseLevel(getDebugLevel()); + if(!m_pIsoManager->init()) { debugFatal("Could not initialize IsoHandlerManager\n"); return false; @@ -208,4 +263,10 @@ startRHThread(); + + // make sure that the thread parameters of all our helper threads are OK + if(!setThreadParameters(m_realtime, m_base_priority)) { + debugFatal("Could not set thread parameters\n"); + return false; + } return true; } @@ -213,9 +274,17 @@ bool Ieee1394Service::setThreadParameters(bool rt, int priority) { - if (m_isoManager) { - return m_isoManager->setThreadParameters(rt, priority); + if (priority > 98) priority = 98; + m_base_priority = priority; + m_realtime = rt; + if (m_pIsoManager) { + return m_pIsoManager->setThreadParameters(rt, priority + ISOMANAGER_PRIO_INCREASE); } else { return true; } + if (m_pCTRHelper) { + return m_pCTRHelper->setThreadParameters(rt, priority + CYCLETIMER_HELPER_PRIO_INCREASE); + } else { + return true; + } } @@ -236,18 +305,7 @@ */ -unsigned int +uint32_t Ieee1394Service::getCycleTimerTicks() { - // the new api should be realtime safe. - // it might cause a reschedule when turning preemption, - // back on but that won't hurt us if we have sufficient - // priority - int err; - uint32_t cycle_timer; - uint64_t local_time; - err=raw1394_read_cycle_timer(m_rtHandle, &cycle_timer, &local_time); - if(err) { - debugWarning("raw1394_read_cycle_timer: %s\n", strerror(err)); - } - return CYCLE_TIMER_TO_TICKS(cycle_timer); + return m_pCTRHelper->getCycleTimerTicks(); } @@ -258,5 +316,5 @@ */ -unsigned int +uint32_t Ieee1394Service::getCycleTimer() { // the new api should be realtime safe. @@ -267,9 +325,43 @@ uint32_t cycle_timer; uint64_t local_time; - err=raw1394_read_cycle_timer(m_rtHandle, &cycle_timer, &local_time); + err=raw1394_read_cycle_timer(m_util_handle, &cycle_timer, &local_time); if(err) { debugWarning("raw1394_read_cycle_timer: %s\n", strerror(err)); } return cycle_timer; +} + +bool +Ieee1394Service::readCycleTimerReg(uint32_t *cycle_timer, uint64_t *local_time) +{ + if(m_have_new_ctr_read) { + int err; + err = raw1394_read_cycle_timer(m_util_handle, cycle_timer, local_time); + if(err) { + debugWarning("raw1394_read_cycle_timer: %s\n", strerror(err)); + return false; + } + return true; + } else { + // do a normal read of the CTR register + // the disadvantage is that local_time and cycle time are not + // read at the same time instant (scheduling issues) + *local_time = getCurrentTimeAsUsecs(); + if ( raw1394_read( m_util_handle, + getLocalNodeId() | 0xFFC0, + CSR_REGISTER_BASE | CSR_CYCLE_TIME, + sizeof(uint32_t), cycle_timer ) == 0 ) { + *cycle_timer = ntohl(*cycle_timer); + return true; + } else { + return false; + } + } +} + +uint64_t +Ieee1394Service::getCurrentTimeAsUsecs() { + assert(m_pTimeSource); + return m_pTimeSource->getCurrentTimeAsUsecs(); } @@ -501,5 +593,5 @@ // do a simple read on ourself in order to update the internal structures // this avoids failures after a bus reset - read_quadlet( getLocalNodeId() & 0xFFC0, + read_quadlet( getLocalNodeId() | 0xFFC0, CSR_REGISTER_BASE | CSR_CYCLE_TIME, &buf ); @@ -974,5 +1066,6 @@ Ieee1394Service::setVerboseLevel(int l) { - if (m_isoManager) m_isoManager->setVerboseLevel(l); + if (m_pIsoManager) m_pIsoManager->setVerboseLevel(l); + if (m_pCTRHelper) m_pCTRHelper->setVerboseLevel(l); setDebugLevel(l); debugOutput( DEBUG_LEVEL_VERBOSE, "Setting verbose level to %d...\n", l ); @@ -985,4 +1078,4 @@ debugOutput( DEBUG_LEVEL_VERBOSE, " Name: %s\n", getPortName().c_str() ); debugOutputShort( DEBUG_LEVEL_NORMAL, "Iso handler info:\n"); - if (m_isoManager) m_isoManager->dumpInfo(); -} + if (m_pIsoManager) m_pIsoManager->dumpInfo(); +} Index: trunk/libffado/src/libieee1394/ieee1394service.h =================================================================== --- trunk/libffado/src/libieee1394/ieee1394service.h (revision 750) +++ trunk/libffado/src/libieee1394/ieee1394service.h (revision 752) @@ -41,8 +41,14 @@ class ARMHandler; class IsoHandlerManager; +class CycleTimerHelper; + +namespace Util { + class TimeSource; +} class Ieee1394Service : public IEC61883 { public: Ieee1394Service(); + Ieee1394Service(bool rt, int prio); ~Ieee1394Service(); @@ -94,22 +100,46 @@ nodeid_t getLocalNodeId(); - /// get the most recent cycle timer value (in ticks) - unsigned int getCycleTimerTicks(); - /// get the most recent cycle timer value (as is) - unsigned int getCycleTimer(); - - - /** - * @brief send async read request to a node and wait for response. - * - * This does the complete transaction and will return when it's finished. - * - * @param node target node (\todo needs 0xffc0 stuff) - * @param addr address to read from - * @param length amount of data to read in quadlets - * @param buffer pointer to buffer where data will be saved - - * @return true on success or false on failure (sets errno) - */ + /** + * @brief get the most recent cycle timer value (in ticks) + * + * @note Uses the most appropriate method for getting the cycle timer + * which is not necessarily a direct read (could be DLL) + */ + uint32_t getCycleTimerTicks(); + + /** + * @brief get the most recent cycle timer value (in CTR format) + * + * @note Uses the most appropriate method for getting the cycle timer + * which is not necessarily a direct read (could be DLL) + */ + uint32_t getCycleTimer(); + + /** + * @brief read the cycle timer value from the controller (in CTR format) + * + * @note Uses a direct method to read the value from the controller + * @return true if successful + */ + bool readCycleTimerReg(uint32_t *cycle_timer, uint64_t *local_time); + + /** + * @brief provide the current system time + * @return + */ + uint64_t getCurrentTimeAsUsecs(); + + /** + * @brief send async read request to a node and wait for response. + * + * This does the complete transaction and will return when it's finished. + * + * @param node target node (\todo needs 0xffc0 stuff) + * @param addr address to read from + * @param length amount of data to read in quadlets + * @param buffer pointer to buffer where data will be saved + * + * @return true on success or false on failure (sets errno) + */ bool read( fb_nodeid_t nodeId, fb_nodeaddr_t addr, @@ -221,5 +251,5 @@ bool freeIsoChannel(signed int channel); - IsoHandlerManager& getIsoHandlerManager() {return *m_isoManager;}; + IsoHandlerManager& getIsoHandlerManager() {return *m_pIsoManager;}; private: enum EAllocType { @@ -267,5 +297,5 @@ raw1394handle_t m_handle; raw1394handle_t m_resetHandle; - raw1394handle_t m_rtHandle; // a handle for operations from the rt thread + raw1394handle_t m_util_handle; // a handle for operations from the rt thread int m_port; std::string m_portName; @@ -275,5 +305,13 @@ bool m_threadRunning; - IsoHandlerManager* m_isoManager; + bool m_realtime; + int m_base_priority; + + IsoHandlerManager* m_pIsoManager; + CycleTimerHelper* m_pCTRHelper; + bool m_have_new_ctr_read; + + // the time source + Util::TimeSource* m_pTimeSource; typedef std::vector< Functor* > reset_handler_vec_t; Index: trunk/libffado/src/libieee1394/IsoHandlerManager.cpp =================================================================== --- trunk/libffado/src/libieee1394/IsoHandlerManager.cpp (revision 750) +++ trunk/libffado/src/libieee1394/IsoHandlerManager.cpp (revision 752) @@ -35,6 +35,4 @@ #define PACKETS_PER_INTERRUPT 4U -#define FFADO_ISOHANDLERMANAGER_PRIORITY_INCREASE 7 - IMPL_DEBUG_MODULE( IsoHandlerManager, IsoHandlerManager, DEBUG_LEVEL_NORMAL ); @@ -45,12 +43,12 @@ , m_service( service ) , m_poll_timeout(100), m_poll_nfds_shadow(0) - , m_realtime(false), m_priority(0), m_xmit_nb_frames( 20 ) + , m_realtime(false), m_priority(0), m_isoManagerThread ( NULL ) {} -IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service, bool run_rt, unsigned int rt_prio) +IsoHandlerManager::IsoHandlerManager(Ieee1394Service& service, bool run_rt, int rt_prio) : m_State(E_Created) , m_service( service ) , m_poll_timeout(100), m_poll_nfds_shadow(0) - , m_realtime(run_rt), m_priority(rt_prio), m_xmit_nb_frames( 20 ) + , m_realtime(run_rt), m_priority(rt_prio), m_isoManagerThread ( NULL ) {} @@ -62,15 +60,15 @@ bool IsoHandlerManager::setThreadParameters(bool rt, int priority) { + if (priority > 98) priority = 98; // cap the priority + m_realtime = rt; + m_priority = priority; + if (m_isoManagerThread) { if (rt) { - unsigned int prio = priority + FFADO_ISOHANDLERMANAGER_PRIORITY_INCREASE; - if (prio > 98) prio = 98; - m_isoManagerThread->AcquireRealTime(prio); + m_isoManagerThread->AcquireRealTime(m_priority); } else { m_isoManagerThread->DropRealTime(); } } - m_realtime = rt; - m_priority = priority; return true; } @@ -87,11 +85,8 @@ // the tread that performs the actual packet transfer // needs high priority - unsigned int prio = m_priority + FFADO_ISOHANDLERMANAGER_PRIORITY_INCREASE; - debugOutput( DEBUG_LEVEL_VERBOSE, " thread should have prio %d, base is %d...\n", prio, m_priority); - - if (prio > 98) prio = 98; + if (m_priority > 98) m_priority = 98; m_isoManagerThread = new Util::PosixThread( this, - m_realtime, prio, + m_realtime, m_priority, PTHREAD_CANCEL_DEFERRED); @@ -183,5 +178,5 @@ { int err; - int i; + unsigned int i; // update the shadow variables if requested @@ -269,5 +264,4 @@ IsoHandlerManager::requestShadowUpdate() { debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); - int i; if (m_isoManagerThread == NULL) { @@ -757,5 +751,4 @@ } - void IsoHandlerManager::setVerboseLevel(int i) { setDebugLevel(i); Index: trunk/libffado/src/libieee1394/IsoHandlerManager.h =================================================================== --- trunk/libffado/src/libieee1394/IsoHandlerManager.h (revision 750) +++ trunk/libffado/src/libieee1394/IsoHandlerManager.h (revision 752) @@ -73,5 +73,5 @@ IsoHandlerManager(Ieee1394Service& service); - IsoHandlerManager(Ieee1394Service& service, bool run_rt, unsigned int rt_prio); + IsoHandlerManager(Ieee1394Service& service, bool run_rt, int rt_prio); virtual ~IsoHandlerManager(); @@ -80,7 +80,4 @@ void setPollTimeout(int t) {m_poll_timeout=t;}; ///< set the timeout used for poll() int getPollTimeout() {return m_poll_timeout;}; ///< get the timeout used for poll() - - void setTransmitBufferNbFrames(unsigned int t) {m_xmit_nb_frames = t;}; - int getTransmitBufferNbFrames() {return m_xmit_nb_frames;}; void setVerboseLevel(int l); ///< set the verbose level @@ -177,9 +174,6 @@ // threading bool m_realtime; - unsigned int m_priority; + int m_priority; Util::PosixThread *m_isoManagerThread; - - // the preferred number of packets to buffer on xmit - unsigned int m_xmit_nb_frames; // debug stuff