1 |
/* $Id$ */ |
---|
2 |
|
---|
3 |
/* |
---|
4 |
* FreeBob Streaming API |
---|
5 |
* FreeBob = Firewire (pro-)audio for linux |
---|
6 |
* |
---|
7 |
* http://freebob.sf.net |
---|
8 |
* |
---|
9 |
* Copyright (C) 2006 Pieter Palmers <pieterpalmers@users.sourceforge.net> |
---|
10 |
* |
---|
11 |
* This program is free software {} you can redistribute it and/or modify |
---|
12 |
* it under the terms of the GNU General Public License as published by |
---|
13 |
* the Free Software Foundation {} either version 2 of the License, or |
---|
14 |
* (at your option) any later version. |
---|
15 |
* |
---|
16 |
* This program is distributed in the hope that it will be useful, |
---|
17 |
* but WITHOUT ANY WARRANTY {} without even the implied warranty of |
---|
18 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
19 |
* GNU General Public License for more details. |
---|
20 |
* |
---|
21 |
* You should have received a copy of the GNU General Public License |
---|
22 |
* along with this program {} if not, write to the Free Software |
---|
23 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
24 |
* |
---|
25 |
* |
---|
26 |
* |
---|
27 |
*/ |
---|
28 |
|
---|
29 |
#include "IsoHandler.h" |
---|
30 |
#include "IsoStream.h" |
---|
31 |
#include "cycletimer.h" |
---|
32 |
|
---|
33 |
#include "libutil/TimeSource.h" |
---|
34 |
#include "libutil/SystemTimeSource.h" |
---|
35 |
|
---|
36 |
#include <errno.h> |
---|
37 |
#include <netinet/in.h> |
---|
38 |
#include <assert.h> |
---|
39 |
#include <unistd.h> |
---|
40 |
#include <string.h> |
---|
41 |
|
---|
42 |
#include <iostream> |
---|
43 |
using namespace std; |
---|
44 |
|
---|
45 |
#define CC_SLEEP_TIME_AFTER_UPDATE 1000 |
---|
46 |
#define CC_SLEEP_TIME_AFTER_FAILURE 10 |
---|
47 |
#define CC_DLL_COEFF ((0.001)*((float)(CC_SLEEP_TIME_AFTER_UPDATE/1000.0))) |
---|
48 |
|
---|
49 |
#define CC_MAX_RATE_ERROR (2.0/100.0) |
---|
50 |
#define CC_INIT_MAX_TRIES 10 |
---|
51 |
|
---|
52 |
|
---|
53 |
namespace FreebobStreaming |
---|
54 |
{ |
---|
55 |
|
---|
56 |
IMPL_DEBUG_MODULE( IsoHandler, IsoHandler, DEBUG_LEVEL_NORMAL ); |
---|
57 |
|
---|
58 |
/* the C callbacks */ |
---|
59 |
enum raw1394_iso_disposition |
---|
60 |
IsoXmitHandler::iso_transmit_handler(raw1394handle_t handle, |
---|
61 |
unsigned char *data, unsigned int *length, |
---|
62 |
unsigned char *tag, unsigned char *sy, |
---|
63 |
int cycle, unsigned int dropped) { |
---|
64 |
|
---|
65 |
IsoXmitHandler *xmitHandler=static_cast<IsoXmitHandler *>(raw1394_get_userdata(handle)); |
---|
66 |
assert(xmitHandler); |
---|
67 |
|
---|
68 |
return xmitHandler->getPacket(data, length, tag, sy, cycle, dropped); |
---|
69 |
} |
---|
70 |
|
---|
71 |
enum raw1394_iso_disposition |
---|
72 |
IsoRecvHandler::iso_receive_handler(raw1394handle_t handle, unsigned char *data, |
---|
73 |
unsigned int length, unsigned char channel, |
---|
74 |
unsigned char tag, unsigned char sy, unsigned int cycle, |
---|
75 |
unsigned int dropped) { |
---|
76 |
|
---|
77 |
IsoRecvHandler *recvHandler=static_cast<IsoRecvHandler *>(raw1394_get_userdata(handle)); |
---|
78 |
assert(recvHandler); |
---|
79 |
|
---|
80 |
return recvHandler->putPacket(data, length, channel, tag, sy, cycle, dropped); |
---|
81 |
} |
---|
82 |
|
---|
83 |
int IsoHandler::busreset_handler(raw1394handle_t handle, unsigned int generation) |
---|
84 |
{ |
---|
85 |
debugOutput( DEBUG_LEVEL_VERBOSE, "Busreset happened, generation %d...\n", generation); |
---|
86 |
|
---|
87 |
IsoHandler *handler=static_cast<IsoHandler *>(raw1394_get_userdata(handle)); |
---|
88 |
assert(handler); |
---|
89 |
return handler->handleBusReset(generation); |
---|
90 |
} |
---|
91 |
|
---|
92 |
|
---|
93 |
/* Base class implementation */ |
---|
94 |
IsoHandler::IsoHandler(int port) |
---|
95 |
: TimeSource(), m_handle(0), m_handle_util(0), m_port(port), |
---|
96 |
m_buf_packets(400), m_max_packet_size(1024), m_irq_interval(-1), |
---|
97 |
m_cycletimer_ticks(0), m_lastmeas_usecs(0), m_ticks_per_usec(24.576), |
---|
98 |
m_ticks_per_usec_dll_err2(0), |
---|
99 |
m_packetcount(0), m_dropped(0), m_Client(0), |
---|
100 |
m_State(E_Created), m_TimeSource_LastSecs(0),m_TimeSource_NbCycleWraps(0) |
---|
101 |
{ |
---|
102 |
m_TimeSource=new FreebobUtil::SystemTimeSource(); |
---|
103 |
} |
---|
104 |
|
---|
105 |
IsoHandler::IsoHandler(int port, unsigned int buf_packets, unsigned int max_packet_size, int irq) |
---|
106 |
: TimeSource(), m_handle(0), m_port(port), |
---|
107 |
m_buf_packets(buf_packets), m_max_packet_size( max_packet_size), |
---|
108 |
m_irq_interval(irq), |
---|
109 |
m_cycletimer_ticks(0), m_lastmeas_usecs(0), m_ticks_per_usec(24.576), |
---|
110 |
m_ticks_per_usec_dll_err2(0), |
---|
111 |
m_packetcount(0), m_dropped(0), m_Client(0), |
---|
112 |
m_State(E_Created), m_TimeSource_LastSecs(0),m_TimeSource_NbCycleWraps(0) |
---|
113 |
{ |
---|
114 |
m_TimeSource=new FreebobUtil::SystemTimeSource(); |
---|
115 |
} |
---|
116 |
|
---|
117 |
IsoHandler::~IsoHandler() { |
---|
118 |
|
---|
119 |
// Don't call until libraw1394's raw1394_new_handle() function has been |
---|
120 |
// fixed to correctly initialise the iso_packet_infos field. Bug is |
---|
121 |
// confirmed present in libraw1394 1.2.1. In any case, |
---|
122 |
// raw1394_destroy_handle() will do any iso system shutdown required. |
---|
123 |
// raw1394_iso_shutdown(m_handle); |
---|
124 |
|
---|
125 |
if(m_handle) { |
---|
126 |
if (m_State == E_Running) { |
---|
127 |
stop(); |
---|
128 |
} |
---|
129 |
|
---|
130 |
raw1394_destroy_handle(m_handle); |
---|
131 |
} |
---|
132 |
|
---|
133 |
if(m_handle_util) raw1394_destroy_handle(m_handle_util); |
---|
134 |
|
---|
135 |
if (m_TimeSource) delete m_TimeSource; |
---|
136 |
} |
---|
137 |
|
---|
138 |
bool |
---|
139 |
IsoHandler::init() |
---|
140 |
{ |
---|
141 |
debugOutput( DEBUG_LEVEL_VERBOSE, "IsoHandler (%p) enter...\n",this); |
---|
142 |
|
---|
143 |
// check the state |
---|
144 |
if(m_State != E_Created) { |
---|
145 |
debugError("Incorrect state, expected E_Created, got %d\n",(int)m_State); |
---|
146 |
return false; |
---|
147 |
} |
---|
148 |
|
---|
149 |
// the main handle for the ISO traffic |
---|
150 |
m_handle = raw1394_new_handle_on_port( m_port ); |
---|
151 |
if ( !m_handle ) { |
---|
152 |
if ( !errno ) { |
---|
153 |
debugError("libraw1394 not compatible\n"); |
---|
154 |
} else { |
---|
155 |
debugError("Could not get 1394 handle: %s", strerror(errno) ); |
---|
156 |
debugError("Are ieee1394 and raw1394 drivers loaded?"); |
---|
157 |
} |
---|
158 |
return false; |
---|
159 |
} |
---|
160 |
raw1394_set_userdata(m_handle, static_cast<void *>(this)); |
---|
161 |
|
---|
162 |
// a second handle for utility stuff |
---|
163 |
m_handle_util = raw1394_new_handle_on_port( m_port ); |
---|
164 |
if ( !m_handle_util ) { |
---|
165 |
if ( !errno ) { |
---|
166 |
debugError("libraw1394 not compatible\n"); |
---|
167 |
} else { |
---|
168 |
debugError("Could not get 1394 handle: %s", strerror(errno) ); |
---|
169 |
debugError("Are ieee1394 and raw1394 drivers loaded?"); |
---|
170 |
} |
---|
171 |
|
---|
172 |
raw1394_destroy_handle(m_handle); |
---|
173 |
return false; |
---|
174 |
} |
---|
175 |
raw1394_set_userdata(m_handle_util, static_cast<void *>(this)); |
---|
176 |
|
---|
177 |
// bus reset handling |
---|
178 |
if(raw1394_busreset_notify (m_handle, RAW1394_NOTIFY_ON)) { |
---|
179 |
debugWarning("Could not enable busreset notification.\n"); |
---|
180 |
debugWarning(" Error message: %s\n",strerror(errno)); |
---|
181 |
debugWarning("Continuing without bus reset support.\n"); |
---|
182 |
} else { |
---|
183 |
// apparently this cannot fail |
---|
184 |
raw1394_set_bus_reset_handler(m_handle, busreset_handler); |
---|
185 |
} |
---|
186 |
|
---|
187 |
// initialize the local timesource |
---|
188 |
m_TimeSource_NbCycleWraps=0; |
---|
189 |
unsigned int new_timer; |
---|
190 |
|
---|
191 |
#ifdef LIBRAW1394_USE_CTRREAD_API |
---|
192 |
struct raw1394_cycle_timer ctr; |
---|
193 |
int err; |
---|
194 |
err=raw1394_read_cycle_timer(m_handle_util, &ctr); |
---|
195 |
if(err) { |
---|
196 |
debugError("raw1394_read_cycle_timer failed.\n"); |
---|
197 |
debugError(" Error: %s\n", strerror(err)); |
---|
198 |
debugError(" Your system doesn't seem to support the raw1394_read_cycle_timer call\n"); |
---|
199 |
return false; |
---|
200 |
} |
---|
201 |
new_timer=ctr.cycle_timer; |
---|
202 |
#else |
---|
203 |
// normally we should be able to use the same handle |
---|
204 |
// because it is not iterated on by any other stuff |
---|
205 |
// but I'm not sure |
---|
206 |
quadlet_t buf=0; |
---|
207 |
raw1394_read(m_handle_util, raw1394_get_local_id(m_handle_util), |
---|
208 |
CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf); |
---|
209 |
new_timer= ntohl(buf) & 0xFFFFFFFF; |
---|
210 |
#endif |
---|
211 |
|
---|
212 |
m_TimeSource_LastSecs=CYCLE_TIMER_GET_SECS(new_timer); |
---|
213 |
|
---|
214 |
// update the cycle timer value for initial value |
---|
215 |
initCycleTimer(); |
---|
216 |
|
---|
217 |
// update the internal state |
---|
218 |
m_State=E_Initialized; |
---|
219 |
|
---|
220 |
return true; |
---|
221 |
} |
---|
222 |
|
---|
223 |
bool IsoHandler::prepare() |
---|
224 |
{ |
---|
225 |
debugOutput( DEBUG_LEVEL_VERBOSE, "IsoHandler (%p) enter...\n",this); |
---|
226 |
|
---|
227 |
// check the state |
---|
228 |
if(m_State != E_Initialized) { |
---|
229 |
debugError("Incorrect state, expected E_Initialized, got %d\n",(int)m_State); |
---|
230 |
return false; |
---|
231 |
} |
---|
232 |
|
---|
233 |
// Don't call until libraw1394's raw1394_new_handle() function has been |
---|
234 |
// fixed to correctly initialise the iso_packet_infos field. Bug is |
---|
235 |
// confirmed present in libraw1394 1.2.1. |
---|
236 |
|
---|
237 |
// raw1394_iso_shutdown(m_handle); |
---|
238 |
|
---|
239 |
m_State = E_Prepared; |
---|
240 |
|
---|
241 |
return true; |
---|
242 |
} |
---|
243 |
|
---|
244 |
bool IsoHandler::start(int cycle) |
---|
245 |
{ |
---|
246 |
debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
247 |
|
---|
248 |
// check the state |
---|
249 |
if(m_State != E_Prepared) { |
---|
250 |
debugError("Incorrect state, expected E_Prepared, got %d\n",(int)m_State); |
---|
251 |
return false; |
---|
252 |
} |
---|
253 |
|
---|
254 |
m_State=E_Running; |
---|
255 |
|
---|
256 |
return true; |
---|
257 |
} |
---|
258 |
|
---|
259 |
bool IsoHandler::stop() |
---|
260 |
{ |
---|
261 |
debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
262 |
|
---|
263 |
// check state |
---|
264 |
if(m_State != E_Running) { |
---|
265 |
debugError("Incorrect state, expected E_Running, got %d\n",(int)m_State); |
---|
266 |
return false; |
---|
267 |
} |
---|
268 |
|
---|
269 |
// this is put here to try and avoid the |
---|
270 |
// Runaway context problem |
---|
271 |
// don't know if it will help though. |
---|
272 |
raw1394_iso_xmit_sync(m_handle); |
---|
273 |
|
---|
274 |
raw1394_iso_stop(m_handle); |
---|
275 |
|
---|
276 |
m_State=E_Prepared; |
---|
277 |
|
---|
278 |
return true; |
---|
279 |
} |
---|
280 |
|
---|
281 |
bool |
---|
282 |
IsoHandler::setSyncMaster(FreebobUtil::TimeSource *t) |
---|
283 |
{ |
---|
284 |
m_TimeSource=t; |
---|
285 |
|
---|
286 |
// update the cycle timer value for initial value |
---|
287 |
initCycleTimer(); |
---|
288 |
|
---|
289 |
return true; |
---|
290 |
} |
---|
291 |
|
---|
292 |
/** |
---|
293 |
* Bus reset handler |
---|
294 |
* |
---|
295 |
* @return ? |
---|
296 |
*/ |
---|
297 |
|
---|
298 |
int IsoHandler::handleBusReset(unsigned int generation) { |
---|
299 |
debugOutput( DEBUG_LEVEL_VERBOSE, "bus reset...\n"); |
---|
300 |
|
---|
301 |
// as busreset can elect a new cycle master, |
---|
302 |
// we need to re-initialize our timing code |
---|
303 |
initCycleTimer(); |
---|
304 |
|
---|
305 |
return 0; |
---|
306 |
} |
---|
307 |
|
---|
308 |
/** |
---|
309 |
* Returns the current value of the cycle timer (in ticks) |
---|
310 |
* |
---|
311 |
* @return the current value of the cycle timer (in ticks) |
---|
312 |
*/ |
---|
313 |
|
---|
314 |
unsigned int IsoHandler::getCycleTimerTicks() { |
---|
315 |
|
---|
316 |
#ifdef LIBRAW1394_USE_CTRREAD_API |
---|
317 |
// the new api should be realtime safe. |
---|
318 |
// it might cause a reschedule when turning preemption, |
---|
319 |
// back on but that won't hurt us if we have sufficient |
---|
320 |
// priority |
---|
321 |
struct raw1394_cycle_timer ctr; |
---|
322 |
int err; |
---|
323 |
err=raw1394_read_cycle_timer(m_handle_util, &ctr); |
---|
324 |
if(err) { |
---|
325 |
debugWarning("raw1394_read_cycle_timer: %s", strerror(err)); |
---|
326 |
} |
---|
327 |
return CYCLE_TIMER_TO_TICKS(ctr.cycle_timer); |
---|
328 |
|
---|
329 |
#else |
---|
330 |
// use the estimated version |
---|
331 |
freebob_microsecs_t now; |
---|
332 |
now=m_TimeSource->getCurrentTimeAsUsecs(); |
---|
333 |
return mapToCycleTimer(now); |
---|
334 |
#endif |
---|
335 |
|
---|
336 |
} |
---|
337 |
|
---|
338 |
/** |
---|
339 |
* Returns the current value of the cycle timer (as is) |
---|
340 |
* |
---|
341 |
* @return the current value of the cycle timer (as is) |
---|
342 |
*/ |
---|
343 |
|
---|
344 |
unsigned int IsoHandler::getCycleTimer() { |
---|
345 |
|
---|
346 |
#ifdef LIBRAW1394_USE_CTRREAD_API |
---|
347 |
// the new api should be realtime safe. |
---|
348 |
// it might cause a reschedule when turning preemption, |
---|
349 |
// back on but that won't hurt us if we have sufficient |
---|
350 |
// priority |
---|
351 |
struct raw1394_cycle_timer ctr; |
---|
352 |
int err; |
---|
353 |
err=raw1394_read_cycle_timer(m_handle_util, &ctr); |
---|
354 |
if(err) { |
---|
355 |
debugWarning("raw1394_read_cycle_timer: %s", strerror(err)); |
---|
356 |
} |
---|
357 |
return ctr.cycle_timer; |
---|
358 |
|
---|
359 |
#else |
---|
360 |
// use the estimated version |
---|
361 |
freebob_microsecs_t now; |
---|
362 |
now=m_TimeSource->getCurrentTimeAsUsecs(); |
---|
363 |
return TICKS_TO_CYCLE_TIMER(mapToCycleTimer(now)); |
---|
364 |
#endif |
---|
365 |
|
---|
366 |
} |
---|
367 |
/** |
---|
368 |
* Maps a value of the active TimeSource to a Cycle Timer value. |
---|
369 |
* |
---|
370 |
* This is usefull if you know a time value and want the corresponding |
---|
371 |
* Cycle Timer value. Note that the value shouldn't be too far off |
---|
372 |
* the current time, because then the mapping can be bad. |
---|
373 |
* |
---|
374 |
* @return the value of the cycle timer (in ticks) |
---|
375 |
*/ |
---|
376 |
|
---|
377 |
unsigned int IsoHandler::mapToCycleTimer(freebob_microsecs_t now) { |
---|
378 |
|
---|
379 |
// linear interpolation |
---|
380 |
int delta_usecs=now-m_lastmeas_usecs; |
---|
381 |
|
---|
382 |
float offset=m_ticks_per_usec * ((float)delta_usecs); |
---|
383 |
|
---|
384 |
int64_t pred_ticks=(int64_t)m_cycletimer_ticks+(int64_t)offset; |
---|
385 |
|
---|
386 |
if (pred_ticks < 0) { |
---|
387 |
debugWarning("Predicted ticks < 0\n"); |
---|
388 |
} |
---|
389 |
debugOutput(DEBUG_LEVEL_VERBOSE,"now=%llu, m_lastmeas_usec=%llu, delta_usec=%d\n", |
---|
390 |
now, m_lastmeas_usecs, delta_usecs); |
---|
391 |
debugOutput(DEBUG_LEVEL_VERBOSE,"t/usec=%f, offset=%f, m_cc_t=%llu, pred_ticks=%lld\n", |
---|
392 |
m_ticks_per_usec, offset, m_cycletimer_ticks, pred_ticks); |
---|
393 |
|
---|
394 |
// if we need to wrap, do it |
---|
395 |
if (pred_ticks > TICKS_PER_SECOND * 128L) { |
---|
396 |
pred_ticks -= TICKS_PER_SECOND * 128L; |
---|
397 |
} |
---|
398 |
|
---|
399 |
return pred_ticks; |
---|
400 |
} |
---|
401 |
|
---|
402 |
/** |
---|
403 |
* Maps a Cycle Timer value (in ticks) of the active TimeSource's unit. |
---|
404 |
* |
---|
405 |
* This is usefull if you know a Cycle Timer value and want the corresponding |
---|
406 |
* timesource value. Note that the value shouldn't be too far off |
---|
407 |
* the current cycle timer, because then the mapping can be bad. |
---|
408 |
* |
---|
409 |
* @return the mapped value |
---|
410 |
*/ |
---|
411 |
|
---|
412 |
freebob_microsecs_t IsoHandler::mapToTimeSource(unsigned int cc) { |
---|
413 |
|
---|
414 |
// linear interpolation |
---|
415 |
int delta_cc=cc-m_cycletimer_ticks; |
---|
416 |
|
---|
417 |
float offset= ((float)delta_cc) / m_ticks_per_usec; |
---|
418 |
|
---|
419 |
int64_t pred_time=(int64_t)m_lastmeas_usecs+(int64_t)offset; |
---|
420 |
|
---|
421 |
if (pred_time < 0) { |
---|
422 |
debugWarning("Predicted time < 0\n"); |
---|
423 |
debugOutput(DEBUG_LEVEL_VERBOSE,"cc=%u, m_cycletimer_ticks=%llu, delta_cc=%d\n", |
---|
424 |
cc, m_cycletimer_ticks, delta_cc); |
---|
425 |
debugOutput(DEBUG_LEVEL_VERBOSE,"t/usec=%f, offset=%f, m_lastmeas_usecs=%llu, pred_time=%lld\n", |
---|
426 |
m_ticks_per_usec, offset, m_lastmeas_usecs, pred_time); |
---|
427 |
} |
---|
428 |
|
---|
429 |
|
---|
430 |
return pred_time; |
---|
431 |
} |
---|
432 |
|
---|
433 |
bool IsoHandler::updateCycleTimer() { |
---|
434 |
freebob_microsecs_t prev_usecs=m_lastmeas_usecs; |
---|
435 |
uint64_t prev_ticks=m_cycletimer_ticks; |
---|
436 |
|
---|
437 |
freebob_microsecs_t new_usecs; |
---|
438 |
uint64_t new_ticks; |
---|
439 |
unsigned int new_timer; |
---|
440 |
|
---|
441 |
/* To estimate the cycle timer, we implement a |
---|
442 |
DLL based routine, that maps the cycle timer |
---|
443 |
on the system clock. |
---|
444 |
|
---|
445 |
For more info, refer to: |
---|
446 |
"Using a DLL to filter time" |
---|
447 |
Fons Adriaensen |
---|
448 |
|
---|
449 |
Can be found at: |
---|
450 |
http://users.skynet.be/solaris/linuxaudio/downloads/usingdll.pdf |
---|
451 |
or maybe at: |
---|
452 |
http://www.kokkinizita.net/linuxaudio |
---|
453 |
|
---|
454 |
Basically what we do is estimate the next point (T1,CC1_est) |
---|
455 |
based upon the previous point (T0, CC0) and the estimated rate (R). |
---|
456 |
Then we compare our estimation with the measured cycle timer |
---|
457 |
at T1 (=CC1_meas). We then calculate the estimation error on R: |
---|
458 |
err=(CC1_meas-CC0)/(T1-T2) - (CC1_est-CC0)/(T1-T2) |
---|
459 |
and try to minimize this on average (DLL) |
---|
460 |
|
---|
461 |
Note that in order to have a contignous mapping, we should |
---|
462 |
update CC0<=CC1_est instead of CC0<=CC1_meas. The measurement |
---|
463 |
serves only to correct the error 'on average'. |
---|
464 |
|
---|
465 |
In the code, the following variable names are used: |
---|
466 |
T0=prev_usecs |
---|
467 |
T1=next_usecs |
---|
468 |
|
---|
469 |
CC0=prev_ticks |
---|
470 |
CC1_est=est_ticks |
---|
471 |
CC1_meas=meas_ticks |
---|
472 |
|
---|
473 |
*/ |
---|
474 |
#ifdef LIBRAW1394_USE_CTRREAD_API |
---|
475 |
struct raw1394_cycle_timer ctr; |
---|
476 |
int err; |
---|
477 |
err=raw1394_read_cycle_timer(m_handle_util, &ctr); |
---|
478 |
if(err) { |
---|
479 |
debugWarning("raw1394_read_cycle_timer: %s", strerror(err)); |
---|
480 |
} |
---|
481 |
new_usecs=(freebob_microsecs_t)ctr.local_time; |
---|
482 |
new_timer=ctr.cycle_timer; |
---|
483 |
#else |
---|
484 |
// normally we should be able to use the same handle |
---|
485 |
// because it is not iterated on by any other stuff |
---|
486 |
// but I'm not sure |
---|
487 |
quadlet_t buf=0; |
---|
488 |
raw1394_read(m_handle_util, raw1394_get_local_id(m_handle_util), |
---|
489 |
CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf); |
---|
490 |
new_usecs=m_TimeSource->getCurrentTimeAsUsecs(); |
---|
491 |
new_timer= ntohl(buf) & 0xFFFFFFFF; |
---|
492 |
#endif |
---|
493 |
|
---|
494 |
new_ticks=CYCLE_TIMER_TO_TICKS(new_timer); |
---|
495 |
|
---|
496 |
// the difference in system time |
---|
497 |
int64_t delta_usecs=new_usecs-prev_usecs; |
---|
498 |
// this cannot be 0, because m_TimeSource->getCurrentTimeAsUsecs should |
---|
499 |
// never return the same value (maybe in future terrahz processors?) |
---|
500 |
assert(delta_usecs); |
---|
501 |
|
---|
502 |
// the measured cycle timer difference |
---|
503 |
int64_t delta_ticks_meas; |
---|
504 |
if (new_ticks >= prev_ticks) { |
---|
505 |
delta_ticks_meas=new_ticks - prev_ticks; |
---|
506 |
} else { // wraparound |
---|
507 |
delta_ticks_meas=CYCLE_TIMER_UNWRAP_TICKS(new_ticks) - prev_ticks; |
---|
508 |
} |
---|
509 |
|
---|
510 |
// the estimated cycle timer difference |
---|
511 |
int64_t delta_ticks_est=(int64_t)(m_ticks_per_usec * ((float)delta_usecs)); |
---|
512 |
|
---|
513 |
// the measured & estimated rate |
---|
514 |
float rate_meas=((double)delta_ticks_meas/(double)delta_usecs); |
---|
515 |
float rate_est=((float)m_ticks_per_usec); |
---|
516 |
|
---|
517 |
// these make sure we don't update when the measurement is |
---|
518 |
// bad. We know the nominal rate, and it can't be that far |
---|
519 |
// off. The thing is that there is a problem in measuring |
---|
520 |
// both usecs and ticks at the same time (no provision in |
---|
521 |
// the kernel. |
---|
522 |
// We know that there are some tolerances on both |
---|
523 |
// the system clock and the firewire clock such that the |
---|
524 |
// actual difference is rather small. So we discard values |
---|
525 |
// that are too far from the nominal rate. |
---|
526 |
// Otherwise the DLL has to have a very low bandwidth, in |
---|
527 |
// order not to be desturbed too much by these bad measurements |
---|
528 |
// resulting in very slow locking. |
---|
529 |
|
---|
530 |
if ( (rate_meas < 24.576*(1.0+CC_MAX_RATE_ERROR)) |
---|
531 |
&& (rate_meas > 24.576*(1.0-CC_MAX_RATE_ERROR))) { |
---|
532 |
|
---|
533 |
#ifdef DEBUG |
---|
534 |
|
---|
535 |
int64_t diff=(int64_t)delta_ticks_est; |
---|
536 |
|
---|
537 |
// calculate the difference in predicted ticks and |
---|
538 |
// measured ticks |
---|
539 |
diff -= delta_ticks_meas; |
---|
540 |
|
---|
541 |
|
---|
542 |
if (diff > 24000L || diff < -24000L) { // approx +/-1 msec error |
---|
543 |
debugOutput(DEBUG_LEVEL_VERBOSE,"Bad pred (%p): diff=%lld, dt_est=%lld, dt_meas=%lld, d=%lldus, err=%fus\n", this, |
---|
544 |
diff, delta_ticks_est, delta_ticks_meas, delta_usecs, (((float)diff)/24.576) |
---|
545 |
); |
---|
546 |
} else { |
---|
547 |
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Good pred: diff=%lld, dt_est=%lld, dt_meas=%lld, d=%lldus, err=%fus\n", |
---|
548 |
diff, delta_ticks_est, delta_ticks_meas, delta_usecs, (((float)diff)/24.576) |
---|
549 |
); |
---|
550 |
} |
---|
551 |
#endif |
---|
552 |
// DLL the error to obtain the rate. |
---|
553 |
// (note: the DLL makes the error=0) |
---|
554 |
// only update the DLL if the rate is within 10% of the expected |
---|
555 |
// rate |
---|
556 |
float err=rate_meas-rate_est; |
---|
557 |
|
---|
558 |
// 2nd order DLL update |
---|
559 |
// const float w=6.28*0.0001; |
---|
560 |
// const float b=w*1.45; |
---|
561 |
// const float c=w*w; |
---|
562 |
// |
---|
563 |
// m_ticks_per_usec += b*err + m_ticks_per_usec_dll_err2; |
---|
564 |
// m_ticks_per_usec_dll_err2 += c * err; |
---|
565 |
|
---|
566 |
// first order DLL update |
---|
567 |
m_ticks_per_usec += CC_DLL_COEFF*err; |
---|
568 |
|
---|
569 |
if ( (m_ticks_per_usec > 24.576*(1.0+CC_MAX_RATE_ERROR)) |
---|
570 |
|| (m_ticks_per_usec < 24.576*(1.0-CC_MAX_RATE_ERROR))) { |
---|
571 |
debugOutput(DEBUG_LEVEL_VERBOSE, "Warning: DLL ticks/usec near clipping (%8.4f)\n", |
---|
572 |
m_ticks_per_usec); |
---|
573 |
} |
---|
574 |
|
---|
575 |
// update the internal values |
---|
576 |
// note: the next cycletimer point is |
---|
577 |
// the estimated one, not the measured one! |
---|
578 |
m_cycletimer_ticks += delta_ticks_est; |
---|
579 |
// if we need to wrap, do it |
---|
580 |
if (m_cycletimer_ticks > TICKS_PER_SECOND * 128L) { |
---|
581 |
m_cycletimer_ticks -= TICKS_PER_SECOND * 128L; |
---|
582 |
} |
---|
583 |
|
---|
584 |
m_lastmeas_usecs = new_usecs; |
---|
585 |
|
---|
586 |
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"U TS: %10llu -> %10llu, d=%7lldus, dt_est=%7lld, dt_meas=%7lld, erate=%6.4f, mrate=%6f\n", |
---|
587 |
prev_ticks, m_cycletimer_ticks, delta_usecs, |
---|
588 |
delta_ticks_est, delta_ticks_meas, m_ticks_per_usec, rate_meas |
---|
589 |
); |
---|
590 |
|
---|
591 |
// the estimate is good |
---|
592 |
return true; |
---|
593 |
} else { |
---|
594 |
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"U TS: Not updating, rate out of range (%6.4f)\n", |
---|
595 |
rate_meas |
---|
596 |
); |
---|
597 |
return false; |
---|
598 |
|
---|
599 |
} |
---|
600 |
} |
---|
601 |
|
---|
602 |
void IsoHandler::initCycleTimer() { |
---|
603 |
freebob_microsecs_t prev_usecs; |
---|
604 |
unsigned int prev_ticks; |
---|
605 |
unsigned int prev_timer; |
---|
606 |
|
---|
607 |
freebob_microsecs_t new_usecs; |
---|
608 |
unsigned int new_ticks; |
---|
609 |
unsigned int new_timer; |
---|
610 |
|
---|
611 |
float rate=0.0; |
---|
612 |
|
---|
613 |
unsigned int try_cnt=0; |
---|
614 |
|
---|
615 |
// make sure that we start with a decent rate, |
---|
616 |
// meaning that we want two successive (usecs,ticks) |
---|
617 |
// points that make sense. |
---|
618 |
|
---|
619 |
while ( (try_cnt++ < CC_INIT_MAX_TRIES) && |
---|
620 |
( (rate > 24.576*(1.0+CC_MAX_RATE_ERROR)) |
---|
621 |
|| (rate < 24.576*(1.0-CC_MAX_RATE_ERROR)))) { |
---|
622 |
|
---|
623 |
#ifdef LIBRAW1394_USE_CTRREAD_API |
---|
624 |
struct raw1394_cycle_timer ctr; |
---|
625 |
int err; |
---|
626 |
err=raw1394_read_cycle_timer(m_handle_util, &ctr); |
---|
627 |
if(err) { |
---|
628 |
debugWarning("raw1394_read_cycle_timer: %s", strerror(err)); |
---|
629 |
} |
---|
630 |
prev_usecs=(freebob_microsecs_t)ctr.local_time; |
---|
631 |
prev_timer=ctr.cycle_timer; |
---|
632 |
#else |
---|
633 |
// normally we should be able to use the same handle |
---|
634 |
// because it is not iterated on by any other stuff |
---|
635 |
// but I'm not sure |
---|
636 |
quadlet_t buf=0; |
---|
637 |
raw1394_read(m_handle_util, raw1394_get_local_id(m_handle_util), |
---|
638 |
CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf); |
---|
639 |
prev_usecs=m_TimeSource->getCurrentTimeAsUsecs(); |
---|
640 |
prev_timer= ntohl(buf) & 0xFFFFFFFF; |
---|
641 |
#endif |
---|
642 |
prev_ticks=CYCLE_TIMER_TO_TICKS(prev_timer); |
---|
643 |
|
---|
644 |
usleep(CC_SLEEP_TIME_AFTER_UPDATE); |
---|
645 |
|
---|
646 |
|
---|
647 |
#ifdef LIBRAW1394_USE_CTRREAD_API |
---|
648 |
err=raw1394_read_cycle_timer(m_handle_util, &ctr); |
---|
649 |
if(err) { |
---|
650 |
debugWarning("raw1394_read_cycle_timer: %s", strerror(err)); |
---|
651 |
} |
---|
652 |
new_usecs=(freebob_microsecs_t)ctr.local_time; |
---|
653 |
new_timer=ctr.cycle_timer; |
---|
654 |
#else |
---|
655 |
// normally we should be able to use the same handle |
---|
656 |
// because it is not iterated on by any other stuff |
---|
657 |
// but I'm not sure |
---|
658 |
raw1394_read(m_handle_util, raw1394_get_local_id(m_handle_util), |
---|
659 |
CSR_REGISTER_BASE | CSR_CYCLE_TIME, 4, &buf); |
---|
660 |
new_usecs=m_TimeSource->getCurrentTimeAsUsecs(); |
---|
661 |
new_timer= ntohl(buf) & 0xFFFFFFFF; |
---|
662 |
#endif |
---|
663 |
|
---|
664 |
new_ticks=CYCLE_TIMER_TO_TICKS(new_timer); |
---|
665 |
|
---|
666 |
unsigned int delta_ticks; |
---|
667 |
|
---|
668 |
if (new_ticks > prev_ticks) { |
---|
669 |
delta_ticks=new_ticks - prev_ticks; |
---|
670 |
} else { // wraparound |
---|
671 |
delta_ticks=CYCLE_TIMER_UNWRAP_TICKS(new_ticks) - prev_ticks; |
---|
672 |
} |
---|
673 |
|
---|
674 |
int delta_usecs=new_usecs-prev_usecs; |
---|
675 |
|
---|
676 |
// this cannot be 0, because m_TimeSource->getCurrentTimeAsUsecs should |
---|
677 |
// never return the same value (maybe in future terrahz processors?) |
---|
678 |
assert(delta_usecs); |
---|
679 |
|
---|
680 |
rate=((float)delta_ticks/(float)delta_usecs); |
---|
681 |
|
---|
682 |
// update the internal values |
---|
683 |
m_cycletimer_ticks=new_ticks; |
---|
684 |
m_lastmeas_usecs=new_usecs; |
---|
685 |
|
---|
686 |
debugOutput(DEBUG_LEVEL_VERBOSE,"Try %d: rate=%6.4f\n", |
---|
687 |
try_cnt,rate |
---|
688 |
); |
---|
689 |
|
---|
690 |
} |
---|
691 |
|
---|
692 |
// this is not fatal, the DLL will eventually correct this |
---|
693 |
if(try_cnt == CC_INIT_MAX_TRIES) { |
---|
694 |
debugWarning("Failed to properly initialize cycle timer...\n"); |
---|
695 |
} |
---|
696 |
|
---|
697 |
// initialize this to the nominal value |
---|
698 |
m_ticks_per_usec = 24.576; |
---|
699 |
m_ticks_per_usec_dll_err2 = 0; |
---|
700 |
|
---|
701 |
} |
---|
702 |
|
---|
703 |
void IsoHandler::dumpInfo() |
---|
704 |
{ |
---|
705 |
|
---|
706 |
int channel=-1; |
---|
707 |
if (m_Client) channel=m_Client->getChannel(); |
---|
708 |
|
---|
709 |
debugOutputShort( DEBUG_LEVEL_NORMAL, " Handler type : %s\n", |
---|
710 |
(this->getType()==EHT_Receive ? "Receive" : "Transmit")); |
---|
711 |
debugOutputShort( DEBUG_LEVEL_NORMAL, " Port, Channel : %2d, %2d\n", |
---|
712 |
m_port, channel); |
---|
713 |
debugOutputShort( DEBUG_LEVEL_NORMAL, " Packet count : %10d (%5d dropped)\n", |
---|
714 |
this->getPacketCount(), this->getDroppedCount()); |
---|
715 |
|
---|
716 |
#ifdef DEBUG |
---|
717 |
unsigned int cc=this->getCycleTimerTicks(); |
---|
718 |
debugOutputShort( DEBUG_LEVEL_NORMAL, " Cycle timer : %10lu (%03us, %04ucycles, %04uticks)\n", |
---|
719 |
cc,TICKS_TO_SECS(cc),TICKS_TO_CYCLES(cc),TICKS_TO_OFFSET(cc)); |
---|
720 |
|
---|
721 |
/* freebob_microsecs_t now=m_TimeSource->getCurrentTimeAsUsecs(); |
---|
722 |
cc=mapToCycleTimer(now); |
---|
723 |
freebob_microsecs_t now_mapped=mapToTimeSource(cc); |
---|
724 |
|
---|
725 |
debugOutputShort( DEBUG_LEVEL_NORMAL, " Mapping test : now: %14llu, cc: %10lu, mapped now: %14llu\n", |
---|
726 |
now,cc,now_mapped);*/ |
---|
727 |
#endif |
---|
728 |
debugOutputShort( DEBUG_LEVEL_NORMAL, " Ticks/usec : %8.6f (dll2: %8.6e)\n\n", |
---|
729 |
this->getTicksPerUsec(), m_ticks_per_usec_dll_err2); |
---|
730 |
|
---|
731 |
}; |
---|
732 |
|
---|
733 |
void IsoHandler::setVerboseLevel(int l) |
---|
734 |
{ |
---|
735 |
setDebugLevel(l); |
---|
736 |
} |
---|
737 |
|
---|
738 |
bool IsoHandler::registerStream(IsoStream *stream) |
---|
739 |
{ |
---|
740 |
assert(stream); |
---|
741 |
debugOutput( DEBUG_LEVEL_VERBOSE, "registering stream (%p)\n", stream); |
---|
742 |
|
---|
743 |
if (m_Client) { |
---|
744 |
debugFatal( "Generic IsoHandlers can have only one client\n"); |
---|
745 |
return false; |
---|
746 |
} |
---|
747 |
|
---|
748 |
m_Client=stream; |
---|
749 |
|
---|
750 |
m_Client->setHandler(this); |
---|
751 |
|
---|
752 |
return true; |
---|
753 |
|
---|
754 |
} |
---|
755 |
|
---|
756 |
bool IsoHandler::unregisterStream(IsoStream *stream) |
---|
757 |
{ |
---|
758 |
assert(stream); |
---|
759 |
debugOutput( DEBUG_LEVEL_VERBOSE, "unregistering stream (%p)\n", stream); |
---|
760 |
|
---|
761 |
if(stream != m_Client) { |
---|
762 |
debugFatal( "no client registered\n"); |
---|
763 |
return false; |
---|
764 |
} |
---|
765 |
|
---|
766 |
m_Client->clearHandler(); |
---|
767 |
|
---|
768 |
m_Client=0; |
---|
769 |
return true; |
---|
770 |
|
---|
771 |
} |
---|
772 |
|
---|
773 |
/* The timesource interface */ |
---|
774 |
freebob_microsecs_t IsoHandler::getCurrentTime() { |
---|
775 |
unsigned int new_timer; |
---|
776 |
|
---|
777 |
new_timer= getCycleTimerTicks(); |
---|
778 |
|
---|
779 |
// this assumes that it never happens that there are more than 2 |
---|
780 |
// minutes between calls |
---|
781 |
if (CYCLE_TIMER_GET_SECS(new_timer) < m_TimeSource_LastSecs) { |
---|
782 |
m_TimeSource_NbCycleWraps++; |
---|
783 |
} |
---|
784 |
|
---|
785 |
freebob_microsecs_t ticks=m_TimeSource_NbCycleWraps * 128L * TICKS_PER_SECOND |
---|
786 |
+ CYCLE_TIMER_TO_TICKS(new_timer); |
---|
787 |
|
---|
788 |
m_TimeSource_LastSecs=CYCLE_TIMER_GET_SECS(new_timer); |
---|
789 |
|
---|
790 |
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"Wraps=%4u, LastSecs=%3u, nowSecs=%3u, ticks=%10u\n", |
---|
791 |
m_TimeSource_NbCycleWraps, m_TimeSource_LastSecs, |
---|
792 |
CYCLE_TIMER_GET_SECS(new_timer), ticks |
---|
793 |
); |
---|
794 |
|
---|
795 |
return ticks; |
---|
796 |
} |
---|
797 |
|
---|
798 |
freebob_microsecs_t IsoHandler::unWrapTime(freebob_microsecs_t t) { |
---|
799 |
return CYCLE_TIMER_UNWRAP_TICKS(t); |
---|
800 |
} |
---|
801 |
|
---|
802 |
freebob_microsecs_t IsoHandler::wrapTime(freebob_microsecs_t t) { |
---|
803 |
return CYCLE_TIMER_WRAP_TICKS(t); |
---|
804 |
} |
---|
805 |
|
---|
806 |
freebob_microsecs_t IsoHandler::getCurrentTimeAsUsecs() { |
---|
807 |
float tmp=getCurrentTime(); |
---|
808 |
float tmp2 = tmp * USECS_PER_TICK; |
---|
809 |
freebob_microsecs_t retval=(freebob_microsecs_t)tmp2; |
---|
810 |
|
---|
811 |
debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"tmp=%f, tmp2=%f, retval=%u\n", |
---|
812 |
tmp, tmp2,retval |
---|
813 |
); |
---|
814 |
|
---|
815 |
return retval; |
---|
816 |
} |
---|
817 |
|
---|
818 |
|
---|
819 |
|
---|
820 |
/* Child class implementations */ |
---|
821 |
|
---|
822 |
IsoRecvHandler::IsoRecvHandler(int port) |
---|
823 |
: IsoHandler(port) |
---|
824 |
{ |
---|
825 |
debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
826 |
} |
---|
827 |
IsoRecvHandler::IsoRecvHandler(int port, unsigned int buf_packets, |
---|
828 |
unsigned int max_packet_size, int irq) |
---|
829 |
: IsoHandler(port, buf_packets,max_packet_size,irq) |
---|
830 |
{ |
---|
831 |
debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
832 |
|
---|
833 |
} |
---|
834 |
IsoRecvHandler::~IsoRecvHandler() |
---|
835 |
{ |
---|
836 |
|
---|
837 |
} |
---|
838 |
|
---|
839 |
bool |
---|
840 |
IsoRecvHandler::init() { |
---|
841 |
debugOutput( DEBUG_LEVEL_VERBOSE, "init recv handler %p\n",this); |
---|
842 |
|
---|
843 |
if(!(IsoHandler::init())) { |
---|
844 |
return false; |
---|
845 |
} |
---|
846 |
return true; |
---|
847 |
|
---|
848 |
} |
---|
849 |
|
---|
850 |
enum raw1394_iso_disposition IsoRecvHandler::putPacket( |
---|
851 |
unsigned char *data, unsigned int length, |
---|
852 |
unsigned char channel, unsigned char tag, unsigned char sy, |
---|
853 |
unsigned int cycle, unsigned int dropped) { |
---|
854 |
|
---|
855 |
debugOutput( DEBUG_LEVEL_VERY_VERBOSE, |
---|
856 |
"received packet: length=%d, channel=%d, cycle=%d\n", |
---|
857 |
length, channel, cycle ); |
---|
858 |
m_packetcount++; |
---|
859 |
m_dropped+=dropped; |
---|
860 |
|
---|
861 |
if(m_Client) { |
---|
862 |
return m_Client->putPacket(data, length, channel, tag, sy, cycle, dropped); |
---|
863 |
} |
---|
864 |
|
---|
865 |
return RAW1394_ISO_OK; |
---|
866 |
} |
---|
867 |
|
---|
868 |
bool IsoRecvHandler::prepare() |
---|
869 |
{ |
---|
870 |
|
---|
871 |
// prepare the generic IsoHandler |
---|
872 |
if(!IsoHandler::prepare()) { |
---|
873 |
return false; |
---|
874 |
} |
---|
875 |
|
---|
876 |
debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing iso receive handler (%p)\n",this); |
---|
877 |
debugOutput( DEBUG_LEVEL_VERBOSE, " Buffers : %d \n",m_buf_packets); |
---|
878 |
debugOutput( DEBUG_LEVEL_VERBOSE, " Max Packet size : %d \n",m_max_packet_size); |
---|
879 |
debugOutput( DEBUG_LEVEL_VERBOSE, " Channel : %d \n",m_Client->getChannel()); |
---|
880 |
debugOutput( DEBUG_LEVEL_VERBOSE, " Irq interval : %d \n",m_irq_interval); |
---|
881 |
|
---|
882 |
if(m_irq_interval > 1) { |
---|
883 |
if(raw1394_iso_recv_init(m_handle, |
---|
884 |
iso_receive_handler, |
---|
885 |
m_buf_packets, |
---|
886 |
m_max_packet_size, |
---|
887 |
m_Client->getChannel(), |
---|
888 |
RAW1394_DMA_BUFFERFILL, |
---|
889 |
m_irq_interval)) { |
---|
890 |
debugFatal("Could not do receive initialisation!\n" ); |
---|
891 |
debugFatal(" %s\n",strerror(errno)); |
---|
892 |
|
---|
893 |
return false; |
---|
894 |
} |
---|
895 |
} else { |
---|
896 |
if(raw1394_iso_recv_init(m_handle, |
---|
897 |
iso_receive_handler, |
---|
898 |
m_buf_packets, |
---|
899 |
m_max_packet_size, |
---|
900 |
m_Client->getChannel(), |
---|
901 |
RAW1394_DMA_PACKET_PER_BUFFER, |
---|
902 |
m_irq_interval)) { |
---|
903 |
debugFatal("Could not do receive initialisation!\n" ); |
---|
904 |
debugFatal(" %s\n",strerror(errno)); |
---|
905 |
|
---|
906 |
return false; |
---|
907 |
} |
---|
908 |
} |
---|
909 |
return true; |
---|
910 |
} |
---|
911 |
|
---|
912 |
bool IsoRecvHandler::start(int cycle) |
---|
913 |
{ |
---|
914 |
debugOutput( DEBUG_LEVEL_VERBOSE, "start on cycle %d\n", cycle); |
---|
915 |
|
---|
916 |
// start the generic IsoHandler |
---|
917 |
if(!IsoHandler::start(cycle)) { |
---|
918 |
return false; |
---|
919 |
} |
---|
920 |
|
---|
921 |
if(raw1394_iso_recv_start(m_handle, cycle, -1, 0)) { |
---|
922 |
debugFatal("Could not start receive handler (%s)\n",strerror(errno)); |
---|
923 |
return false; |
---|
924 |
} |
---|
925 |
return true; |
---|
926 |
} |
---|
927 |
|
---|
928 |
int IsoRecvHandler::handleBusReset(unsigned int generation) { |
---|
929 |
debugOutput( DEBUG_LEVEL_VERBOSE, "handle bus reset...\n"); |
---|
930 |
|
---|
931 |
//TODO: implement busreset |
---|
932 |
|
---|
933 |
// pass on the busreset signal |
---|
934 |
if(IsoHandler::handleBusReset(generation)) { |
---|
935 |
return -1; |
---|
936 |
} |
---|
937 |
return 0; |
---|
938 |
} |
---|
939 |
|
---|
940 |
/* ----------------- XMIT --------------- */ |
---|
941 |
|
---|
942 |
IsoXmitHandler::IsoXmitHandler(int port) |
---|
943 |
: IsoHandler(port), m_prebuffers(0) |
---|
944 |
{ |
---|
945 |
debugOutput( DEBUG_LEVEL_VERBOSE, "IsoXmitHandler enter...\n"); |
---|
946 |
|
---|
947 |
} |
---|
948 |
IsoXmitHandler::IsoXmitHandler(int port, unsigned int buf_packets, |
---|
949 |
unsigned int max_packet_size, int irq) |
---|
950 |
: IsoHandler(port, buf_packets, max_packet_size,irq), |
---|
951 |
m_speed(RAW1394_ISO_SPEED_400), m_prebuffers(0) |
---|
952 |
{ |
---|
953 |
debugOutput( DEBUG_LEVEL_VERBOSE, "IsoXmitHandler enter...\n"); |
---|
954 |
|
---|
955 |
} |
---|
956 |
IsoXmitHandler::IsoXmitHandler(int port, unsigned int buf_packets, |
---|
957 |
unsigned int max_packet_size, int irq, |
---|
958 |
enum raw1394_iso_speed speed) |
---|
959 |
: IsoHandler(port, buf_packets,max_packet_size,irq), |
---|
960 |
m_speed(speed), m_prebuffers(0) |
---|
961 |
{ |
---|
962 |
debugOutput( DEBUG_LEVEL_VERBOSE, "IsoXmitHandler enter...\n"); |
---|
963 |
|
---|
964 |
} |
---|
965 |
|
---|
966 |
IsoXmitHandler::~IsoXmitHandler() |
---|
967 |
{ |
---|
968 |
// handle cleanup is done in the IsoHanlder destructor |
---|
969 |
} |
---|
970 |
|
---|
971 |
bool |
---|
972 |
IsoXmitHandler::init() { |
---|
973 |
|
---|
974 |
debugOutput( DEBUG_LEVEL_VERBOSE, "init xmit handler %p\n",this); |
---|
975 |
|
---|
976 |
if(!(IsoHandler::init())) { |
---|
977 |
return false; |
---|
978 |
} |
---|
979 |
|
---|
980 |
return true; |
---|
981 |
} |
---|
982 |
|
---|
983 |
bool IsoXmitHandler::prepare() |
---|
984 |
{ |
---|
985 |
debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing iso transmit handler (%p, client=%p)\n",this,m_Client); |
---|
986 |
|
---|
987 |
if(!(IsoHandler::prepare())) { |
---|
988 |
return false; |
---|
989 |
} |
---|
990 |
|
---|
991 |
debugOutput( DEBUG_LEVEL_VERBOSE, " Buffers : %d \n",m_buf_packets); |
---|
992 |
debugOutput( DEBUG_LEVEL_VERBOSE, " Max Packet size : %d \n",m_max_packet_size); |
---|
993 |
debugOutput( DEBUG_LEVEL_VERBOSE, " Channel : %d \n",m_Client->getChannel()); |
---|
994 |
debugOutput( DEBUG_LEVEL_VERBOSE, " Speed : %d \n",m_speed); |
---|
995 |
debugOutput( DEBUG_LEVEL_VERBOSE, " Irq interval : %d \n",m_irq_interval); |
---|
996 |
|
---|
997 |
if(raw1394_iso_xmit_init(m_handle, |
---|
998 |
iso_transmit_handler, |
---|
999 |
m_buf_packets, |
---|
1000 |
m_max_packet_size, |
---|
1001 |
m_Client->getChannel(), |
---|
1002 |
m_speed, |
---|
1003 |
m_irq_interval)) { |
---|
1004 |
debugFatal("Could not do xmit initialisation!\n" ); |
---|
1005 |
|
---|
1006 |
return false; |
---|
1007 |
} |
---|
1008 |
|
---|
1009 |
return true; |
---|
1010 |
} |
---|
1011 |
|
---|
1012 |
bool IsoXmitHandler::start(int cycle) |
---|
1013 |
{ |
---|
1014 |
debugOutput( DEBUG_LEVEL_VERBOSE, "start on cycle %d\n", cycle); |
---|
1015 |
|
---|
1016 |
if(!(IsoHandler::start(cycle))) { |
---|
1017 |
return false; |
---|
1018 |
} |
---|
1019 |
|
---|
1020 |
if(raw1394_iso_xmit_start(m_handle, cycle, m_prebuffers)) { |
---|
1021 |
debugFatal("Could not start xmit handler (%s)\n",strerror(errno)); |
---|
1022 |
return false; |
---|
1023 |
} |
---|
1024 |
return true; |
---|
1025 |
} |
---|
1026 |
|
---|
1027 |
enum raw1394_iso_disposition IsoXmitHandler::getPacket( |
---|
1028 |
unsigned char *data, unsigned int *length, |
---|
1029 |
unsigned char *tag, unsigned char *sy, |
---|
1030 |
int cycle, unsigned int dropped) { |
---|
1031 |
|
---|
1032 |
debugOutput( DEBUG_LEVEL_VERY_VERBOSE, |
---|
1033 |
"sending packet: length=%d, cycle=%d\n", |
---|
1034 |
*length, cycle ); |
---|
1035 |
m_packetcount++; |
---|
1036 |
m_dropped+=dropped; |
---|
1037 |
|
---|
1038 |
if(m_Client) { |
---|
1039 |
return m_Client->getPacket(data, length, tag, sy, cycle, dropped, m_max_packet_size); |
---|
1040 |
} |
---|
1041 |
|
---|
1042 |
return RAW1394_ISO_OK; |
---|
1043 |
} |
---|
1044 |
|
---|
1045 |
int IsoXmitHandler::handleBusReset(unsigned int generation) { |
---|
1046 |
debugOutput( DEBUG_LEVEL_VERBOSE, "bus reset...\n"); |
---|
1047 |
//TODO: implement busreset |
---|
1048 |
|
---|
1049 |
// pass on the busreset signal |
---|
1050 |
if(IsoHandler::handleBusReset(generation)) { |
---|
1051 |
return -1; |
---|
1052 |
} |
---|
1053 |
|
---|
1054 |
return 0; |
---|
1055 |
} |
---|
1056 |
|
---|
1057 |
} |
---|
1058 |
|
---|
1059 |
/* multichannel receive */ |
---|
1060 |
#if 0 |
---|
1061 |
IsoRecvHandler::IsoRecvHandler(int port) |
---|
1062 |
: IsoHandler(port) |
---|
1063 |
{ |
---|
1064 |
debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
1065 |
} |
---|
1066 |
IsoRecvHandler::IsoRecvHandler(int port, unsigned int buf_packets, |
---|
1067 |
unsigned int max_packet_size, int irq) |
---|
1068 |
: IsoHandler(port, buf_packets,max_packet_size,irq) |
---|
1069 |
{ |
---|
1070 |
debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
1071 |
|
---|
1072 |
} |
---|
1073 |
IsoRecvHandler::~IsoRecvHandler() |
---|
1074 |
{ |
---|
1075 |
// Don't call until libraw1394's raw1394_new_handle() function has been |
---|
1076 |
// fixed to correctly initialise the iso_packet_infos field. Bug is |
---|
1077 |
// confirmed present in libraw1394 1.2.1. In any case, |
---|
1078 |
// raw1394_destroy_handle() (in the base class destructor) will do any iso |
---|
1079 |
// system shutdown required. |
---|
1080 |
raw1394_iso_shutdown(m_handle); |
---|
1081 |
|
---|
1082 |
} |
---|
1083 |
|
---|
1084 |
bool |
---|
1085 |
IsoRecvHandler::initialize() { |
---|
1086 |
debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
1087 |
|
---|
1088 |
IsoHandler *base=static_cast<IsoHandler *>(this); |
---|
1089 |
|
---|
1090 |
if(!(base->initialize())) { |
---|
1091 |
return false; |
---|
1092 |
} |
---|
1093 |
|
---|
1094 |
raw1394_set_userdata(m_handle, static_cast<void *>(this)); |
---|
1095 |
|
---|
1096 |
if(raw1394_iso_multichannel_recv_init(m_handle, |
---|
1097 |
iso_receive_handler, |
---|
1098 |
m_buf_packets, |
---|
1099 |
m_max_packet_size, |
---|
1100 |
m_irq_interval)) { |
---|
1101 |
debugFatal("Could not do multichannel receive initialisation!\n" ); |
---|
1102 |
|
---|
1103 |
return false; |
---|
1104 |
} |
---|
1105 |
|
---|
1106 |
return true; |
---|
1107 |
|
---|
1108 |
} |
---|
1109 |
|
---|
1110 |
enum raw1394_iso_disposition IsoRecvHandler::putPacket(unsigned char *data, unsigned int length, |
---|
1111 |
unsigned char channel, unsigned char tag, unsigned char sy, |
---|
1112 |
unsigned int cycle, unsigned int dropped) { |
---|
1113 |
|
---|
1114 |
debugOutput( DEBUG_LEVEL_VERY_VERBOSE, |
---|
1115 |
"received packet: length=%d, channel=%d, cycle=%d\n", |
---|
1116 |
length, channel, cycle ); |
---|
1117 |
|
---|
1118 |
return RAW1394_ISO_OK; |
---|
1119 |
} |
---|
1120 |
|
---|
1121 |
// an recv handler can have multiple destination IsoStreams |
---|
1122 |
// NOTE: this implementation even allows for already registered |
---|
1123 |
// streams to be registered again. |
---|
1124 |
int IsoRecvHandler::registerStream(IsoRecvStream *stream) |
---|
1125 |
{ |
---|
1126 |
assert(stream); |
---|
1127 |
debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
1128 |
|
---|
1129 |
m_Clients.push_back(stream); |
---|
1130 |
|
---|
1131 |
listen(stream->getChannel()); |
---|
1132 |
return 0; |
---|
1133 |
|
---|
1134 |
} |
---|
1135 |
|
---|
1136 |
int IsoRecvHandler::unregisterStream(IsoRecvStream *stream) |
---|
1137 |
{ |
---|
1138 |
assert(stream); |
---|
1139 |
debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
1140 |
|
---|
1141 |
for ( IsoRecvStreamVectorIterator it = m_Clients.begin(); |
---|
1142 |
it != m_Clients.end(); |
---|
1143 |
++it ) |
---|
1144 |
{ |
---|
1145 |
IsoRecvStream* s = *it; |
---|
1146 |
if ( s == stream ) { |
---|
1147 |
unListen(s->getChannel()); |
---|
1148 |
m_Clients.erase(it); |
---|
1149 |
return 0; |
---|
1150 |
} |
---|
1151 |
} |
---|
1152 |
|
---|
1153 |
return -1; //not found |
---|
1154 |
|
---|
1155 |
} |
---|
1156 |
|
---|
1157 |
void IsoRecvHandler::listen(int channel) { |
---|
1158 |
int retval; |
---|
1159 |
debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
1160 |
|
---|
1161 |
retval=raw1394_iso_recv_listen_channel(m_handle, channel); |
---|
1162 |
|
---|
1163 |
} |
---|
1164 |
|
---|
1165 |
void IsoRecvHandler::unListen(int channel) { |
---|
1166 |
int retval; |
---|
1167 |
debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
1168 |
|
---|
1169 |
retval=raw1394_iso_recv_unlisten_channel(m_handle, channel); |
---|
1170 |
|
---|
1171 |
} |
---|
1172 |
|
---|
1173 |
int IsoRecvHandler::start(int cycle) |
---|
1174 |
{ |
---|
1175 |
debugOutput( DEBUG_LEVEL_VERBOSE, "enter...\n"); |
---|
1176 |
return raw1394_iso_recv_start(m_handle, cycle, -1, 0); |
---|
1177 |
} |
---|
1178 |
#endif |
---|