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