1/* 2 File: IrLAP.h 3 4 Contains: Methods for implementing IrLAP 5 6*/ 7 8 9#ifndef __IRLAP_H 10#define __IRLAP_H 11 12#include "IrDATypes.h" 13#include "IrStream.h" 14#include "CBufferSegment.h" 15#include "IrEvent.h" 16 17// Forward reference 18class TIrGlue; 19class TIrLMP; 20class TIrQOS; 21class TLSAPConn; 22class TCMOSlowIRStats; 23class CIrDiscovery; 24class CIrDevice; 25class CBuffer; 26 27// Constants 28 29#define kIrLAPVersionNumber 0x00 30#define kIrLAPBroadcastAddr 0x7F 31#define kIrLAPCommandBit 0x01 32 33#define kIrLAPBroadcastDevAddr 0xFFFFFFFF 34#define kIrLAPSnifferDevAddr 0x736E6966 35#define kIrLAPSniffeeDevAddr 0x726F7365 36#define kIrLAPProbeDevAddr 0x70726265 37 38#define kIrDefaultLeadinCount 10 39#define kIrLAPFinalSlot 0xFF 40 41 42enum IrLAPCommandsAndResponses 43{ 44 kIrLAPUSIMask = 0x03, 45 kIrLAPIMask = 0x01, 46 kIrLAPUnnumbered = 0x03, 47 kIrLAPSupervisory = 0x01, 48 kIrLAPInformation = 0x00, 49 50 kIrLAPPFMask = 0x10, 51 kIrLAPPollBit = 0x10, 52 kIrLAPFinalBit = 0x10, 53 54 kIrLAPNrMask = 0xE0, 55 kIrLAPNrShift = 5, 56 kIrLAPNsMask = 0x0E, 57 kIrLAPNsShift = 1, 58 59 kIrLAPUnexpectedNr = 0x01, 60 kIrLAPUnexpectedNs = 0x02, 61 kIrLAPInvalidNr = 0x04, 62 kIrLAPInvalidNs = 0x08, 63 64 // Unnumbered commands 65 kIrLAPCmdSNRM = 0x83, 66 kIrLAPCmdDISC = 0x43, 67 kIrLAPCmdUI = 0x03, 68 kIrLAPCmdXID = 0x2F, 69 kIrLAPCmdTEST = 0xE3, 70 71 // Unnumbered responses 72 kIrLAPRspRNRM = 0x83, 73 kIrLAPRspUA = 0x63, 74 kIrLAPRspFRMR = 0x87, 75 kIrLAPRspDM = 0x0F, 76 kIrLAPRspRD = 0x43, 77 kIrLAPRspUI = 0x03, 78 kIrLAPRspXID = 0xAF, 79 kIrLAPRspTEST = 0xE3, 80 81 // Supervisor cmd/rsp 82 kIrLAPFrameRR = 0x01, 83 kIrLAPFrameRNR = 0x05, 84 kIrLAPFrameREJ = 0x09, 85 kIrLAPFrameSREJ = 0x0D, 86 87 // Information 88 kIrLAPFrameINFO = 0x00 89}; 90 91enum IrLAPFormatIdentifiers 92{ 93 kIrLAPDiscoveryXIDFormat = 0x01 94}; 95 96enum IrLAPDiscoverFlags 97{ 98 kIrLAPDiscoverFlagsSlotMask = 0x03, 99 kIrLAPDiscoverFlags1Slot = 0x00, 100 kIrLAPDiscoverFlags6Slots = 0x01, 101 kIrLAPDiscoverFlags8Slots = 0x02, 102 kIrLAPDiscoverFlags16Slots = 0x03, 103 104 kIrLAPDiscoverFlagsNewAddr = 0x04 105}; 106 107enum IrFRMRFlags // w,x,y,z fields of third FRMR I-field 108{ 109 kIrFRMRFlagUndefinedCtrl = 0x01, 110 kIrFRMRFlagInvalidIField = 0x02, 111 kIrFRMRFlagSizeExceeded = 0x04, 112 kIrFRMRFlagInvalidNrCount = 0x08, 113 114 kIrFRMRCrBit = 0x10 115}; 116 117enum IrLAPStates 118{ 119 kIrLAPDisconnectedState, /* NDM */ 120 kIrLAPQueryState, /* Discover query from primary */ 121 kIrLAPConnectState, /* Connect from primary */ 122 kIrLAPListenState, /* Listen from secondary */ 123 kIrLAPReplyState, /* Discover reply from secondary */ 124 125 kIrLAPLastNDMState = kIrLAPReplyState, 126 127 kIrLAPPriReceiveState, /* Primary in NRM receive */ 128 kIrLAPPriTransmitState, /* Primary in NRM transmit */ 129 kIrLAPPriCloseState, /* Primary in NRM close */ 130 kIrLAPSecReceiveState, /* Secondary in NRM receive */ 131 kIrLAPSecTransmitState, /* Secondary in NRM transmit */ 132 kIrLAPSecCloseState /* Secondary in NRM close */ 133}; 134 135enum IrLAPTimings // in milliseconds 136{ 137 kIrMediaBusyTimeout = 600, 138 kIrDiscoverSlotTimeout = 100, // *** Review - should be 60 (or35 if done right) 139 kIrConnectFinalTimerTimeout = 500, // *** Review - is this right? 140 kIrDisconnectWarningTimeout = 3 * 1000 // 3 seconds 141}; 142 143enum IrLAPRetries 144{ 145 kMaxConnectRetries = 3, 146 kMaxDisconnectRetries = 3, 147 kMaxDiscoverRetries = 10 // JDG: max times mediabusy timer fires before 1st discover 148}; 149 150enum { 151 kMaxUnconnectedPacketSize = 64 152}; 153 154// Classes 155 156 157// -------------------------------------------------------------------------------------------------------------------- 158// TXIDPacket 159// -------------------------------------------------------------------------------------------------------------------- 160 161#define kTXIDPacketSize 14 // Can't use sizeof because of padding stuff 162 163class TXIDPacket 164{ 165 public: 166 167 UByte fPhonyBologna1; // Ensure alignment of the following� 168 UByte fAddress; 169 UByte fCmdRsp; 170 UByte fFormatId; 171 ULong fSrcDevAddr; 172 ULong fDstDevAddr; 173 UByte fFlags; 174 UByte fSlotNum; 175 UByte fVersion; 176 UByte fDevInfo[2]; // Device info, actually longer, just padding 177}; 178 179 180// -------------------------------------------------------------------------------------------------------------------- 181// TSNRMPacket 182// -------------------------------------------------------------------------------------------------------------------- 183 184#define kTSNRMPacketSize 11 // Can't use sizeof because of padding stuff 185 186class TSNRMPacket 187{ 188 public: 189 190 UByte fPhonyBologna1; // Ensure alignment of the following� 191 UByte fPhonyBalogna2; // Ensure alignment of the following� 192 UByte fAddress; 193 UByte fCmdRsp; 194 ULong fSrcDevAddr; 195 ULong fDstDevAddr; 196 UByte fConnAddr; 197 UByte fQOSParmData[3]; // QOS parm info, actually longer, just padding 198}; 199 200 201// -------------------------------------------------------------------------------------------------------------------- 202// TUAPacket 203// -------------------------------------------------------------------------------------------------------------------- 204 205#define kTUAPacketSize 10 // Can't use sizeof because of padding stuff 206 207class TUAPacket 208{ 209 public: 210 211 UByte fPhonyBologna1; // Ensure alignment of the following� 212 UByte fPhonyBalogna2; // Ensure alignment of the following� 213 UByte fAddress; 214 UByte fCmdRsp; 215 ULong fSrcDevAddr; 216 ULong fDstDevAddr; 217 UByte fQOSParmData[4]; // QOS parm info, actually longer, just padding 218}; 219 220 221// -------------------------------------------------------------------------------------------------------------------- 222// TControlPacket 223// -------------------------------------------------------------------------------------------------------------------- 224 225#define kTControlPacketSize 2 // Can't use sizeof because of padding stuff 226 227class TControlPacket 228{ 229 public: 230 231 UByte fPhonyBologna1; // Ensure alignment of the following� 232 UByte fPhonyBalogna2; // Ensure alignment of the following� 233 UByte fAddress; 234 UByte fCmdRsp; 235 UByte fLMPDUData[4]; // Up to 4 bytes 236}; 237 238 239// -------------------------------------------------------------------------------------------------------------------- 240// TFRMRPacket 241// -------------------------------------------------------------------------------------------------------------------- 242 243#define kTFRMRPacketSize 5 // Can't use sizeof because of padding stuff 244 245class TFRMRPacket 246{ 247 public: 248 249 UByte fAddress; 250 UByte fCmdRsp; 251 UByte fRejCtrlField; 252 UByte fMyNrAndNs; 253 UByte fReasonFlags; 254 UByte fPhonyBologna1; // Pad it out (sheer paranoia) 255 UByte fPhonyBalogna2; // Pad it out (sheer paranoia) 256 UByte fPhonyBalogna3; // Pad it out (sheer paranoia) 257}; 258 259 260// -------------------------------------------------------------------------------------------------------------------- 261// TTestHdrPacket 262// -------------------------------------------------------------------------------------------------------------------- 263 264#define kTTestHdrPacketSize 2 // Can't use sizeof because of padding stuff 265 266class TTestHdrPacket 267{ 268 public: 269 270 UByte fAddress; 271 UByte fCmdRsp; 272}; 273 274 275//-------------------------------------------------------------------------------- 276// TIrLAPPutBuffer 277//-------------------------------------------------------------------------------- 278class TIrLAPPutBuffer : public OSObject 279{ 280 OSDeclareDefaultStructors(TIrLAPPutBuffer); 281 282public: 283 static TIrLAPPutBuffer * tIrLAPPutBuffer(void); // factory constructor 284 void free(void); 285 bool init(); 286 287 void SetControlBuffer(UByte* buffer, ULong length, Boolean initFirst); 288 void SetDataBuffer(CBuffer* buffer, ULong offset, ULong length); 289 290 UByte Get(void); 291 void Seek(Long off, int dir); 292 Boolean AtEOF(void) const; 293 ULong GetCtrlSize ( void ); 294 UByte * GetCtrlBuffer ( void ); 295 ULong GetDataSize ( void ); 296 UByte * GetDataBuffer ( void ); 297 298private: 299 // Fields� 300 UByte* fCtrlBuf; 301 ULong fCtrlBufLength; 302 ULong fCtrlBufPos; 303 304 CBuffer* fDataBuf; 305 ULong fDataBufOffset; 306 ULong fDataBufLength; 307 ULong fDataBufPos; 308}; 309 310inline ULong TIrLAPPutBuffer::GetCtrlSize() { return fCtrlBufLength; } 311inline UByte * TIrLAPPutBuffer::GetCtrlBuffer() { return fCtrlBuf; } 312inline ULong TIrLAPPutBuffer::GetDataSize() { return fDataBufLength; } 313inline UByte * TIrLAPPutBuffer::GetDataBuffer() { return fDataBuf ? ((CBufferSegment *)fDataBuf)->GetBufferPtr() : nil; }; 314 315 316// -------------------------------------------------------------------------------------------------------------------- 317// TIrLAP 318// -------------------------------------------------------------------------------------------------------------------- 319 320class TIrLAP : public TIrStream 321{ 322 OSDeclareDefaultStructors(TIrLAP); 323 324 public: 325 326 static TIrLAP * tIrLAP(TIrGlue *irda, TIrQOS *myQOS, TIrQOS* peerQOS); 327 Boolean Init(TIrGlue *irda, TIrQOS *myQOS, TIrQOS* peerQOS); 328 void free(void); 329 330 void Reset(); 331 332 // Callback for timer completion 333 334 void TimerComplete(ULong refCon); 335 336 // Callbacks for I/O completion 337 338 void OutputComplete(); 339 void ChangeSpeedComplete(); // jdg 340 341 void InputComplete(UByte aField, UByte cField); 342 Boolean InputAborted(); // read failed 343 344 // Access to IrLAP level stats 345 346 void CopyStatsTo(TCMOSlowIRStats* irStats); 347 void ResetStats(); 348 349 // To return input buffer to the buffer pool 350 351 void ReleaseInputBuffer(CBufferSegment* inputBuffer); 352 353 // Inline getter for my device address (for address resolution checking) 354 355 ULong GetMyDevAddr() { return fMyDevAddr; } 356 357 UInt32 GetDisconnectTimeoutMax ( void ); 358 UInt32 GetDisconnectTime ( void ); 359 Boolean InBrokenBeam ( void ); 360 Boolean Discovering ( void ); 361 Boolean ReaquiredConnection ( void ); 362 void BrokenBeamDisconnect ( void ); 363 Boolean IsConnected ( void ); 364 void GetNickName ( UInt8 * name, int maxlen); 365 // jdg: stop listen if in disconnected state 366 TIrEvent * CancelPendingListenRequest (void); // return event if canceled, else nil 367/*** Temp I hope ***/ 368/***JDG***/ void DisconnectComplete(IrDAErr result = errConnectionAborted); 369 TIrEvent * GetCurrentRequest(void); // jdg: ugly hack #2341 370 371 void Suspend(void); // jdg: going to sleep mode 372 void Resume(void); // jdg: waking up from sleep 373 374 private: 375 376 // TIrStream override 377 void NextState(ULong event); 378 379 void DeInit(); 380 void FreeGetBuffers(); 381 382 // NDM states 383 void HandleDisconnectedStateEvent(ULong event); 384 void HandleQueryStateEvent(ULong event); 385 void HandleConnectStateEvent(ULong event); 386 void HandleListenStateEvent(ULong event); 387 void HandleReplyStateEvent(ULong event); 388 void HandleNDMDisconnectRequest(); 389 390 // NRM states 391 void HandlePriTransmitStateEvent(ULong event); 392 void HandlePriReceiveStateEvent(ULong event); 393 void HandlePriCloseStateEvent(ULong event); 394 void HandleSecTransmitStateEvent(ULong event); 395 void HandleSecReceiveStateEvent(ULong event); 396 void HandleSecCloseStateEvent(ULong event); 397 398 void UpdateNrReceived(); 399 void ResendRejectedFrames(); 400 void ProcessRecdInfoOrSuperFrame(); 401 402 IrDAErr ParseNegotiateAndInitConnState(Boolean primary); 403 void ConnLstnComplete(IrDAErr result); 404 // void DisconnectComplete(IrDAErr result = kCommErrConnectionAborted); 405 void CancelPutRequest(); 406 void CancelPendingPutRequests(TLSAPConn* lsapConn, IrDAErr returnCode); 407 void PutComplete(TIrPutReply* putReply, IrDAErr result); 408 void NotConnectedCompletion(); 409 void ApplyDefaultConnParms(); 410 void StartDataReceive(); 411 412 void PostponePutRequest(); 413 void PrepareFRMRResponse(); 414 415 void OutputXIDCommand(); 416 void OutputXIDResponse(TXIDPacket& xidCmd); 417 void OutputSNRMCommand(); 418 void OutputUAResponse(); 419 void OutputFRMRResponse(); 420 void OutputControlFrame(UByte cmdRsp); 421 void OutputDataFrame(TIrPutRequest* request, Boolean finalOrPollFlag); 422 423 Boolean GotData(UByte *data, ULong size); 424 Boolean RecdCmd(UByte cmdPattern); 425 Boolean RecdPollCmd(UByte cmdPattern); 426 Boolean RecdRsp(UByte rspPattern); 427 Boolean RecdFinalRsp(UByte rspPattern); 428 429 Boolean Recd(UByte cmdRsp) { return fRecdCmdRsp == cmdRsp; } 430 Boolean RecdCmd() { return fRecdCR == kIrLAPCommandBit; } 431 Boolean RecdRsp() { return fRecdCR != kIrLAPCommandBit; } 432 Boolean RecdPoll() { return fRecdPF; } 433 Boolean RecdFinal() { return fRecdPF; } 434 Boolean RecdPollOrFinal() { return fRecdPF; } 435 436 Boolean RecdUFrame() { return (fRecdCmdRsp & kIrLAPUSIMask) == kIrLAPUnnumbered; } 437 Boolean RecdSFrame() { return (fRecdCmdRsp & kIrLAPUSIMask) == kIrLAPSupervisory; } 438 Boolean RecdIFrame() { return (fRecdCmdRsp & kIrLAPIMask) == kIrLAPInformation; } 439 440 Boolean RecdInvalidNr() { return (fNrNsFlags & kIrLAPInvalidNr) != 0; } 441 Boolean RecdInvalidNs() { return (fNrNsFlags & kIrLAPInvalidNs) != 0; } 442 Boolean RecdInvalidNrOrNs() { return (fNrNsFlags & (kIrLAPInvalidNr | kIrLAPInvalidNs)) != 0;} 443 Boolean RecdUnexpectedNr() { return (fNrNsFlags & kIrLAPUnexpectedNr) != 0; } 444 Boolean RecdUnexpectedNs() { return (fNrNsFlags & kIrLAPUnexpectedNs) != 0; } 445 446 void StartTimer(TTimeout timeDelay, int refCon); 447 void StopTimer(); 448 449 void StartOutput(TIrLAPPutBuffer* outputBuffer, ULong leadInCount); 450 void StopOutput(); 451 void StartInput(CBufferSegment* inputBuffer); 452 void StopInput(); 453 454 void HandleTestFrame(); 455 void TestFrameComplete(); 456 457 void RejectRequest(TIrEvent *request, IrDAErr err); // jdg, send back a request w/error 458 459 // Fields� 460 461 UByte fState; 462 UByte fConnAddr; // The 'A' field address 463 ULong fMyDevAddr; 464 465 UByte fDiscoverMaxSlots; 466 UByte fDiscoverSlot; 467 UByte fDiscoverFlags; 468 Boolean fDiscoverEnteredReplyState; 469 Boolean fDiscoverReplied; 470 ULong fConflictDevAddr; 471 ULong fReplacementDevAddr; 472 473 ULong fPeerDevAddr; 474 475 TIrEvent *fCurrentRequest; // For discover, connect, listen 476 TIrEvent *fPendingDisconnect; // For pending disconnect 477 CList *fPendingRequests; // jdg: deferred requests 478 479 TIrQOS *fMyQOS; 480 TIrQOS *fPeerQOS; 481 482 UByte fVr; 483 UByte fVs; 484 UByte fNextToAck; 485 UByte fWindow; 486 Boolean fConnected; // Is LAP connected? 487 Boolean fLocalBusy; 488 Boolean fRemoteBusy; 489 Boolean fSetLocalBusyPending; 490 Boolean fClrLocalBusyPending; 491 Boolean fEnteringCloseState; 492 Boolean fRespondingToDisconnect; 493 494 Boolean fWaitingForPollTimer; // avoiding cycle comsumption while idle or busy 495 496 Boolean fHandlingTestFrame; 497 TTestHdrPacket fTestHeader; 498 499 Boolean fFRMRPending; 500 UByte fFRMRRejCtrlField; 501 UByte fFRMRMyNrAndNs; 502 UByte fFRMRReasonFlags; 503 504 ULong fRetryCount; 505 ULong fDisconnectWarningLimit; 506 ULong fDisconnectLinkLimit; 507 508 UInt32 fInitialRetryTime; 509 UInt32 fDisconnectLinkLimitTime; 510 UInt32 fBusyCounter; // JDG: number of media busy in a row 511 512 ULong fDataRetries; 513 ULong fProtocolErrs; 514 515 //TIrEvent *fLocalBusyEvent; // Review. Why is this not referenced? 516 TIrEvent *fLocalBusyClearedEvent; // REVIEW. How is this used? 517 518 UByte fLeadInCount; 519 UByte fMyWindowSize; // Number of recv buffers - from fMyQOS->GetWindowSize() 520 UByte fPeerWindowSize; // Number of recv buffers - from fPeerQOS->GetWindowSize() 521 TTimeout fPollTimerTimeout; 522 TTimeout fFinalTimerTimeout; 523 TTimeout fWatchdogTimeout; 524 TTimeout fMinTurnAroundTimeout; 525 526 Boolean fPrimary; 527 //Boolean fNeedNewInputBuffer; // if fInputBuffer is nil, then we need a new one 528 Boolean fPutReqsPending; // One or more addl put reqs pending for secondary? 529 UByte fNextCmdRspToSend; // Cmd to send after recv cmd is processed 530 UByte fLastCmdRsp; // The last packet type sent. 531 532 UByte fRecdCtrl; // Control field as received (only used w/FRMR) 533 UByte fRecdCR; // C/R bit of the A field 534 UByte fRecdAddr; // Addr bits of the A field 535 UByte fRecdPF; // PF bit of the C field 536 UByte fRecdNr; // Nr bits of the C field 537 UByte fRecdNs; // Ns bits of the C field 538 UByte fRecdCmdRsp; // C field (less P/F, Nr, Ns) 539 540 UByte fValidRecdNr; // Bits representing valid fRecdNr values 541 UByte fValidRecdNs; // Bits representing valid fRecdNs values 542 UByte fNrNsFlags; // Unexpected/invalid Nr/Ns flags 543 544 //ULong fIOBuffer[64/4]; // Note: must be ULong for alignment! 545 CBufferSegment *fIOBufferItem; // used for misc i/o and when out of input buffers. 546 547 Boolean fInputInProgress; // Waiting for input (or perhaps receiving data) 548 Boolean fOutputInProgress; // Outputting data 549 550 Boolean fInBrokenBeam; // true if the beam is broken (but connection still exists) 551 Boolean fDiscoverActive; // true if we're discovering 552 553 ULong fGetBufferAvail; 554 ULong fNumGetBuffers; 555 CBufferSegment* fGetBuffers[15]; // Was 8, have 2*window for 556 // a workaround 557 558 CBufferSegment* fInputBuffer; // either fIOBufferItem or one of fGetBuffers 559 //CList fPendingPuts; 560 UInt8 fNickName[22]; // Name of device connected to. 561 CList* fPendingPutRequests; 562 TIrLAPPutBuffer *fPutBuffer; 563 TIrPutRequest *fPutRequests[8]; 564 565}; 566 567inline UInt32 TIrLAP::GetDisconnectTimeoutMax() { return fDisconnectLinkLimitTime; } 568inline UInt32 TIrLAP::GetDisconnectTime() { return fInitialRetryTime; } 569inline Boolean TIrLAP::InBrokenBeam() { return fInBrokenBeam; } 570inline Boolean TIrLAP::Discovering() { return fDiscoverActive; } 571inline Boolean TIrLAP::ReaquiredConnection() { return fRetryCount < fDisconnectWarningLimit; } 572inline void TIrLAP::BrokenBeamDisconnect() { if( fInBrokenBeam ) 573 fRetryCount = fDisconnectLinkLimit; } 574inline Boolean TIrLAP::IsConnected( void ) { return fConnected; } 575 576inline TIrEvent * TIrLAP::GetCurrentRequest(void) { return fCurrentRequest; }; // jdg, temp? 577#endif // __IRLAP_H 578