IsoHandler::getPacket(): when keeping tabs of the last cycle, allow for cases where...
[ffado.git] / libffado / src / libieee1394 / IsoHandlerManager.h
blobaf6a14b5d399210238c7f4c1a8d1f3c7872552c6
1 /*
2 * Copyright (C) 2005-2008 by Pieter Palmers
4 * This file is part of FFADO
5 * FFADO = Free Firewire (pro-)audio drivers for linux
7 * FFADO is based upon FreeBoB.
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) version 3 of the License.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #ifndef __FFADO_ISOHANDLERMANAGER__
25 #define __FFADO_ISOHANDLERMANAGER__
27 #include "config.h"
29 #include "debugmodule/debugmodule.h"
31 #include "libutil/Thread.h"
33 #include <sys/poll.h>
34 #include <errno.h>
35 #include <vector>
36 #include <semaphore.h>
38 class Ieee1394Service;
39 //class IsoHandler;
40 //enum IsoHandler::EHandlerType;
42 namespace Streaming {
43 class StreamProcessor;
44 typedef std::vector<StreamProcessor *> StreamProcessorVector;
45 typedef std::vector<StreamProcessor *>::iterator StreamProcessorVectorIterator;
48 /*!
49 \brief The ISO Handler management class
51 This class manages the use of ISO handlers by ISO streams.
52 You can register an Streaming::StreamProcessor with an IsoHandlerManager. This
53 manager will assign an IsoHandler to the stream. If nescessary
54 the manager allocates a new handler. If there is already a handler
55 that can handle the Streaming::StreamProcessor (e.g. in case of multichannel receive),
56 it can be assigned.
60 class IsoHandlerManager
62 friend class IsoTask;
64 ////
65 /*!
66 \brief The Base Class for ISO Handlers
68 These classes perform the actual ISO communication through libraw1394.
69 They are different from Streaming::StreamProcessors because one handler can provide multiple
70 streams with packets in case of ISO multichannel receive.
74 class IsoHandler
76 public:
77 enum EHandlerType {
78 eHT_Receive,
79 eHT_Transmit
81 IsoHandler(IsoHandlerManager& manager, enum EHandlerType t);
82 IsoHandler(IsoHandlerManager& manager, enum EHandlerType t,
83 unsigned int buf_packets, unsigned int max_packet_size, int irq);
84 IsoHandler(IsoHandlerManager& manager, enum EHandlerType t,
85 unsigned int buf_packets, unsigned int max_packet_size, int irq, enum raw1394_iso_speed speed);
86 ~IsoHandler();
88 private: // the ISO callback interface
89 static enum raw1394_iso_disposition
90 iso_receive_handler(raw1394handle_t handle, unsigned char *data,
91 unsigned int length, unsigned char channel,
92 unsigned char tag, unsigned char sy, unsigned int cycle,
93 unsigned int dropped);
95 enum raw1394_iso_disposition
96 putPacket(unsigned char *data, unsigned int length,
97 unsigned char channel, unsigned char tag, unsigned char sy,
98 unsigned int cycle, unsigned int dropped);
100 static enum raw1394_iso_disposition iso_transmit_handler(raw1394handle_t handle,
101 unsigned char *data, unsigned int *length,
102 unsigned char *tag, unsigned char *sy,
103 int cycle, unsigned int dropped);
104 enum raw1394_iso_disposition
105 getPacket(unsigned char *data, unsigned int *length,
106 unsigned char *tag, unsigned char *sy,
107 int cycle, unsigned int dropped, unsigned int skipped);
109 public:
112 * Iterate the handler, transporting ISO packets to the client(s)
113 * @return true if success
115 bool iterate();
118 * Iterate the handler, transporting ISO packets to the client(s)
119 * @param ctr_now the CTR time at which the iterate call is done.
120 * @return true if success
122 bool iterate(uint32_t ctr_now);
124 int getFileDescriptor() { return raw1394_get_fd(m_handle);};
126 bool init();
127 void setVerboseLevel(int l);
129 // the enable/disable functions should only be used from within the loop that iterates()
130 // but not from within the iterate callback. use the requestEnable / requestDisable functions
131 // for that
132 bool enable() {return enable(-1);};
133 bool enable(int cycle);
134 bool disable();
136 // functions to request enable or disable at the next opportunity
137 bool requestEnable(int cycle = -1);
138 bool requestDisable();
140 // Manually set the start cycle for the iso handler
141 void setIsoStartCycle(signed int cycle = -1);
144 * updates the internal state if required
146 void updateState();
148 enum EHandlerType getType() {return m_type;};
149 const char *getTypeString() {return eHTToString(m_type); };
151 // pretty printing
152 const char *eHTToString(enum EHandlerType);
154 bool isEnabled()
155 {return m_State == eHS_Running;};
157 // no setter functions, because those would require a re-init
158 unsigned int getMaxPacketSize() { return m_max_packet_size;};
159 unsigned int getNbBuffers() { return m_buf_packets;};
160 int getIrqInterval() { return m_irq_interval;};
162 void dumpInfo();
164 bool inUse() {return (m_Client != 0) ;};
165 bool isStreamRegistered(Streaming::StreamProcessor *s) {return (m_Client == s);};
167 bool registerStream(Streaming::StreamProcessor *);
168 bool unregisterStream(Streaming::StreamProcessor *);
170 bool canIterateClient(); // FIXME: implement with functor
174 * @brief get last cycle number seen by handler
175 * @return cycle number
177 int getLastCycle() {return m_last_cycle;};
180 * @brief returns the CTR value saved at the last iterate() call
181 * @return CTR value saved at last iterate() call
183 uint32_t getLastIterateTime() {return m_last_now;};
186 * @brief returns the CTR value saved at the last iterate handler call
187 * @return CTR value saved at last iterate handler call
189 uint32_t getLastPacketTime() {return m_last_packet_handled_at;};
192 * @brief set iso receive mode. doesn't have any effect if the stream is running
193 * @param m receive mode
195 void setReceiveMode(enum raw1394_iso_dma_recv_mode m)
196 {m_receive_mode = m;}
198 void notifyOfDeath();
199 bool handleBusReset();
201 private:
202 IsoHandlerManager& m_manager;
203 enum EHandlerType m_type;
204 raw1394handle_t m_handle;
205 unsigned int m_buf_packets;
206 unsigned int m_max_packet_size;
207 int m_irq_interval;
208 int m_last_cycle;
209 uint32_t m_last_now;
210 uint32_t m_last_packet_handled_at;
211 enum raw1394_iso_dma_recv_mode m_receive_mode;
213 Streaming::StreamProcessor *m_Client; // FIXME: implement with functors
215 enum raw1394_iso_speed m_speed;
217 // the state machine
218 enum EHandlerStates {
219 eHS_Stopped,
220 eHS_Running,
221 eHS_Error,
223 enum EHandlerStates m_State;
224 enum EHandlerStates m_NextState;
225 int m_switch_on_cycle;
227 pthread_mutex_t m_disable_lock;
229 public:
230 unsigned int m_packets;
231 #ifdef DEBUG
232 unsigned int m_dropped;
233 unsigned int m_skipped;
234 int m_min_ahead;
235 #endif
236 unsigned int m_deferred_cycles;
238 protected:
239 DECLARE_DEBUG_MODULE;
242 typedef std::vector<IsoHandler *> IsoHandlerVector;
243 typedef std::vector<IsoHandler *>::iterator IsoHandlerVectorIterator;
245 ////
247 // threads that will handle the packet framing
248 // one thread per direction, as a compromise for one per
249 // channel and one for all
250 class IsoTask : public Util::RunnableInterface
252 friend class IsoHandlerManager;
253 public:
254 IsoTask(IsoHandlerManager& manager, enum IsoHandler::EHandlerType);
255 virtual ~IsoTask();
257 private:
258 bool Init();
259 bool Execute();
262 * @brief requests the thread to sync it's stream map with the manager
264 void requestShadowMapUpdate();
265 enum eActivityResult {
266 eAR_Activity,
267 eAR_Timeout,
268 eAR_Interrupted,
269 eAR_Error
273 * @brief signals that something happened in one of the clients of this task
275 void signalActivity();
277 * @brief wait until something happened in one of the clients of this task
279 enum eActivityResult waitForActivity();
282 * @brief This should be called when a busreset has happened.
284 bool handleBusReset();
286 void setVerboseLevel(int i);
288 protected:
289 IsoHandlerManager& m_manager;
291 // the event request structure
292 int32_t request_update;
294 // static allocation due to RT constraints
295 // this is the map used by the actual thread
296 // it is a shadow of the m_StreamProcessors vector
297 struct pollfd m_poll_fds_shadow[ISOHANDLERMANAGER_MAX_ISO_HANDLERS_PER_PORT];
298 IsoHandler * m_IsoHandler_map_shadow[ISOHANDLERMANAGER_MAX_ISO_HANDLERS_PER_PORT];
299 unsigned int m_poll_nfds_shadow;
300 IsoHandler * m_SyncIsoHandler;
302 // updates the streams map
303 void updateShadowMapHelper();
305 #ifdef DEBUG
306 uint64_t m_last_loop_entry;
307 int m_successive_short_loops;
308 #endif
310 enum IsoHandler::EHandlerType m_handlerType;
311 bool m_running;
312 bool m_in_busreset;
314 // activity signaling
315 sem_t m_activity_semaphore;
316 long long int m_activity_wait_timeout_nsec;
318 // debug stuff
319 DECLARE_DEBUG_MODULE;
322 //// the IsoHandlerManager itself
323 public:
325 IsoHandlerManager(Ieee1394Service& service);
326 IsoHandlerManager(Ieee1394Service& service, bool run_rt, int rt_prio);
327 virtual ~IsoHandlerManager();
329 bool setThreadParameters(bool rt, int priority);
331 void setVerboseLevel(int l); ///< set the verbose level
333 void dumpInfo(); ///< print some information about the manager to stdout/stderr
334 void dumpInfoForStream(Streaming::StreamProcessor *); ///< print some info about the stream's handler
336 bool registerStream(Streaming::StreamProcessor *); ///< register an iso stream with the manager
337 bool unregisterStream(Streaming::StreamProcessor *); ///< unregister an iso stream from the manager
339 bool startHandlers(); ///< start the managed ISO handlers
340 bool startHandlers(int cycle); ///< start the managed ISO handlers
341 bool stopHandlers(); ///< stop the managed ISO handlers
343 bool reset(); ///< reset the ISO manager and all streams
344 bool init();
347 * @brief signals that something happened in one of the clients
349 void signalActivityTransmit();
350 void signalActivityReceive();
352 ///> disables the handler attached to the stream
353 bool stopHandlerForStream(Streaming::StreamProcessor *);
354 ///> starts the handler attached to the specific stream
355 bool startHandlerForStream(Streaming::StreamProcessor *);
356 ///> starts the handler attached to the specific stream on a specific cycle
357 bool startHandlerForStream(Streaming::StreamProcessor *, int cycle);
359 ///> Directly tells the handler attached to the stream to start on
360 ///> the given cycle regardless of what is passed to
361 ///> startHandlerForStream().
362 void setIsoStartCycleForStream(Streaming::StreamProcessor *stream, signed int cycle);
365 * returns the latency of a wake-up for this stream.
366 * The latency is the time it takes for a packet is delivered to the
367 * stream after it has been received (was on the wire).
368 * expressed in cycles
370 int getPacketLatencyForStream(Streaming::StreamProcessor *);
373 * Enables the isohandler manager to ignore missed packets. This
374 * behaviour is needed by some interfaces which don't send empty
375 * placeholder packets when no data needs to be sent.
377 void setMissedCyclesOK(bool ok) { m_MissedCyclesOK = ok; };
379 private:
380 IsoHandler * getHandlerForStream(Streaming::StreamProcessor *stream);
381 void requestShadowMapUpdate();
382 public:
383 Ieee1394Service& get1394Service() {return m_service;};
386 * This should be called when a busreset has happened.
388 bool handleBusReset();
390 // the state machine
391 private:
392 enum eHandlerStates {
393 E_Created,
394 E_Prepared,
395 E_Running,
396 E_Error
399 enum eHandlerStates m_State;
400 const char *eHSToString(enum eHandlerStates);
402 private:
403 Ieee1394Service& m_service;
404 // note: there is a disctinction between streams and handlers
405 // because one handler can serve multiple streams (in case of
406 // multichannel receive)
408 // only streams are allowed to be registered externally.
409 // we allocate a handler if we need one, otherwise the stream
410 // is assigned to another handler
412 // the collection of handlers
413 IsoHandlerVector m_IsoHandlers;
415 bool registerHandler(IsoHandler *);
416 bool unregisterHandler(IsoHandler *);
417 void pruneHandlers();
419 // the collection of streams
420 Streaming::StreamProcessorVector m_StreamProcessors;
422 // handler thread/task
423 bool m_realtime;
424 int m_priority;
425 Util::Thread * m_IsoThreadTransmit;
426 IsoTask * m_IsoTaskTransmit;
427 Util::Thread * m_IsoThreadReceive;
428 IsoTask * m_IsoTaskReceive;
430 bool m_MissedCyclesOK;
432 // debug stuff
433 DECLARE_DEBUG_MODULE;
437 #endif /* __FFADO_ISOHANDLERMANAGER__ */