1/*
2    File:       IrStream.cpp
3
4    Contains:   Implementation of the TIrStream base class
5
6
7*/
8
9#include "IrStream.h"
10#include "CList.h"
11#include "IrEvent.h"
12
13#if (hasTracing > 0 && hasIrStreamTracing > 0)
14
15enum {
16    kLogCreate = 1,
17    kLogFree,
18    kLogFreeQueue,
19    kLogInit,
20    kLogInit2,
21    kLogInit3,
22    kLogNewEventList,
23    kLogRetainEventList,
24    kLogEnqueue,
25    kLogEnqueueThis,
26    kLogEventRecordRun,
27
28    kLogCleanup1,
29    kLogCleanup2,
30
31    kGenericEnqueue,
32    kGenericDequeueStart,
33    kGenericDequeueEnd,
34
35
36				    // the order of these must match enum in IrEvent.h
37    kLogEventNamesStart,            // 0
38
39    kLogNameOutputComplete,         // 1
40    kLogNameInputComplete,          // 2
41
42    kLogNameDiscoverRequest,        // 3
43    kLogNameDiscoverReply,          // 4
44
45    kLogNameConnectRequest,         // 5
46    kLogNameConnectReply,           // 6
47
48    kLogNameListenRequest,          // 7
49    kLogNameListenReply,            // 8
50
51    kLogNameAcceptRequest,          // 9
52    kLogNameAcceptReply,            // a
53
54    kLogNameGetDataRequest,         // b
55    kLogNameGetDataReply,           // c
56
57    kLogNamePutDataRequest,         // d
58    kLogNamePutDataReply,           // e
59
60    kLogNameLookupRequest,          // f
61    kLogNameLookupReply,            // 10
62
63    kLogNameCancelGetRequest,       // 11
64    kLogNameCancelGetReply,         // 12
65
66    kLogNameCancelPutRequest,       // 13
67    kLogNameCancelPutReply,         // 14
68
69    kLogNameReleaseRequest,         // 15
70    kLogNameReleaseReply,           // 16
71
72    kLogNameDisconnectRequest,      // 17
73    kLogNameDisconnectReply,        // 18
74
75    kLogNameLocalBusy,              // 19
76    kLogNameLocalBusyClear,         // 1a
77
78    kLogNameLapTimers,              // 1b
79    kLogNameMediaBusyTimer,         // 1c
80    kLogNameSlotTimer,              // 1d
81    kLogNameQueryTimer,             // 1e
82    kLogNameBackoffTimer,           // 1f
83    kLogNameFinalTimer,             // 20
84    kLogNamePollTimer,              // 21
85    kLogNameWatchdogTimer,          // 22
86    kLogNameTurnaroundTimer,        // 23
87    kLogNameLastLapTimer,           // 24
88
89    kLogNameLMPTimers,              // 25
90    kLogNameConnWatchdogTimer,      // 26
91    kLogNameIdleDisconnectTimer,    // 27
92    kLogNameLastLMPTimer,           // 28
93
94    kLogNameChangeSpeedComplete     // 29
95
96
97};
98
99static
100EventTraceCauseDesc TraceEvents[] = {
101    {kLogCreate,            "IrStream: create, obj="},
102    {kLogFree,              "IrStream: free, obj="},
103    {kLogFreeQueue,         "IrStream: clist retain=, length="},
104    {kLogInit,              "IrStream: init, obj="},
105    {kLogInit2,             "IrStream: qtrace array="},
106    {kLogInit3,             "IrStream: qtrace index="},
107    {kLogNewEventList,      "IrStream: new clist, obj="},
108    {kLogRetainEventList,   "IrStream: clist retain, new count="},
109    {kLogEnqueue,           "IrStream: enqueue irevent="},
110    {kLogEnqueueThis,       "IrStream: enqueued for obj="},
111    {kLogEventRecordRun,    "IrStream: run of event record at"},
112
113    {kLogCleanup1,          "IrStream: nuking event queued for us on queue"},
114    {kLogCleanup2,          "IrStream: nuking event queued for us on fNextEvent"},
115
116    {kGenericEnqueue,       "IrStream: Generic Enqueue Event, event="},
117    {kGenericDequeueStart,  "IrStream: Generic Dequeue Event Start"},
118    {kGenericDequeueEnd,    "IrStream: Generic Dequeue Event Complete"},
119
120    {kLogEventNamesStart,       "IrStream: dummy"},                     // 0
121    {kLogNameOutputComplete,    "IrStream: output complete event"},     // 1
122    {kLogNameInputComplete,     "IrStream: input complete event"},      // 2
123
124    {kLogNameDiscoverRequest,   "IrStream: discover request event"},    // 3
125    {kLogNameDiscoverReply,     "IrStream: discover reply event"},      // 4
126
127    {kLogNameConnectRequest,    "IrStream: connect request event"},     // 5
128    {kLogNameConnectReply,      "IrStream: connect reply event"},       // 6
129
130    {kLogNameListenRequest,     "IrStream: listen request event"},      // 7
131    {kLogNameListenReply,       "IrStream: listen reply event"},        // 8
132
133    {kLogNameAcceptRequest,     "IrStream: accept request event"},      // 9
134    {kLogNameAcceptReply,       "IrStream: accept reply event"},        // a
135
136    {kLogNameGetDataRequest,    "IrStream: get data request event"},    // b
137    {kLogNameGetDataReply,      "IrStream: get data reply event"},      // c
138
139    {kLogNamePutDataRequest,    "IrStream: put data request event"},    // d
140    {kLogNamePutDataReply,      "IrStream: put data reply event"},      // e
141
142    {kLogNameLookupRequest,     "IrStream: lookup request event"},      // f
143    {kLogNameLookupReply,       "IrStream: lookup reply event"},        // 10
144
145    {kLogNameCancelGetRequest,  "IrStream: cancel get request event"},  // 11
146    {kLogNameCancelGetReply,    "IrStream: cancel get reply event"},    // 12
147
148    {kLogNameCancelPutRequest,  "IrStream: cancel put request event"},  // 13
149    {kLogNameCancelPutReply,    "IrStream: cancel put reply event"},    // 14
150
151    {kLogNameReleaseRequest,    "IrStream: release request event"},     // 15
152    {kLogNameReleaseReply,      "IrStream: release reply event"},       // 16
153
154    {kLogNameDisconnectRequest, "IrStream: disconnect request event"},  // 17
155    {kLogNameDisconnectReply,   "IrStream: disconnect reply event"},    // 18
156
157    {kLogNameLocalBusy,         "IrStream: local busy event"},          // 19
158    {kLogNameLocalBusyClear,    "IrStream: local busy clear event"},    // 1a
159
160    {kLogNameLapTimers,         "IrStream: lap timer"},                 // 1b
161    {kLogNameMediaBusyTimer,    "IrStream: media busy timer event"},    // 1c
162    {kLogNameSlotTimer,         "IrStream: slot timer event"},          // 1d
163    {kLogNameQueryTimer,        "IrStream: query timer event"},         // 1e
164    {kLogNameBackoffTimer,      "IrStream: backoff timer event"},       // 1f
165    {kLogNameFinalTimer,        "IrStream: final timer event"},         // 20
166    {kLogNamePollTimer,         "IrStream: poll timer event"},          // 21
167    {kLogNameWatchdogTimer,     "IrStream: watchdog timer event"},      // 22
168    {kLogNameTurnaroundTimer,   "IrStream: turnaround timer event"},    // 23
169    {kLogNameLastLapTimer,      "IrStream: last lap timer"},            // 24
170
171    {kLogNameLMPTimers,             "IrStream: lmp timers"},                    // 25
172    {kLogNameConnWatchdogTimer,     "IrStream: connection watchdog timer event"},   // 26
173    {kLogNameIdleDisconnectTimer,   "IrStream: idle disconnect timer event"},       // 27
174    {kLogNameLastLMPTimer,          "IrStream: last lap timer"},                    // 28
175
176    {kLogNameChangeSpeedComplete,   "IrStream: changespeed complete event"}     // 29
177
178};
179    #define XTRACE(x, y, z) IrDALogAdd ( x, y, (uintptr_t)z & 0xffff, TraceEvents, true)
180    #define QTRACE(x, y, z) IrDALogAdd ( x, y, (uintptr_t)z & 0xffff, fTraceArray, true)
181    #define QTRACEArray(x, y, z, array) IrDALogAdd ( x, y, (uintptr_t)z & 0xffff, array, true)
182    #define ETRACE(x, y, z) IrDALogAdd ((x + kLogEventNamesStart), y, (uintptr_t)z & 0xffff, TraceEvents, true)
183#else
184    #define XTRACE(x, y, z) ((void)0)
185    #define QTRACE(x, y, z) ((void)0)
186    #define QTRACEArray(x, y, z, array) ((void)0)
187    #define ETRACE(x, y, z) ((void)0)
188#endif
189
190//--------------------------------------------------------------------------------
191#define super OSObject
192    OSDefineMetaClassAndAbstractStructors(TIrStream, OSObject);
193//--------------------------------------------------------------------------------
194
195//--------------------------------------------------------------------------------
196// Define the static fields here, or the dynamic loader doesn't find them.
197//--------------------------------------------------------------------------------
198TIrEvent    *TIrStream::fCurrentEvent;          // event we're running (not on the queue)
199TIrEvent    *TIrStream::fNextEvent;             // slight optimization to keep next event off the fifo
200CList       *TIrStream::fPendingEventsList;     // add to front, take from last, event FIFO
201
202//--------------------------------------------------------------------------------
203//      free
204//--------------------------------------------------------------------------------
205void
206TIrStream::free()
207{
208    int list_retain_count;
209
210    XTRACE(kLogFree, 0, this);
211
212    // should have a pending events list until the last stream is freed
213    require(fPendingEventsList, Fail);
214
215    // Free the pending events list
216    list_retain_count = fPendingEventsList->getRetainCount();
217    XTRACE(kLogFreeQueue, list_retain_count, fPendingEventsList->GetArraySize());
218
219    fPendingEventsList->release();  // this stream doesn't need the list anymore
220
221    if (list_retain_count == 1) {   // if retain count was one, then we just freed it
222	fPendingEventsList = nil;
223    }
224
225    // this stream is going away, let's go over the (static) pending event list and
226    // nuke anything that's queued up for us.  This doesn't normally happen unless
227    // we're stopped in the middle of doing stuff.
228
229    // first check the clist (which may have just been freed)
230    if (fPendingEventsList != nil && fPendingEventsList->GetArraySize() > 0) {
231	int index;
232	// go over the list backwards to make deleting easier
233	for (index = fPendingEventsList->GetArraySize()-1; index >= 0; index--) {
234	    TIrEvent *event = (TIrEvent *)fPendingEventsList->At(index);
235	    if (event && event->fDest == this) {
236		XTRACE(kLogCleanup1, 0, event);
237		fPendingEventsList->RemoveAt(index);        // just remove it from the list
238	    }
239	}
240    }
241    // then check fNextEvent
242    if (fNextEvent && fNextEvent->fDest == this) {
243	XTRACE(kLogCleanup2, 0, fNextEvent);
244	// could call DequeueEvent, but I don't want to clobber fCurrentEvent
245	if (fPendingEventsList) {
246	    fNextEvent = (TIrEvent *)fPendingEventsList->Last();
247	    if (fNextEvent) fPendingEventsList->RemoveLast();
248	}
249	else fNextEvent = nil;
250    }
251
252Fail:
253    super::free();
254
255} // free
256
257
258//--------------------------------------------------------------------------------
259//      Init
260//--------------------------------------------------------------------------------
261Boolean TIrStream::Init(TIrGlue *irda, EventTraceCauseDesc *trace, UInt16 index)
262{
263    XTRACE(kLogInit, 0, this);
264    XTRACE(kLogInit2, 0, trace);
265    XTRACE(kLogInit3, 0, index);
266
267    if (!super::init()) return false;
268
269    fIrDA = irda;                       // save this for all our derived classes (make static?)
270
271    if (fPendingEventsList == nil) {    // if first IrStream to get init'd
272	fPendingEventsList = CList::cList();    // create the pending event list
273	require(fPendingEventsList, Fail);
274	XTRACE(kLogNewEventList, 0, fPendingEventsList);
275	check(fCurrentEvent == nil);
276	check(fNextEvent == nil);
277    }
278    else {                              // if not the first stream, then incr the
279	fPendingEventsList->retain();       // list's in-use count!
280	XTRACE(kLogRetainEventList, 0, fPendingEventsList->getRetainCount());
281    }
282
283#if (hasTracing > 0 && hasIrStreamTracing > 0)
284    if( trace != 0 ) {                  // support funky enqueue/dequeue logging
285	fTraceIndex = index;            // index = enqueue, index+1 = dequeue start
286	fTraceArray = trace;            // index+2 = dequeue
287    }
288    else {                              // Use the generic trace code if the subclass
289	fTraceIndex = kGenericEnqueue;          // didn't explicitly set them
290	fTraceArray = TraceEvents;              // generic if client not tracing
291    }
292#endif
293
294    return true;
295
296Fail:
297    return false;
298
299} // TIrStream::Init
300
301
302//--------------------------------------------------------------------------------
303//      EnqueueEvent
304//--------------------------------------------------------------------------------
305IrDAErr TIrStream::EnqueueEvent(TIrEvent *eventBlock)
306{
307    UInt8   eventNum;
308    require(eventBlock, Fail);
309
310    eventNum = eventBlock->fEvent;
311
312    QTRACE(fTraceIndex, (uintptr_t)this >> 16, this);
313    ETRACE(eventNum, 0, eventNum);
314    XTRACE(kLogEnqueue, 0, eventBlock);
315    //XTRACE(kLogEnqueueThis, (int)this >>16, this);
316
317    require(eventNum > 0 && eventNum <= kIrMaxEventNumber, Fail);
318
319    eventBlock->fDest = this;           // single queue, so keep track of destination
320
321    if (fNextEvent == nil) {
322	fNextEvent = eventBlock;
323    }
324    else {
325	// Check for cases where the same event block is being enqueued more than once
326	// Although this won't catch cases where the same event block is put on the list
327	check(eventBlock != fNextEvent);
328
329	// Add the event to the pending events list
330	fPendingEventsList->InsertFirst(eventBlock);
331    }
332
333    //XASSERT(fIrDA);
334    //fIrDA->NextStateMachine(this);
335
336    return noErr;
337
338Fail:
339    return errBadArg;
340
341} // TIrStream::EnqueueEvent
342
343
344//--------------------------------------------------------------------------------
345//      DequeueEvent
346//--------------------------------------------------------------------------------
347/*static*/
348void TIrStream::DequeueEvent()
349{
350    require(fPendingEventsList, Fail);
351
352    // Next event becomes the current event
353    fCurrentEvent = fNextEvent;
354
355    // Take next event from the pending events list (if any)
356    fNextEvent = (TIrEvent *)fPendingEventsList->Last();
357    if (fNextEvent) {
358	fPendingEventsList->RemoveLast();
359    }
360
361Fail:
362    return;
363
364} // TIrStream::DequeueEvent
365
366//--------------------------------------------------------------------------------
367//      RunQueue
368//--------------------------------------------------------------------------------
369/* static */
370void TIrStream::RunQueue()
371{
372    TIrStream *dest;                // destination of the current event request/reply
373#if (hasTracing > 0 && hasIrStreamTracing > 0)
374    EventTraceCauseDesc *array;     // save pointer to subclases debug table
375    UInt32              index;      // save index to use (let's us do this after "delete obj")
376    UInt8           orig_event;     // saved event number
377#endif
378
379    while (true) {                  // single queue for all IrStream objects
380	DequeueEvent();
381	if (fCurrentEvent == nil) {     // we're done, seeya
382	    break;
383	}
384	dest = fCurrentEvent->fDest;        // get back to individual IrStream object
385	check(dest);
386
387	check(fCurrentEvent->fEvent > 0 && fCurrentEvent->fEvent <= kIrMaxEventNumber);
388
389#if (hasTracing > 0 && hasIrStreamTracing > 0)
390	orig_event = fCurrentEvent->fEvent;
391	array = dest->fTraceArray;          // save these in case the object is deleted on us
392	index = dest->fTraceIndex;          //  as a result of running the nextstate routine
393#endif
394	QTRACEArray(index+1, (uintptr_t)dest >> 16, dest, array);  // object event start message
395	ETRACE(orig_event, 0, orig_event);
396	XTRACE(kLogEventRecordRun, 0, fCurrentEvent);
397
398	dest->NextState(fCurrentEvent->fEvent);     // send the event to the stream object for processing!
399
400	QTRACEArray(index+2, orig_event, fCurrentEvent->fEvent, array);
401    }
402    return;
403
404} // TIrStream::ProcessNextEvent
405