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