root/branches/streaming-rework/src/libfreebobavc/ieee1394service.cpp

Revision 411, 16.7 kB (checked in by pieterpalmers, 16 years ago)

cycletimer.h:
- some extra operations on Ticks (diffTicks & substractTicks)

StreamProcessor?.cpp
AmdtpStreamProcessor?.cpp
MotuStreamProcessor?.cpp:
- Moved the syncDelay to StreamProcessor::getTimeUntilNextPeriodSignalUsecs(). This delay should be the delay between the actual period boundary and the time it is reported to the SPManager. Therefore it's place is not as a buffer offset, but in the calculation of the signalling time.
This makes that the buffer timestamps correspond to 'real' timestamps. These might have to be manipulated by the transmit or receive handles to account for e.g. iso buffering etc..., but at least the timestamps themselves have a well-defined meaning now.

StreamProcessorManager?.cpp:
- The only stream that needs to be running is the sync source stream. It is assumed that the other streams start running in time. 'In time' is currently about 2000 cycles afterwards.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /* ieee1394service.cpp
2  * Copyright (C) 2005,07 by Daniel Wagner
3  * Copyright (C) 2007 by Pieter Palmers
4  *
5  * This file is part of FreeBoB.
6  *
7  * FreeBoB is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  * FreeBoB is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with FreeBoB; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19  * MA 02111-1307 USA.
20  */
21 #include "ieee1394service.h"
22
23 #include <libavc1394/avc1394.h>
24 #include <libraw1394/csr.h>
25 #include <libiec61883/iec61883.h>
26
27 #include <errno.h>
28 #include <netinet/in.h>
29
30 #include "string.h"
31
32 #include <iostream>
33 #include <iomanip>
34
35 IMPL_DEBUG_MODULE( Ieee1394Service, Ieee1394Service, DEBUG_LEVEL_VERBOSE );
36
37 Ieee1394Service::Ieee1394Service()
38     : m_handle( 0 ), m_resetHandle( 0 )
39     , m_port( -1 )
40     , m_threadRunning( false )
41 {
42     pthread_mutex_init( &m_mutex, 0 );
43    
44     for (unsigned int i=0; i<64; i++) {
45         m_channels[i].channel=-1;
46         m_channels[i].bandwidth=-1;
47         m_channels[i].alloctype=AllocFree;
48         m_channels[i].xmit_node=0xFFFF;
49         m_channels[i].xmit_plug=-1;
50         m_channels[i].recv_node=0xFFFF;
51         m_channels[i].recv_plug=-1;
52     }
53 }
54
55 Ieee1394Service::~Ieee1394Service()
56 {
57     stopRHThread();
58
59     if ( m_handle ) {
60         raw1394_destroy_handle( m_handle );
61     }
62     if ( m_resetHandle ) {
63         raw1394_destroy_handle( m_resetHandle );
64     }
65 }
66
67 bool
68 Ieee1394Service::initialize( int port )
69 {
70     using namespace std;
71
72     m_handle = raw1394_new_handle_on_port( port );
73     if ( !m_handle ) {
74         if ( !errno ) {
75             debugFatal("libraw1394 not compatible\n");
76         } else {
77             debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s",
78                 strerror(errno) );
79             debugFatal("Is ieee1394 and raw1394 driver loaded?\n");
80         }
81         return false;
82     }
83
84     m_resetHandle = raw1394_new_handle_on_port( port );
85     if ( !m_handle ) {
86         if ( !errno ) {
87             debugFatal("libraw1394 not compatible\n");
88         } else {
89             debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s",
90                 strerror(errno) );
91             debugFatal("Is ieee1394 and raw1394 driver loaded?\n");
92         }
93         return false;
94     }
95
96     m_port = port;
97
98     raw1394_set_userdata( m_handle, this );
99     raw1394_set_userdata( m_resetHandle, this );
100     raw1394_set_bus_reset_handler( m_resetHandle,
101                                    this->resetHandlerLowLevel );
102     startRHThread();
103
104     return true;
105 }
106
107 int
108 Ieee1394Service::getNodeCount()
109 {
110     return raw1394_get_nodecount( m_handle );
111 }
112
113 nodeid_t Ieee1394Service::getLocalNodeId() {
114     return raw1394_get_local_id(m_handle) & 0x3F;
115 }
116
117 bool
118 Ieee1394Service::read( fb_nodeid_t nodeId,
119                        fb_nodeaddr_t addr,
120                        size_t length,
121                        fb_quadlet_t* buffer )
122 {
123     using namespace std;
124     if ( raw1394_read( m_handle, nodeId, addr, length*4, buffer ) == 0 ) {
125
126         #ifdef DEBUG
127         debugOutput(DEBUG_LEVEL_VERY_VERBOSE,
128             "read: node 0x%X, addr = 0x%016llX, length = %u\n",
129             nodeId, addr, length);
130         printBuffer( length, buffer );
131         #endif
132
133         return true;
134     } else {
135         #ifdef DEBUG
136         debugError("raw1394_read failed: node 0x%X, addr = 0x%016llX, length = %u\n",
137               nodeId, addr, length);
138         #endif
139
140         return false;
141     }
142 }
143
144
145 bool
146 Ieee1394Service::read_quadlet( fb_nodeid_t nodeId,
147                                fb_nodeaddr_t addr,
148                                fb_quadlet_t* buffer )
149 {
150     return read( nodeId,  addr, sizeof( *buffer )/4, buffer );
151 }
152
153 bool
154 Ieee1394Service::read_octlet( fb_nodeid_t nodeId,
155                               fb_nodeaddr_t addr,
156                               fb_octlet_t* buffer )
157 {
158     return read( nodeId, addr, sizeof( *buffer )/4,
159                  reinterpret_cast<fb_quadlet_t*>( buffer ) );
160 }
161
162
163 bool
164 Ieee1394Service::write( fb_nodeid_t nodeId,
165                         fb_nodeaddr_t addr,
166                         size_t length,
167                         fb_quadlet_t* data )
168 {
169     using namespace std;
170
171     #ifdef DEBUG
172     debugOutput(DEBUG_LEVEL_VERY_VERBOSE,"write: node 0x%X, addr = 0x%016X, length = %d\n",
173                 nodeId, addr, length);
174     printBuffer( length, data );
175     #endif
176
177     return raw1394_write( m_handle, nodeId, addr, length*4, data ) == 0;
178 }
179
180
181 bool
182 Ieee1394Service::write_quadlet( fb_nodeid_t nodeId,
183                                 fb_nodeaddr_t addr,
184                                 fb_quadlet_t data )
185 {
186     return write( nodeId, addr, sizeof( data )/4, &data );
187 }
188
189 bool
190 Ieee1394Service::write_octlet( fb_nodeid_t nodeId,
191                                fb_nodeaddr_t addr,
192                                fb_octlet_t data )
193 {
194     return write( nodeId, addr, sizeof( data )/4,
195                   reinterpret_cast<fb_quadlet_t*>( &data ) );
196 }
197
198 fb_quadlet_t*
199 Ieee1394Service::transactionBlock( fb_nodeid_t nodeId,
200                                    fb_quadlet_t* buf,
201                                    int len,
202                                    unsigned int* resp_len )
203 {
204     for (int i = 0; i < len; ++i) {
205         buf[i] = ntohl( buf[i] );
206     }
207
208     #ifdef DEBUG
209     debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "  pre avc1394_transaction_block2\n" );
210     printBuffer( len, buf );
211     #endif
212
213     fb_quadlet_t* result =
214         avc1394_transaction_block2( m_handle,
215                                     nodeId,
216                                     buf,
217                                     len,
218                                     resp_len,
219                                     10 );
220
221     #ifdef DEBUG
222     debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "  post avc1394_transaction_block2\n" );
223     printBuffer( *resp_len, result );
224     #endif
225
226     for ( unsigned int i = 0; i < *resp_len; ++i ) {
227         result[i] = htonl( result[i] );
228     }
229
230     return result;
231 }
232
233
234 bool
235 Ieee1394Service::transactionBlockClose()
236 {
237     avc1394_transaction_block_close( m_handle );
238     return true;
239 }
240
241 bool
242 Ieee1394Service::setVerbose( int verboseLevel )
243 {
244     setDebugLevel(verboseLevel);
245     return true;
246 }
247
248 int
249 Ieee1394Service::getVerboseLevel()
250 {
251     return getDebugLevel();
252 }
253
254 void
255 Ieee1394Service::printBuffer( size_t length, fb_quadlet_t* buffer ) const
256 {
257
258     for ( unsigned int i=0; i < length; ++i ) {
259         if ( ( i % 4 ) == 0 ) {
260             if ( i > 0 ) {
261                 debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE,"\n");
262             }
263             debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE," %4d: ",i*4);
264         }
265         debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE,"%08X ",buffer[i]);
266     }
267     debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE,"\n");
268 }
269
270 int
271 Ieee1394Service::resetHandlerLowLevel( raw1394handle_t handle,
272                                        unsigned int generation )
273 {
274     raw1394_update_generation ( handle, generation );
275     Ieee1394Service* instance
276         = (Ieee1394Service*) raw1394_get_userdata( handle );
277     instance->resetHandler( generation );
278
279     return 0;
280 }
281
282 bool
283 Ieee1394Service::resetHandler( unsigned int generation )
284 {
285     m_generation = generation;
286
287     for ( reset_handler_vec_t::iterator it = m_busResetHandlers.begin();
288           it != m_busResetHandlers.end();
289           ++it )
290     {
291         Functor* func = *it;
292         ( *func )();
293     }
294
295     return true;
296 }
297
298 bool
299 Ieee1394Service::startRHThread()
300 {
301     int i;
302
303     if ( m_threadRunning ) {
304         return true;
305     }
306     pthread_mutex_lock( &m_mutex );
307     i = pthread_create( &m_thread, 0, rHThread, this );
308     pthread_mutex_unlock( &m_mutex );
309     if (i) {
310         debugFatal("Could not start ieee1394 service thread\n");
311         return false;
312     }
313     m_threadRunning = true;
314
315     return true;
316 }
317
318 void
319 Ieee1394Service::stopRHThread()
320 {
321     if ( m_threadRunning ) {
322         pthread_mutex_lock (&m_mutex);
323         pthread_cancel (m_thread);
324         pthread_join (m_thread, 0);
325         pthread_mutex_unlock (&m_mutex);
326         m_threadRunning = false;
327     }
328 }
329
330 void*
331 Ieee1394Service::rHThread( void* arg )
332 {
333     Ieee1394Service* pIeee1394Service = (Ieee1394Service*) arg;
334
335     while (true) {
336         raw1394_loop_iterate (pIeee1394Service->m_resetHandle);
337         pthread_testcancel ();
338     }
339
340     return 0;
341 }
342
343 bool
344 Ieee1394Service::addBusResetHandler( Functor* functor )
345 {
346     m_busResetHandlers.push_back( functor );
347     return true;
348 }
349
350 bool
351 Ieee1394Service::remBusResetHandler( Functor* functor )
352 {
353     for ( reset_handler_vec_t::iterator it = m_busResetHandlers.begin();
354           it != m_busResetHandlers.end();
355           ++it )
356     {
357         if ( *it == functor ) {
358             m_busResetHandlers.erase( it );
359             return true;
360         }
361     }
362     return false;
363 }
364
365 /**
366  * Allocates an iso channel for use by the interface in a similar way to
367  * libiec61883.  Returns -1 on error (due to there being no free channels)
368  * or an allocated channel number.
369  *
370  * Does not perform anything other than registering the channel and the
371  * bandwidth at the IRM
372  *
373  * Also allocates the necessary bandwidth (in ISO allocation units).
374  *
375  * FIXME: As in libiec61883, channel 63 is not requested; this is either a
376  * bug or it's omitted since that's the channel preferred by video devices.
377  *
378  * @param bandwidth the bandwidth to allocate for this channel
379  * @return the channel number
380  */
381 signed int Ieee1394Service::allocateIsoChannelGeneric(unsigned int bandwidth) {
382     debugOutput(DEBUG_LEVEL_VERBOSE, "Allocating ISO channel using generic method...\n" );
383    
384     struct ChannelInfo cinfo;
385
386     int c = -1;
387     for (c = 0; c < 63; c++) {
388         if (raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_ALLOC) == 0)
389             break;
390     }
391     if (c < 63) {
392         if (raw1394_bandwidth_modify(m_handle, bandwidth, RAW1394_MODIFY_ALLOC) < 0) {
393             debugFatal("Could not allocate bandwidth of %d\n", bandwidth);
394            
395             raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_FREE);
396             return -1;
397         } else {
398             cinfo.channel=c;
399             cinfo.bandwidth=bandwidth;
400             cinfo.alloctype=AllocGeneric;
401            
402             if (registerIsoChannel(c, cinfo)) {
403                 return c;
404             } else {
405                 raw1394_bandwidth_modify(m_handle, bandwidth, RAW1394_MODIFY_FREE);
406                 raw1394_channel_modify (m_handle, c, RAW1394_MODIFY_FREE);
407                 return -1;
408             }
409         }
410     }
411     return -1;
412 }
413
414 /**
415  * Allocates an iso channel for use by the interface in a similar way to
416  * libiec61883.  Returns -1 on error (due to there being no free channels)
417  * or an allocated channel number.
418  *
419  * Uses IEC61883 Connection Management Procedure to establish the connection.
420  *
421  * Also allocates the necessary bandwidth (in ISO allocation units).
422  *
423  * @param xmit_node  node id of the transmitter
424  * @param xmit_plug  the output plug to use. If -1, find the first online plug, and
425  * upon return, contains the plug number used.
426  * @param recv_node  node id of the receiver
427  * @param recv_plug the input plug to use. If -1, find the first online plug, and
428  * upon return, contains the plug number used.
429  *
430  * @return the channel number
431  */
432
433 signed int Ieee1394Service::allocateIsoChannelCMP(
434     nodeid_t xmit_node, int xmit_plug,
435     nodeid_t recv_node, int recv_plug
436     ) {
437
438     debugOutput(DEBUG_LEVEL_VERBOSE, "Allocating ISO channel using IEC61883 CMP...\n" );
439    
440     struct ChannelInfo cinfo;
441    
442     int c = -1;
443     int bandwidth=1;
444    
445     // do connection management: make connection
446     c = iec61883_cmp_connect(
447         m_handle,
448         xmit_node | 0xffc0,
449         &xmit_plug,
450         recv_node | 0xffc0,
451         &recv_plug,
452         &bandwidth);
453
454     if((c<0) || (c>63)) {
455         debugError("Could not do CMP from %04X:%02d to %04X:%02d\n",
456             xmit_node, xmit_plug, recv_node, recv_plug
457             );
458         return -1;
459     }
460
461     cinfo.channel=c;
462     cinfo.bandwidth=bandwidth;
463     cinfo.alloctype=AllocCMP;
464    
465     cinfo.xmit_node=xmit_node;
466     cinfo.xmit_plug=xmit_plug;
467     cinfo.recv_node=recv_node;
468     cinfo.recv_plug=recv_plug;
469        
470     if (registerIsoChannel(c, cinfo)) {
471         return c;
472     }
473
474     return -1;
475 }
476
477 /**
478  * Deallocates an iso channel.  Silently ignores a request to deallocate
479  * a negative channel number.
480  *
481  * Figures out the method that was used to allocate the channel (generic, cmp, ...)
482  * and uses the appropriate method to deallocate. Also frees the bandwidth
483  * that was reserved along with this channel.
484  *
485  * @param c channel number
486  * @return true if successful
487  */
488 bool Ieee1394Service::freeIsoChannel(signed int c) {
489     debugOutput(DEBUG_LEVEL_VERBOSE, "Freeing ISO channel %d...\n", c );
490    
491     if (c < 0 || c > 63) {
492         debugWarning("Invalid channel number: %d\n", c);
493         return false;
494     }
495    
496     switch (m_channels[c].alloctype) {
497         default:
498             debugError(" BUG: invalid allocation type!\n");
499             return false;
500            
501         case AllocFree:
502             debugWarning(" Channel %d not registered\n", c);
503             return false;
504            
505         case AllocGeneric:
506             debugOutput(DEBUG_LEVEL_VERBOSE, " allocated using generic routine...\n" );
507             if (unregisterIsoChannel(c)) {
508                 return false;
509             } else {
510                 debugOutput(DEBUG_LEVEL_VERBOSE, " freeing %d bandwidth units...\n", m_channels[c].bandwidth );
511                 if (raw1394_bandwidth_modify(m_handle, m_channels[c].bandwidth, RAW1394_MODIFY_FREE) !=0) {
512                     debugWarning("Failed to deallocate bandwidth\n");
513                 }
514                 debugOutput(DEBUG_LEVEL_VERBOSE, " freeing channel %d...\n", m_channels[c].channel );
515                 if (raw1394_channel_modify (m_handle, m_channels[c].channel, RAW1394_MODIFY_FREE) != 0) {
516                     debugWarning("Failed to free channel\n");
517                 }
518                 return true;
519             }
520            
521         case AllocCMP:
522             debugOutput(DEBUG_LEVEL_VERBOSE, " allocated using IEC61883 CMP...\n" );
523             if (unregisterIsoChannel(c)) {
524                 return false;
525             } else {
526                 debugOutput(DEBUG_LEVEL_VERBOSE, " performing IEC61883 CMP disconnect...\n" );
527                 if(iec61883_cmp_disconnect(
528                         m_handle,
529                         m_channels[c].xmit_node | 0xffc0,
530                         m_channels[c].xmit_plug,
531                         m_channels[c].recv_node | 0xffc0,
532                         m_channels[c].recv_plug,
533                         m_channels[c].channel,
534                         m_channels[c].bandwidth) != 0) {
535                     debugWarning("Could not do CMP disconnect for channel %d!\n",c);
536                 }
537             }
538             return true;
539     }
540    
541     // unreachable
542     debugError("BUG: unreachable code reached!\n");
543    
544     return false;
545 }
546
547 /**
548  * Registers a channel as managed by this ieee1394service
549  * @param c channel number
550  * @param cinfo channel info struct
551  * @return true if successful
552  */
553 bool Ieee1394Service::registerIsoChannel(unsigned int c, struct ChannelInfo cinfo) {
554     if (c < 63) {
555         if (m_channels[c].alloctype != AllocFree) {
556             debugWarning("Channel %d already registered with bandwidth %d\n",
557                 m_channels[c].channel, m_channels[c].bandwidth);
558         }
559        
560         memcpy(&m_channels[c], &cinfo, sizeof(struct ChannelInfo));
561        
562     } else return false;
563     return true;
564 }
565
566 /**
567  * unegisters a channel from this ieee1394service
568  * @param c channel number
569  * @return true if successful
570  */
571 bool Ieee1394Service::unregisterIsoChannel(unsigned int c) {
572     if (c < 63) {
573         if (m_channels[c].alloctype == AllocFree) {
574             debugWarning("Channel %d not registered\n", c);
575             return false;
576         }
577        
578         m_channels[c].channel=-1;
579         m_channels[c].bandwidth=-1;
580         m_channels[c].alloctype=AllocFree;
581         m_channels[c].xmit_node=0xFFFF;
582         m_channels[c].xmit_plug=-1;
583         m_channels[c].recv_node=0xFFFF;
584         m_channels[c].recv_plug=-1;
585        
586     } else return false;
587     return true;
588 }
589
590 /**
591  * Returns the current value of the `bandwidth available' register on
592  * the IRM, or -1 on error.
593  * @return
594  */
595 signed int Ieee1394Service::getAvailableBandwidth() {
596     quadlet_t buffer;
597     signed int result = raw1394_read (m_handle, raw1394_get_irm_id (m_handle),
598         CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE,
599         sizeof (quadlet_t), &buffer);
600
601     if (result < 0)
602         return -1;
603     return ntohl(buffer);
604 }
Note: See TracBrowser for help on using the browser.