#define IRDA_TEST_FRAME_SUPPORTED 1 // required I think
#include "IrLAP.h"
#include "IrLMP.h"
#include "CList.h"
#include "IrGlue.h"
#include "CListIterator.h"
#include "IrDscInfo.h"
#include "IrQOS.h"
#include "IrDiscovery.h"
#include "IrLSAPConn.h"
#include "CIrDevice.h"
#define forMac 1 // TEMP TEMP TEMP -- clean up the code
const UByte IrSlotCounts[4] = {1, 6, 8, 16};
#if (hasTracing > 0 && hasLAPTracing > 0)
enum IrLAPTraceCodes
{
kLogCreate = 1,
kLogFree,
kLogInit,
kLogInit2,
kUnexpectedEvent,
kLogStateEvent,
kNDMTimeoutEvent,
kNDMRecdInputEvent,
kNDMDiscoveryEvent,
kNDMConnectEvent,
kNDMListenEvent,
kNDMDisconnectEvent,
kQueryTimeoutEvent,
kQueryRecdInputEvent,
kQueryOutputDoneEvent,
kQueryDisconnectEvent,
kConnectBackoffTimeoutEvent,
kConnectFinalTimeoutEvent,
kConnectRecdInputEvent,
kConnectOutputDoneEvent,
kConnectDisconnectEvent,
kConnectChangeSpeed,
kListenRecdInputEvent,
kListenOutputDoneEvent,
kListenDisconnectEvent,
kListenChangeSpeed, kOutputUACommandEvent,
kReplyTimeoutEvent,
kReplyRecdInputEvent,
kReplyOutputDoneEvent,
kReplyDisconnectEvent,
kReplyDiscoverRequestEvent, kReplyListenRequestEvent,
kPriReceiveFinalTimeoutEvent,
kPriReceiveRecdInputEvent,
kPriReceiveOutputDoneEvent,
kPriReceivePutDataEvent,
kPriReceiveDisconnectEvent,
kPriReceiveClrLocBsyPendEvent,
kPriReceiveFRMREvent,
kPriTransmitEnterEvent,
kPriTransmitPollTimeoutEvent,
kPriTransmitOutputDoneEvent,
kPriTransmitPutDataEvent,
kPriTransmitDisconnectEvent,
kPriTransmitClrLocBsyPendEvent,
kPriCloseFinalTimeoutEvent,
kPriCloseRecdInputEvent,
kPriCloseOutputDoneEvent,
kPriCloseDisconnectRequest,
kSecReceiveWDTimeoutEvent,
kSecReceiveRecdInputEvent,
kSecReceiveOutputDoneEvent,
kSecReceivePutDataEvent,
kSecReceiveDisconnectEvent,
kSecReceiveClrLocBsyPendEvent,
kSecReceiveConnLstnRequest,
kSecTransmitEnterEvent,
kSecTransmitOutputDoneEvent,
kSecTransmitPutDataEvent,
kSecTransmitDisconnectEvent,
kSecTransmitClrLocBsyPendEvent,
kSecTransmitConnLstnRequest,
kSecCloseWDTimeoutEvent,
kSecCloseRecdInputEvent,
kSecCloseOutputDoneEvent,
kSecCloseDisconnectRequest,
kDiscoveredDevice,
kDiscoverXIDCmdEvent,
kDiscoverXIDRspEvent,
kQOSSetBaudRateEvent,
kQOSBufferInfoEvent,
kQOSLeadInCountEvent,
kQOSMinTurnAroundEvent,
kQOSMaxTurnAroundEvent,
kSetLocalBusyPendingEvent,
kSetLocalBusyEvent,
kAbortLocalBusyPendingEvent,
kClrLocalBusyPendingEvent,
kClrLocalBusyEvent,
kNDMDisconnectFwdReply,
kNDMDisconnectReply,
kNRMDisconnectReply,
kNRMDisconnectAsyncReply,
kNRMDisconnectRequeue,
kTestFrameReceivedEvent,
kTestFrameOutputDoneEvent,
kValidPacketReceived,
kLogPacketDropped,
kPacketOutput,
kUnexpectedNr, kInvalidNr,
kUnexpectedNs,
kInvalidNs,
kIgnoringInvalidNrNs,
kOutputControlFrame,
kOutputControlFrameRR,
kOutputDataFrame,
kOutputDataFrameNotFinal,
kInputControlFrame,
kInputControlFrameRR,
kInputControlFrameNotFinal,
kInputDataFrame,
kInputDataFrameNotFinal,
kResendRejectedFrames,
kProcessISFrame,
kUpdateNrReceived,
kEnqueueEvent, kDequeueEventStart,
kDequeueEventEnd,
kReusingBuffer,
kUsingDefaultBuffer,
kLAPAddr,
kInputAborted, kConnLstnComplete,
kRejectRequest,
kLogEnteringCloseState,
kLogStartTimer,
kLogStopTimer,
kLogTimerComplete,
kLogSuspend,
kLogResume,
kLogChangeSpeedCompleteIgnored,
kLogMyAddr,
kLogGotAddr,
kLogStartInput,
kLogStartInput2,
kLogStartInput3,
kLogGotData,
kLogFailedFirst,
kLogFailedSecond,
kLogFailedThird,
kLogReleaseInputBuffer,
kLogReleaseInputBuffer2,
kLogStartDataRcv1,
kLogStartDataRcv2,
kLogReset1,
kLogReset2,
kLogFreeGetBuffers1,
kLogFreeGetBuffers2,
kLogFreeGetBuffers3,
kLogFreeGetBuffers4
};
static
EventTraceCauseDesc TraceEvents[] = {
{kLogCreate, "irlap: create obj="},
{kLogFree, "irlap: free obj="},
{kLogInit, "irlap: init, obj="},
{kLogInit2, "irlap: init, my dev addr="},
{kUnexpectedEvent, "irlap: unexpected event"},
{kLogStateEvent, "irlap: NextState, state=, event="},
{kNDMTimeoutEvent, "irlap: NDM media busy timer"},
{kNDMRecdInputEvent, "irlap: NDM recvd input"},
{kNDMDiscoveryEvent, "irlap: NDM discovery"},
{kNDMConnectEvent, "irlap: NDM connect"},
{kNDMListenEvent, "irlap: NDM listen"},
{kNDMDisconnectEvent, "irlap: NDM disconnect"},
{kQueryTimeoutEvent, "irlap: Probe query timer"},
{kQueryRecdInputEvent, "irlap: Probe query recvd input"},
{kQueryOutputDoneEvent, "irlap: Probe query output done"},
{kQueryDisconnectEvent, "irlap: Probe query disconnect"},
{kConnectBackoffTimeoutEvent, "irlap: Connect backoff timer"},
{kConnectFinalTimeoutEvent, "irlap: Connect F-timer"},
{kConnectRecdInputEvent, "irlap: Connect recvd input"},
{kConnectOutputDoneEvent, "irlap: Connect output done"},
{kConnectDisconnectEvent, "irlap: Connect disconnect"},
{kConnectChangeSpeed, "irlap: Connect changed speed"},
{kListenRecdInputEvent, "irlap: Listen recvd input"},
{kListenOutputDoneEvent, "irlap: Listen output done"},
{kListenDisconnectEvent, "irlap: Listen disconnect"},
{kListenChangeSpeed, "irlap: Listen changed spped"},
{kOutputUACommandEvent, "irlap: OutputUAPacket"},
{kReplyTimeoutEvent, "irlap: Probe reply timer"},
{kReplyRecdInputEvent, "irlap: Probe reply recvd input"},
{kReplyOutputDoneEvent, "irlap: Probe reply output done"},
{kReplyDisconnectEvent, "irlap: Probe reply disconnect"},
{kReplyDiscoverRequestEvent, "irlap: Probe reply, got discover request"},
{kReplyListenRequestEvent, "irlap: Probe reply, got listen request"},
{kPriReceiveFinalTimeoutEvent, "irlap: PRecv final timer"},
{kPriReceiveRecdInputEvent, "irlap: PRecv recvd input, cmd, Ns|Nr"},
{kPriReceiveOutputDoneEvent, "irlap: PRecv output done"},
{kPriReceivePutDataEvent, "irlap: PRecv put data"},
{kPriReceiveDisconnectEvent, "irlap: PRecv disconnect"},
{kPriReceiveClrLocBsyPendEvent, "irlap: PRecv clr local busy"},
{kPriReceiveFRMREvent, "irlap: PRecv recvd FRMR"},
{kPriTransmitEnterEvent, "irlap: PXmit enter"},
{kPriTransmitPollTimeoutEvent, "irlap: PXmit poll timer"},
{kPriTransmitOutputDoneEvent, "irlap: PXmit output done"},
{kPriTransmitPutDataEvent, "irlap: PXmit put data"},
{kPriTransmitDisconnectEvent, "irlap: PXmit disconnect"},
{kPriTransmitClrLocBsyPendEvent,"irlap: PXmit clr local busy"},
{kPriCloseFinalTimeoutEvent, "irlap: PClose final timer"},
{kPriCloseRecdInputEvent, "irlap: PClose recvd input"},
{kPriCloseOutputDoneEvent, "irlap: PClose output done"},
{kPriCloseDisconnectRequest, "irlap: PClose deferring disconnect request"},
{kSecReceiveWDTimeoutEvent, "irlap: SRecv WD timer"},
{kSecReceiveRecdInputEvent, "irlap: SRecv recvd input"},
{kSecReceiveOutputDoneEvent, "irlap: SRecv output done"},
{kSecReceivePutDataEvent, "irlap: SRecv put data"},
{kSecReceiveDisconnectEvent, "irlap: SRecv disconnect"},
{kSecReceiveClrLocBsyPendEvent, "irlap: SRecv clr local busy"},
{kSecReceiveConnLstnRequest, "irlap: SRecv conn/listen request"},
{kSecTransmitEnterEvent, "irlap: SXmit enter"},
{kSecTransmitOutputDoneEvent, "irlap: SXmit output done"},
{kSecTransmitPutDataEvent, "irlap: SXmit put data"},
{kSecTransmitDisconnectEvent, "irlap: SXmit disconnect"},
{kSecTransmitClrLocBsyPendEvent,"irlap: SXmit clr local busy"},
{kSecTransmitConnLstnRequest, "irlap: SXmit conn/listen request"},
{kSecCloseWDTimeoutEvent, "irlap: SClose WD timer"},
{kSecCloseRecdInputEvent, "irlap: SClose recvd input"},
{kSecCloseOutputDoneEvent, "irlap: SClose output done"},
{kSecCloseDisconnectRequest, "irlap: SClose deferring disconnect request"},
{kDiscoveredDevice, "irlap: discovered"},
{kDiscoverXIDCmdEvent, "irlap: put XID command"},
{kDiscoverXIDRspEvent, "irlap: put XID response"},
{kQOSSetBaudRateEvent, "irlap: new baud rate"},
{kQOSBufferInfoEvent, "irlap: buf cnt/size"},
{kQOSLeadInCountEvent, "irlap: lead in count"},
{kQOSMinTurnAroundEvent, "irlap: min turnaround"},
{kQOSMaxTurnAroundEvent, "irlap: max turnaround"},
{kSetLocalBusyPendingEvent, "irlap: set local busy pending"},
{kSetLocalBusyEvent, "irlap: set local busy"},
{kAbortLocalBusyPendingEvent, "irlap: set local busy pending aborted"},
{kClrLocalBusyPendingEvent, "irlap: clr local busy pending"},
{kClrLocalBusyEvent, "irlap: clr local busy"},
{kNDMDisconnectFwdReply, "irlap: NDM disconnect forward reply"},
{kNDMDisconnectReply, "irlap: NDM disconnect reply"},
{kNRMDisconnectReply, "irlap: NRM disconnect reply"},
{kNRMDisconnectAsyncReply, "irlap: NRM disconnect async reply"},
{kNRMDisconnectRequeue, "irlap: NRM disconnect requeue event"},
{kTestFrameReceivedEvent, "irlap: test frame received"},
{kTestFrameOutputDoneEvent, "irlap: test frame response sent"},
{kValidPacketReceived, "irlap: valid packet received"},
{kLogPacketDropped, "irlap: packet dropped ** no read pending!"},
{kPacketOutput, "irlap: packet output"},
{kUnexpectedNr, "irlap: Unexpected NR"}, {kInvalidNr, "irlap: Invalid NR"},
{kUnexpectedNs, "irlap: Unexpected NS"},
{kInvalidNs, "irlap: Invalid NS"},
{kIgnoringInvalidNrNs, "irlap: IGNORING*** invalid NrNs"},
{kOutputControlFrame, "irlap: output non-RR control frame, Cmd, Nr"},
{kOutputControlFrameRR, "irlap: output RR control frame, 0, Nr"},
{kOutputDataFrame, "irlap: output data frame (Ns, Nr)"},
{kOutputDataFrameNotFinal, "irlap: output data frame, not final (Ns,Nr)"},
{kInputControlFrame, "irlap: input NON-RR control frame, (CMD,Nr)"},
{kInputControlFrameRR, "irlap: input RR control frame, (0, Nr)"},
{kInputControlFrameNotFinal, "irlap: input control frame, NOT FINAL (cfield,Nr)"},
{kInputDataFrame, "irlap: input data frame (Ns, Nr)"},
{kInputDataFrameNotFinal, "irlap: input data frame, non-final (Ns, Nr)"},
{kResendRejectedFrames, "irlap: inside resend rejected frames"},
{kProcessISFrame, "irlap: process Info/Super frame"},
{kUpdateNrReceived, "irlap: update Nr received"},
{kEnqueueEvent, "irlap: Event Queued"},
{kDequeueEventStart, "irlap: Event Start"},
{kDequeueEventEnd, "irlap: Event End"},
{kReusingBuffer, "irlap: start data recv, reusing input buffer"},
{kUsingDefaultBuffer, "irlap: start data recv, using DEFAULT input buffer"},
{kLAPAddr, "irlap: Peer Addr: My Addr:"},
{kInputAborted, "irlap: input abort - fast link turnaround after read err"},
{kConnLstnComplete, "irlap: conn/lstn complete, peer dev addr="},
{kRejectRequest, "irlap: rejecting request"},
{kLogEnteringCloseState, "irlap: entering close state at #"},
{kLogStartTimer, "irlap: start timer, (delay, event)"},
{kLogStopTimer, "irlap: stop timer"},
{kLogTimerComplete, "irlap: timer complete, 0, event"},
{kLogSuspend, "irlap: sleep"},
{kLogResume, "irlap: wakeup"},
{kLogChangeSpeedCompleteIgnored, "irlap: change speed complete ignored"},
{kLogMyAddr, "irlap: my addr"},
{kLogGotAddr, "irlap: rcvd addr"},
{kLogStartInput, "irlap: start input, buf="},
{kLogStartInput2, "irlap: start input, old buf="},
{kLogStartInput3, "irlap: start input - keeping memory from leaking"},
{kLogGotData, "irlap: gotdata, wanted=, got="},
{kLogFailedFirst, "irlap: ** failed ** 1st test"},
{kLogFailedSecond, "irlap: ** failed ** second test"},
{kLogFailedThird, "irlap: ** failed ** third test"},
{kLogReleaseInputBuffer, "irlap: release input buffer, buffer="},
{kLogReleaseInputBuffer2, "irlap: release input buffer, flags, index"},
{kLogStartDataRcv1, "irlap: start data rcv alloc, buffer="},
{kLogStartDataRcv2, "irlap: start data rcv alloc, flags, index"},
{kLogReset1, "irlap: reset, buffer alloc mask"},
{kLogReset2, "irlap: reset, states"},
{kLogFreeGetBuffers1, "irlap: free get buffers, buffer="},
{kLogFreeGetBuffers2, "irlap: free get buffers, flag, index"},
{kLogFreeGetBuffers3, "irlap: free get buffers, mask="},
{kLogFreeGetBuffers4, "irlap: free get buffers, found fInputBuffer"}
};
#define XTRACE(x, y, z) IrDALogAdd ( x, y, (uintptr_t)z & 0xffff, TraceEvents, true )
#else
#define XTRACE(x, y, z) ((void)0)
#endif // hasTracing && hasLAPTracing
#define GetLMP (fIrDA->GetLMP())
#define GetDiscovery (fIrDA->GetDiscovery())
#define GetIrDevice (fIrDA->GetIrDevice())
void LAPTimerNotifier( UInt32 refCon, UInt32 sig );
Boolean gLastWasFRMR = false;
#define super TIrStream
OSDefineMetaClassAndStructors(TIrLAP, TIrStream);
TIrLAP *
TIrLAP::tIrLAP(TIrGlue *irda, TIrQOS *myQOS, TIrQOS* peerQOS)
{
TIrLAP *obj = new TIrLAP;
XTRACE(kLogCreate, 0, obj);
if (obj && !obj->Init(irda, myQOS, peerQOS)) {
obj->release();
obj = nil;
}
return obj;
}
Boolean
TIrLAP::Init(TIrGlue *irda, TIrQOS *myQOS, TIrQOS* peerQOS)
{
XTRACE(kLogInit, 0, this);
fState = kIrLAPDisconnectedState; fConnAddr = 0;
fMyDevAddr = 0;
fDiscoverMaxSlots = 0;
fDiscoverSlot = 0;
fDiscoverFlags =0;
fDiscoverReplied = fDiscoverEnteredReplyState = false;
fConflictDevAddr = fReplacementDevAddr = fPeerDevAddr= 0;
fCurrentRequest = nil;
fPendingDisconnect = nil;
fPendingRequests = nil;
fMyQOS = myQOS;
fPeerQOS = peerQOS;
fVr = fVs = fNextToAck = fWindow = 0;
fConnected = fLocalBusy = fRemoteBusy = false;
fSetLocalBusyPending = fClrLocalBusyPending = fEnteringCloseState = fRespondingToDisconnect = false;
fWaitingForPollTimer = fHandlingTestFrame = false;
bzero(&fTestHeader, sizeof(fTestHeader));
fFRMRPending = false;
fFRMRRejCtrlField = fFRMRMyNrAndNs = fFRMRReasonFlags = 0;
fRetryCount = fDisconnectWarningLimit = fDisconnectLinkLimit = 0;
fInitialRetryTime = fDisconnectLinkLimitTime = fBusyCounter = 0;
fDataRetries = fProtocolErrs = 0;
fLocalBusyClearedEvent = nil;
fLeadInCount = fMyWindowSize = fPeerWindowSize = 0;
fPollTimerTimeout = fFinalTimerTimeout = fWatchdogTimeout = fMinTurnAroundTimeout = 0;
fPrimary = fPutReqsPending = false;
fNextCmdRspToSend = fLastCmdRsp = 0;
fRecdCtrl = fRecdCR = fRecdAddr = 0;
fRecdPF = fRecdNr = fRecdNs = fRecdCmdRsp = 0;
fValidRecdNr = fValidRecdNs = fNrNsFlags = 0;
fIOBufferItem = nil;
fInputInProgress = fOutputInProgress = fInBrokenBeam = false;
fGetBufferAvail = fNumGetBuffers = 0;
bzero(fGetBuffers, sizeof(fGetBuffers));
fInputBuffer = nil;
bzero(fNickName, sizeof(fNickName));
fPendingPutRequests = nil;
fPutBuffer = nil;
bzero(fPutRequests, sizeof(fPutRequests));
#if (hasTracing > 0 && hasLAPTracing > 0)
if (!super::Init(irda, TraceEvents, kEnqueueEvent)) return false;
#else
if (!super::Init(irda)) return false;
#endif
fLeadInCount = kIrDefaultLeadinCount;
fMyDevAddr = ( random() % 0xFFFFFFFE + 1 );
if ((fMyDevAddr == kIrLAPSnifferDevAddr) || (fMyDevAddr == kIrLAPSniffeeDevAddr) || (fMyDevAddr == kIrLAPProbeDevAddr)) {
fMyDevAddr++;
}
XTRACE(kLogInit2, fMyDevAddr>>16, fMyDevAddr);
require(fMyDevAddr, Fail);
fIOBufferItem = CBufferSegment::New(3000); require(fIOBufferItem, Fail);
fPendingPutRequests = CList::cList();
require(fPendingPutRequests, Fail);
fPendingRequests = CList::cList();
require(fPendingRequests, Fail);
fLocalBusyClearedEvent = fIrDA->GrabEventBlock(kIrLocalBusyClearedEvent, sizeof(TIrEvent)); require(fLocalBusyClearedEvent, Fail);
fPutBuffer = TIrLAPPutBuffer::tIrLAPPutBuffer();
require(fPutBuffer, Fail);
ResetStats();
return true;
Fail:
return false;
}
void
TIrLAP::free()
{
XTRACE(kLogFree, 0, this);
#define FREE(x) { if (x) { (x)->release(); x = nil; } }
FreeGetBuffers();
FREE(fPendingPutRequests);
FREE(fPendingRequests);
FREE(fIOBufferItem);
FREE(fPutBuffer);
if (fIrDA) {
if (fLocalBusyClearedEvent) {
fIrDA->ReleaseEventBlock(fLocalBusyClearedEvent);
fLocalBusyClearedEvent = nil;
}
}
super::free();
}
void TIrLAP::Reset()
{
XTRACE(kLogReset1, fGetBufferAvail >> 16, fGetBufferAvail);
XTRACE(kLogReset2, kIrLAPDisconnectedState, fState);
fState = kIrLAPDisconnectedState;
FreeGetBuffers();
}
void
TIrLAP::Suspend(void)
{
XTRACE(kLogSuspend, 0, 0);
fRetryCount = fDisconnectLinkLimit; }
void
TIrLAP::Resume(void)
{
XTRACE(kLogResume, 0, 0);
}
void TIrLAP::GetNickName( UInt8 * nickName, int maxlen )
{
if( fNickName[0] != 0 )
strlcpy( ( char * )nickName, ( const char * )fNickName, maxlen);
else
nickName[0] = 0;
}
void TIrLAP::FreeGetBuffers()
{
UInt32 flag, index;
XTRACE(kLogFreeGetBuffers3, fGetBufferAvail >> 16, fGetBufferAvail);
for (index = 0, flag=1; index < fNumGetBuffers; index++, flag <<= 1) {
XTRACE(kLogFreeGetBuffers1, 0, fGetBuffers[index]);
XTRACE(kLogFreeGetBuffers2, flag, index);
check(fGetBuffers[index]);
check((fGetBufferAvail & flag) || (fInputBuffer == fGetBuffers[index]));
if (fGetBuffers[index] && (fGetBufferAvail & flag)) { fGetBuffers[index]->Delete(); }
else {
if (fInputBuffer == fGetBuffers[index]) {
XTRACE(kLogFreeGetBuffers4, 0, fInputBuffer);
fInputBuffer = nil;
fGetBuffers[index]->Delete(); }
else { DebugLog("memory leak! fInputBuffer=0x%lx\n", (uintptr_t)fInputBuffer);
DebugLog("buffer problem in free get buffers, index %ld, buffer 0x%lx\n",
(long int)index, (uintptr_t) fGetBuffers[index]);
}
}
fGetBuffers[index] = nil; }
fNumGetBuffers = 0; fGetBufferAvail = 0;
}
TIrEvent *
TIrLAP::CancelPendingListenRequest(void) {
TIrEvent *request = GetCurrentEvent();
StopInput();
if (fState == kIrLAPDisconnectedState && request && request->fEvent == kIrListenRequestEvent) {
fCurrentRequest = nil; return request; }
return nil;
}
void TIrLAP::NextState(ULong event)
{
XTRACE(kLogStateEvent, fState, event);
switch (fState) {
case kIrLAPDisconnectedState:
HandleDisconnectedStateEvent(event);
break;
case kIrLAPQueryState:
HandleQueryStateEvent(event);
break;
case kIrLAPConnectState:
HandleConnectStateEvent(event);
break;
case kIrLAPListenState:
HandleListenStateEvent(event);
break;
case kIrLAPReplyState:
HandleReplyStateEvent(event);
break;
case kIrLAPPriReceiveState:
HandlePriReceiveStateEvent(event);
break;
case kIrLAPPriTransmitState:
HandlePriTransmitStateEvent(event);
break;
case kIrLAPPriCloseState:
HandlePriCloseStateEvent(event);
break;
case kIrLAPSecReceiveState:
HandleSecReceiveStateEvent(event);
break;
case kIrLAPSecTransmitState:
HandleSecTransmitStateEvent(event);
break;
case kIrLAPSecCloseState:
HandleSecCloseStateEvent(event);
break;
default:
DebugLog("TIrLAP::NextState: bad fState");
break;
}
}
void TIrLAP::HandleDisconnectedStateEvent(ULong event)
{
#if forMac // Using a hammer for the problem, but if I am
fConnected = false; fDiscoverActive = false; fNickName[0] = 0;
#endif
switch (event) {
case kIrDiscoverRequestEvent:
{
XTRACE(kNDMDiscoveryEvent, 0, 0);
fDiscoverActive = true; if (fCurrentRequest != nil) { RejectRequest(fCurrentRequest, kIrDAErrRetry); }
fCurrentRequest = GetCurrentEvent();
GetIrDevice->ResetMediaBusy();
StartTimer(kIrMediaBusyTimeout, kIrMediaBusyTimerExpiredEvent);
fBusyCounter = 0; StartInput(fIOBufferItem);
}
break;
case kIrConnectRequestEvent:
{
XTRACE(kNDMConnectEvent, 0, 0);
TIrConnLstnRequest* connectRequest = (TIrConnLstnRequest*)GetCurrentEvent();
if (fCurrentRequest != nil) { fDiscoverActive = false; StopTimer(); RejectRequest(fCurrentRequest, kIrDAErrRetry); }
fCurrentRequest = GetCurrentEvent();
fMyQOS = connectRequest->fMyQOS;
fPeerQOS = connectRequest->fPeerQOS;
if (1) {
XTRACE(kQOSBufferInfoEvent, fMyQOS->GetWindowSize(), fMyQOS->GetDataSize());
XTRACE(kQOSLeadInCountEvent, 0, fMyQOS->GetExtraBOFs());
XTRACE(kQOSMinTurnAroundEvent, 0, fMyQOS->GetMinTurnAroundTime());
XTRACE(kQOSMaxTurnAroundEvent, 0, fMyQOS->GetMaxTurnAroundTime());
XTRACE(kQOSBufferInfoEvent, fPeerQOS->GetWindowSize(), fPeerQOS->GetDataSize());
XTRACE(kQOSLeadInCountEvent, 1, fPeerQOS->GetExtraBOFs());
XTRACE(kQOSMinTurnAroundEvent, 1, fPeerQOS->GetMinTurnAroundTime());
XTRACE(kQOSMaxTurnAroundEvent, 1, fPeerQOS->GetMaxTurnAroundTime());
}
fPeerDevAddr = connectRequest->fDevAddr;
fConnAddr = (UByte)random() % 0x7C + 2;
if ((fConnAddr == 0x60) || (fConnAddr == 0x3E)) {
fConnAddr++;
}
XTRACE( kLAPAddr, fPeerDevAddr, fConnAddr );
check(fConnAddr);
GetIrDevice->SetLAPAddress( fConnAddr );
fRetryCount = 0;
fInitialRetryTime = 0;
fState = kIrLAPConnectState;
OutputSNRMCommand();
}
break;
case kIrListenRequestEvent:
{
XTRACE(kNDMListenEvent, 0, 0);
TIrConnLstnRequest* listenRequest = (TIrConnLstnRequest*)GetCurrentEvent();
if (fCurrentRequest != nil) { RejectRequest(GetCurrentEvent(), kIrDAErrRetry); return; }
fCurrentRequest = GetCurrentEvent();
fMyQOS = listenRequest->fMyQOS;
fPeerQOS = listenRequest->fPeerQOS;
StartInput(fIOBufferItem);
}
break;
case kIrInputCompleteEvent:
{
XTRACE(kNDMRecdInputEvent, fRecdCmdRsp, fRecdAddr);
StopTimer();
if (RecdPollCmd(kIrLAPCmdXID)) {
fDiscoverEnteredReplyState = true;
HandleReplyStateEvent(kIrInputCompleteEvent);
}
else if (RecdPollCmd(kIrLAPCmdSNRM)) {
HandleListenStateEvent(kIrInputCompleteEvent);
}
else {
StartInput(fIOBufferItem);
}
if (fState == kIrLAPDisconnectedState) {
if (fCurrentRequest && fCurrentRequest->fEvent == kIrDiscoverRequestEvent) {
GetIrDevice->ResetMediaBusy();
StartTimer(kIrMediaBusyTimeout, kIrMediaBusyTimerExpiredEvent);
}
}
}
break;
case kIrMediaBusyTimerExpiredEvent:
{
XTRACE(kNDMTimeoutEvent, 0, 0);
TIrDiscoverRequest* discoverRequest = (TIrDiscoverRequest*)fCurrentRequest;
fDiscoverActive = true;
if (GetIrDevice->GetMediaBusy()) {
if (fBusyCounter++ < kMaxDiscoverRetries) { GetIrDevice->ResetMediaBusy(); StartTimer(kIrMediaBusyTimeout, kIrMediaBusyTimerExpiredEvent);
} else { fDiscoverActive = false; discoverRequest->fPassiveDiscovery = false; RejectRequest(fCurrentRequest, kIrDAErrLinkBusy); fCurrentRequest = nil;
}
}
else {
StopInput();
fDiscoverFlags = kIrLAPDiscoverFlags1Slot;
fDiscoverMaxSlots = 0;
UByte index;
for (index = 0; index < sizeof(IrSlotCounts); index++) {
if (IrSlotCounts[index] == discoverRequest->fNumSlots) {
fDiscoverFlags = index;
fDiscoverMaxSlots = (UByte)discoverRequest->fNumSlots - 1;
break;
}
}
fConflictDevAddr = discoverRequest->fConflictDevAddr;
if (fConflictDevAddr != kIrLAPBroadcastDevAddr) {
fDiscoverFlags |= kIrLAPDiscoverFlagsNewAddr;
}
fDiscoverSlot = 0;
fState = kIrLAPQueryState;
OutputXIDCommand();
}
}
break;
case kIrCancelPutRequestEvent:
CancelPutRequest();
break;
case kIrDisconnectRequestEvent:
XTRACE(kNDMDisconnectEvent, 0, 0);
HandleNDMDisconnectRequest();
break;
case kIrPutDataRequestEvent:
NotConnectedCompletion(); break;
case kIrLocalBusyClearedEvent:
break;
case kIrOutputCompleteEvent: break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TIrLAP::HandleDisconnectedStateEvent: bad event");
break;
}
}
void TIrLAP::HandleQueryStateEvent(ULong event)
{
fDiscoverActive = true;
switch (event) {
case kIrInputCompleteEvent:
XTRACE(kQueryRecdInputEvent, fRecdCmdRsp, fRecdAddr);
if ((fRecdAddr == kIrLAPBroadcastAddr) && RecdFinalRsp(kIrLAPRspXID)) {
TXIDPacket xidRsp;
if (GotData(&xidRsp.fFormatId, kTXIDPacketSize - 2)) {
if (xidRsp.fDstDevAddr == fMyDevAddr) {
XTRACE(kDiscoveredDevice, 0, (xidRsp.fSrcDevAddr >> 16));
XTRACE(kDiscoveredDevice, 1, (xidRsp.fSrcDevAddr));
TIrDscInfo* discoveryInfo = TIrDscInfo::tIrDscInfo();
if (discoveryInfo != nil) {
TIrDiscoverReply* discoverReply = (TIrDiscoverReply*)fCurrentRequest;
XASSERT(discoverReply != nil);
discoveryInfo->SetVersion(xidRsp.fVersion);
discoveryInfo->SetDeviceAddr(xidRsp.fSrcDevAddr);
discoveryInfo->ExtractDevInfoFromBuffer(fInputBuffer);
discoverReply->fDiscoveredDevices->InsertLast(discoveryInfo);
}
}
else {
XTRACE(kLogMyAddr, fMyDevAddr >> 16, fMyDevAddr);
XTRACE(kLogGotAddr, xidRsp.fDstDevAddr >> 16, xidRsp.fDstDevAddr);
XTRACE(kLogFailedThird, 0, 0);
DebugLog(" failed 3rd");
}
}
else {
DebugLog(" failed 2nd");
XTRACE(kLogFailedSecond, 0, 0);
}
}
else {
XTRACE(kLogFailedFirst, 0, 0);
DebugLog(" failed 1st");
}
StartInput(fIOBufferItem);
break;
case kIrOutputCompleteEvent:
XTRACE(kQueryOutputDoneEvent, fDiscoverSlot, fDiscoverMaxSlots);
XASSERT(fNextCmdRspToSend == kIrLAPCmdXID);
if (fDiscoverSlot != kIrLAPFinalSlot) {
StartTimer(kIrDiscoverSlotTimeout, kIrSlotTimerExpiredEvent);
StartInput(fIOBufferItem); }
else {
TIrDiscoverReply* discoverReply = (TIrDiscoverReply*)fCurrentRequest;
fCurrentRequest = nil;
discoverReply->fEvent = kIrDiscoverReplyEvent;
discoverReply->fPassiveDiscovery = false;
#if forMac
fDiscoverActive = false; #endif
fState = kIrLAPDisconnectedState;
GetLMP->EnqueueEvent(discoverReply);
}
break;
case kIrSlotTimerExpiredEvent:
XTRACE(kQueryTimeoutEvent, fDiscoverSlot, fDiscoverMaxSlots);
StopInput();
if (fDiscoverSlot < fDiscoverMaxSlots) {
fDiscoverSlot++;
}
else {
fDiscoverSlot = kIrLAPFinalSlot;
}
OutputXIDCommand();
break;
case kIrDisconnectRequestEvent:
XTRACE(kQueryDisconnectEvent, 0, 0);
XASSERT(fCurrentRequest != nil);
#if forMac
fDiscoverActive = false; #endif
HandleNDMDisconnectRequest();
break;
case kIrDiscoverRequestEvent:
case kIrListenRequestEvent:
case kIrConnectRequestEvent:
XTRACE(kUnexpectedEvent, fState, event);
RejectRequest(GetCurrentEvent(), kIrDAErrWrongState); break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TIrLAP::HandleQueryStateEvent: bad event");
break;
}
}
void TIrLAP::HandleConnectStateEvent(ULong event)
{
switch (event) {
case kIrChangeSpeedCompleteEvent:
XTRACE(kConnectChangeSpeed, 0, 0); OutputControlFrame(kIrLAPFrameRR); break;
case kIrInputCompleteEvent:
{
XTRACE(kConnectRecdInputEvent, fRecdCmdRsp, 0);
Boolean repostInput = true;
if (RecdFinalRsp(kIrLAPRspUA)) {
TUAPacket uaRsp;
if (GotData((UByte*)&uaRsp.fSrcDevAddr, kTUAPacketSize - 2)) {
if ((uaRsp.fSrcDevAddr == fPeerDevAddr) && (uaRsp.fDstDevAddr == fMyDevAddr)) {
IrDAErr result;
StopTimer();
result = ParseNegotiateAndInitConnState(true );
if (result != noErr) break;
GetIrDevice->ChangeSpeed(fMyQOS->GetBaudRate());
repostInput = false;
#if forMac fConnected = true; GetDiscovery->GetRemoteDeviceName( fPeerDevAddr, fNickName, sizeof(fNickName));
#endif
}
}
}
else if (RecdPollCmd(kIrLAPCmdSNRM)) {
TSNRMPacket snrmCmd;
if (GotData((UByte*)&snrmCmd.fSrcDevAddr, kTSNRMPacketSize - 2)) {
if ((snrmCmd.fDstDevAddr == fMyDevAddr) && (fMyDevAddr < snrmCmd.fSrcDevAddr)) {
IrDAErr result;
UByte connAddr = snrmCmd.fConnAddr >> 1;
if ((connAddr > 0) && (connAddr < kIrLAPBroadcastAddr)) {
fState = kIrLAPListenState;
fConnAddr = connAddr;
fPeerDevAddr = snrmCmd.fSrcDevAddr;
StopTimer();
check(connAddr); GetIrDevice->SetLAPAddress(connAddr);
result = ParseNegotiateAndInitConnState(false );
if (result != noErr) break;
OutputUAResponse();
repostInput = false;
}
}
}
}
else if (RecdCmd(kIrLAPCmdDISC) || RecdRsp(kIrLAPRspDM)) {
ConnLstnComplete(kIrDAErrCancel);
repostInput = false;
}
if (repostInput) {
StartInput(fIOBufferItem);
}
}
break;
case kIrOutputCompleteEvent:
XTRACE(kConnectOutputDoneEvent, fNextCmdRspToSend, fConnAddr);
switch (fNextCmdRspToSend) {
case kIrLAPCmdSNRM:
fRetryCount++;
StartTimer(kIrConnectFinalTimerTimeout, kIrFinalTimerExpiredEvent);
StartInput(fIOBufferItem);
break;
case kIrLAPFrameRR:
fLeadInCount = (UByte)fPeerQOS->GetExtraBOFs();
ConnLstnComplete(noErr);
StartTimer(fFinalTimerTimeout, kIrFinalTimerExpiredEvent);
fState = kIrLAPPriReceiveState;
StartDataReceive(); break;
default:
DebugLog("TIrLAP::HandleConnectStateEvent: bad output state");
break;
}
break;
case kIrFinalTimerExpiredEvent:
XTRACE(kConnectFinalTimeoutEvent, 0, 0);
if (fRetryCount < kMaxConnectRetries) {
StartTimer((25 + (random() % 50)) * kMilliseconds, kIrBackoffTimerExpiredEvent);
}
else {
StopInput();
ConnLstnComplete(kIrDAErrTimeout);
}
break;
case kIrBackoffTimerExpiredEvent:
XTRACE(kConnectBackoffTimeoutEvent, 0, 0);
StopInput();
OutputSNRMCommand();
break;
case kIrDisconnectRequestEvent:
XTRACE(kConnectDisconnectEvent, 0, 0);
XASSERT(fCurrentRequest != nil);
HandleNDMDisconnectRequest();
break;
case kIrDiscoverRequestEvent:
case kIrListenRequestEvent:
case kIrConnectRequestEvent:
XTRACE(kUnexpectedEvent, fState, event);
RejectRequest(GetCurrentEvent(), kIrDAErrWrongState); break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TIrLAP::HandleConnectStateEvent: bad event");
break;
}
}
void TIrLAP::HandleListenStateEvent(ULong event)
{
switch (event) {
case kIrInputCompleteEvent:
{
XTRACE(kListenRecdInputEvent, fRecdCmdRsp, 0);
Boolean repostInput = true;
if (RecdPollCmd(kIrLAPCmdSNRM)) {
TSNRMPacket snrmCmd;
if (GotData((UByte*)&snrmCmd.fSrcDevAddr, kTSNRMPacketSize - 2)) {
if (snrmCmd.fDstDevAddr == fMyDevAddr) {
IrDAErr result;
UByte connAddr = snrmCmd.fConnAddr >> 1;
if ((connAddr > 0) && (connAddr < kIrLAPBroadcastAddr)) {
fState = kIrLAPListenState;
fConnAddr = connAddr;
fPeerDevAddr = snrmCmd.fSrcDevAddr;
check(connAddr); GetIrDevice->SetLAPAddress(connAddr);
result = ParseNegotiateAndInitConnState(false );
if (result != noErr) break;
OutputUAResponse();
repostInput = false;
}
}
}
}
if (repostInput) {
StartInput(fIOBufferItem);
}
}
break;
case kIrOutputCompleteEvent:
XTRACE(kListenOutputDoneEvent, fNextCmdRspToSend, 0);
XASSERT(fNextCmdRspToSend == kIrLAPRspUA);
GetIrDevice->ChangeSpeed(fMyQOS->GetBaudRate());
break;
case kIrChangeSpeedCompleteEvent:
XTRACE(kListenChangeSpeed, 0, 0);
fLeadInCount = (UByte)fPeerQOS->GetExtraBOFs();
ConnLstnComplete(noErr);
StartTimer(fWatchdogTimeout, kIrWatchdogTimerExpiredEvent);
fState = kIrLAPSecReceiveState;
StartDataReceive(); break;
case kIrDisconnectRequestEvent:
XTRACE(kListenDisconnectEvent, 0, 0);
XASSERT(fCurrentRequest != nil);
HandleNDMDisconnectRequest();
break;
case kIrDiscoverRequestEvent:
case kIrListenRequestEvent: case kIrConnectRequestEvent:
XTRACE(kUnexpectedEvent, fState, event);
RejectRequest(GetCurrentEvent(), kIrDAErrWrongState); break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TIrLAP::HandleListenStateEvent: bad event");
break;
}
}
void TIrLAP::HandleReplyStateEvent(ULong event)
{
switch (event) {
case kIrInputCompleteEvent:
{
XTRACE(kReplyRecdInputEvent, fRecdCmdRsp, 0);
Boolean repostInput = true;
if (RecdPollCmd(kIrLAPCmdXID)) {
TXIDPacket xidCmd;
if (GotData(&xidCmd.fFormatId, kTXIDPacketSize - 2)) {
if (((xidCmd.fFormatId == kIrLAPDiscoveryXIDFormat)) &&
((xidCmd.fSrcDevAddr != 0) && (xidCmd.fSrcDevAddr != kIrLAPBroadcastDevAddr)) &&
((xidCmd.fDstDevAddr == kIrLAPBroadcastDevAddr) || ((xidCmd.fDstDevAddr == fMyDevAddr) && (xidCmd.fFlags & kIrLAPDiscoverFlagsNewAddr)))) {
if (xidCmd.fSlotNum != kIrLAPFinalSlot) {
if (fDiscoverEnteredReplyState) {
fState = kIrLAPReplyState;
fDiscoverMaxSlots = IrSlotCounts[xidCmd.fFlags & kIrLAPDiscoverFlagsSlotMask];
fDiscoverSlot = random() % fDiscoverMaxSlots;
fDiscoverReplied = false;
fReplacementDevAddr = 0;
#if forMac StartTimer(fDiscoverMaxSlots * 140 * kMilliseconds, kIrQueryTimerExpiredEvent);
#else
StartTimer(fDiscoverMaxSlots * 100 * kMilliseconds, kIrQueryTimerExpiredEvent);
#endif
fDiscoverEnteredReplyState = false;
}
if (!fDiscoverReplied && (xidCmd.fSlotNum >= fDiscoverSlot)) {
OutputXIDResponse(xidCmd);
fDiscoverReplied = true;
repostInput = false;
}
}
else {
StopTimer();
if (fReplacementDevAddr) fMyDevAddr = fReplacementDevAddr;
fState = kIrLAPDisconnectedState;
if (fCurrentRequest && fCurrentRequest->fEvent == kIrDiscoverRequestEvent) {
TIrDscInfo* discoveryInfo = TIrDscInfo::tIrDscInfo();
TIrDiscoverReply* discoverReply = (TIrDiscoverReply*)fCurrentRequest;
fCurrentRequest = nil;
discoverReply->fEvent = kIrDiscoverReplyEvent;
if (discoveryInfo == nil) {
discoverReply->fResult = kIrDAErrNoMemory;
}
else {
discoveryInfo->SetVersion(xidCmd.fVersion);
discoveryInfo->SetDeviceAddr(xidCmd.fSrcDevAddr);
discoveryInfo->ExtractDevInfoFromBuffer(fInputBuffer);
discoverReply->fDiscoveredDevices->InsertLast(discoveryInfo);
discoverReply->fResult = noErr;
discoverReply->fPassiveDiscovery = true;
}
repostInput = false;
GetLMP->EnqueueEvent(discoverReply);
}
else {
CIrDiscovery * discObj = GetDiscovery;
if( discObj ) {
TIrDscInfo* discoveryInfo = TIrDscInfo::tIrDscInfo();
if (discoveryInfo ) {
discoveryInfo->SetVersion(xidCmd.fVersion);
discoveryInfo->SetDeviceAddr(xidCmd.fSrcDevAddr);
discoveryInfo->ExtractDevInfoFromBuffer(fInputBuffer);
discObj->PassiveDiscovery( discoveryInfo );
}
}
}
}
}
}
}
if (!repostInput) break;
}
case kIrOutputCompleteEvent:
XTRACE(kReplyOutputDoneEvent, fNextCmdRspToSend, fDiscoverSlot);
StartInput(fIOBufferItem);
break;
case kIrQueryTimerExpiredEvent:
XTRACE(kReplyTimeoutEvent, 0, 0);
if (fReplacementDevAddr) fMyDevAddr = fReplacementDevAddr;
fState = kIrLAPDisconnectedState;
DebugLog("Missed final packet of peer discovery;g");
break;
case kIrDisconnectRequestEvent:
XTRACE(kReplyDisconnectEvent, 0, 0);
XASSERT(fCurrentRequest != nil);
HandleNDMDisconnectRequest();
break;
case kIrListenRequestEvent: {
XTRACE(kReplyListenRequestEvent, 0, 0);
TIrConnLstnReply* connLstnReply = (TIrConnLstnReply*)GetCurrentEvent();
connLstnReply->fEvent = kIrListenReplyEvent;
connLstnReply->fResult = kIrDAErrToolBusy;
GetLMP->EnqueueEvent(connLstnReply);
}
break;
case kIrDiscoverRequestEvent:
XTRACE(kUnexpectedEvent, fState, event);
RejectRequest(GetCurrentEvent(), kIrDAErrWrongState); break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TIrLAP::HandleReplyStateEvent: bad event");
break;
}
}
void TIrLAP::HandleNDMDisconnectRequest()
{
StopInput();
StopOutput();
StopTimer();
fDiscoverActive = false;
if (fCurrentRequest != nil) {
TIrEvent* reply = (TIrEvent*)fCurrentRequest;
fCurrentRequest = nil;
reply->fEvent = (UByte)RequestIdToReplyId(reply->fEvent);
reply->fResult = kIrDAErrCancel;
XTRACE(kNDMDisconnectFwdReply, fState, reply->fEvent);
GetLMP->EnqueueEvent(reply);
}
TIrDisconnectReply* discReply = (TIrDisconnectReply*)GetCurrentEvent();
discReply->fEvent = kIrDisconnectReplyEvent;
discReply->fResult = kIrDAErrCancel;
XTRACE(kNDMDisconnectReply, fState, 0);
fState = kIrLAPDisconnectedState;
GetLMP->EnqueueEvent(discReply);
}
void TIrLAP::HandlePriReceiveStateEvent(ULong event)
{
switch (event) {
case kIrFinalTimerExpiredEvent:
GetIrDevice->Stats_ReceiveTimeout();
XTRACE(kPriReceiveFinalTimeoutEvent, 0, 0);
StopInput();
if (fRetryCount >= fDisconnectLinkLimit) {
DisconnectComplete(kIrDAErrTimeout);
}
else {
if (fRetryCount == fDisconnectWarningLimit) {
fInBrokenBeam = true;
}
fRetryCount++;
OutputControlFrame(fLocalBusy ? kIrLAPFrameRNR : kIrLAPFrameRR);
}
break;
case kIrTurnaroundTimerExpiredEvent:
if (fEnteringCloseState) {
fNextCmdRspToSend = kIrLAPCmdDISC;
fState = kIrLAPPriCloseState;
}
else if (fSetLocalBusyPending) {
XTRACE(kSetLocalBusyEvent, 0, 0);
fNextCmdRspToSend = kIrLAPFrameRNR;
fLocalBusy = true;
fSetLocalBusyPending = false;
}
else if (fClrLocalBusyPending) {
XTRACE(kClrLocalBusyEvent, 0, 0);
fNextCmdRspToSend = kIrLAPFrameRR;
fLocalBusy = false;
fClrLocalBusyPending = false;
}
else if (fNextCmdRspToSend == kIrLAPFrameINFO) {
fValidRecdNr = 0;
fState = kIrLAPPriTransmitState;
NextState(kIrTurnaroundTimerExpiredEvent);
break;
}
OutputControlFrame(fNextCmdRspToSend); break;
case kIrOutputCompleteEvent:
XTRACE(kPriReceiveOutputDoneEvent, fNextCmdRspToSend, 0);
switch (fNextCmdRspToSend) {
case kIrLAPFrameRR:
case kIrLAPFrameRNR:
StartDataReceive();
StartTimer(fFinalTimerTimeout, kIrFinalTimerExpiredEvent);
break;
default:
DebugLog("TIrLAP::HandlePriReceiveStateEvent: bad output state");
break;
}
break;
case kIrInputCompleteEvent:
XTRACE(kPriReceiveRecdInputEvent, fRecdCmdRsp, (fRecdNs << 8) | fRecdNr);
if (RecdFinal()) {
StopTimer();
}
fRetryCount = 0;
#if forMac
fInitialRetryTime = 0;
fInBrokenBeam = false;
#endif
fNextCmdRspToSend = kIrLAPFrameINFO;
if (!RecdFinalRsp(kIrLAPRspFRMR)) gLastWasFRMR = false;
if (!RecdUFrame() || RecdRsp(kIrLAPRspUI)) {
if (RecdInvalidNrOrNs()) {
fProtocolErrs++;
if (0) { fEnteringCloseState = true;
}
XTRACE(kIgnoringInvalidNrNs, 0, 0);
}
else {
ProcessRecdInfoOrSuperFrame();
}
}
else if (RecdFinalRsp(kIrLAPRspFRMR)) {
UInt8 frmrInfo[3];
fInputBuffer->Getn( ( UInt8 * )&frmrInfo, 3 ); XTRACE(kPriReceiveFRMREvent, frmrInfo[0], *( UInt16 *)&frmrInfo[1] );
GetIrDevice->Stats_TransmitTimeout();
if (gLastWasFRMR) {
fEnteringCloseState = true;
XTRACE(kLogEnteringCloseState, 2, 2);
}
else
gLastWasFRMR = true; }
else if (RecdFinalRsp(kIrLAPRspRD) || RecdFinalRsp(kIrLAPRspRNRM)) {
fEnteringCloseState = true;
XTRACE(kLogEnteringCloseState, 3, 3);
}
else if (RecdFinal()) {
fProtocolErrs++;
}
else {
fProtocolErrs++;
}
if (fState == kIrLAPPriReceiveState) {
if (RecdFinal()) {
if( fRecdCmdRsp == kIrLAPFrameRNR ) {
StartTimer(fPollTimerTimeout>>2, kIrTurnaroundTimerExpiredEvent);
}
else
StartTimer(fMinTurnAroundTimeout, kIrTurnaroundTimerExpiredEvent);
}
else {
StartDataReceive();
}
}
break;
case kIrPutDataRequestEvent:
XTRACE(kPriReceivePutDataEvent, 0, 0);
PostponePutRequest();
break;
case kIrCancelPutRequestEvent:
CancelPutRequest();
break;
case kIrDisconnectRequestEvent:
XTRACE(kPriReceiveDisconnectEvent, 0, 0);
XASSERT(fPendingDisconnect == nil);
fPendingDisconnect = GetCurrentEvent();
fEnteringCloseState = true;
XTRACE(kLogEnteringCloseState, 4, 4);
break;
case kIrLocalBusyClearedEvent:
XTRACE(kPriReceiveClrLocBsyPendEvent, 0, 0);
break;
case kIrDiscoverRequestEvent:
case kIrListenRequestEvent:
case kIrConnectRequestEvent:
XTRACE(kUnexpectedEvent, fState, event);
RejectRequest(GetCurrentEvent(), kIrDAErrWrongState); break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TIrLAP::HandlePriReceiveStateEvent: bad event");
break;
}
}
void TIrLAP::HandlePriTransmitStateEvent(ULong event)
{
switch (event) {
case kIrPollTimerExpiredEvent:
#if forMac
#endif
XTRACE(kPriTransmitPollTimeoutEvent, 0, 0);
fWaitingForPollTimer = false;
StopInput();
OutputControlFrame(kIrLAPFrameRR); break;
case kIrTurnaroundTimerExpiredEvent:
XTRACE(kPriTransmitEnterEvent, 0, 0);
if (!fPendingPutRequests->IsEmpty() && ! fRemoteBusy) {
TIrPutRequest* putRequest = (TIrPutRequest*)fPendingPutRequests->Last();
XASSERT(putRequest != nil);
fPendingPutRequests->RemoveLast();
fPutReqsPending = !fPendingPutRequests->IsEmpty();
if( ( fWindow > 1 ) && fPutReqsPending ) {
StartTimer(fPollTimerTimeout, kIrPollTimerExpiredEvent);
}
OutputDataFrame(putRequest, !fLocalBusy && ((fWindow == 1) || !fPutReqsPending));
}
else {
NextState( kIrPollTimerExpiredEvent );
}
break;
case kIrOutputCompleteEvent:
XTRACE(kPriTransmitOutputDoneEvent, fNextCmdRspToSend, 0);
switch (fNextCmdRspToSend) { case kIrLAPFrameINFO:
if (--fWindow > 0 && fPutReqsPending) {
if (!fPendingPutRequests->IsEmpty()) {
TIrPutRequest* putRequest = (TIrPutRequest*)fPendingPutRequests->Last();
XASSERT(putRequest != nil);
fPendingPutRequests->RemoveLast();
fPutReqsPending = !fPendingPutRequests->IsEmpty();
if ( ( fWindow == 1 ) || !fPutReqsPending ) {
StopTimer();
}
OutputDataFrame(putRequest, !fLocalBusy && ((fWindow == 1) || !fPutReqsPending));
}
break;
}
else {
fWindow = fPeerWindowSize;
if (fLocalBusy) {
OutputControlFrame(kIrLAPFrameRNR); break;
}
else {
}
}
case kIrLAPFrameRR:
case kIrLAPFrameRNR:
StartTimer(fFinalTimerTimeout, kIrFinalTimerExpiredEvent);
fState = kIrLAPPriReceiveState;
StartDataReceive(); break;
default:
DebugLog("TIrLAP::HandlePriTransmitStateEvent: bad output state");
break;
}
break;
case kIrPutDataRequestEvent:
XTRACE(kPriTransmitPutDataEvent, 0, 0);
if (fWaitingForPollTimer && !fRemoteBusy) { fWaitingForPollTimer = false; StopTimer();
OutputDataFrame((TIrPutRequest*)GetCurrentEvent(), true); }
else
PostponePutRequest();
break;
case kIrCancelPutRequestEvent:
CancelPutRequest();
break;
case kIrDisconnectRequestEvent:
XTRACE(kPriTransmitDisconnectEvent, 0, 0);
XASSERT(fPendingDisconnect == nil);
fPendingDisconnect = GetCurrentEvent();
fEnteringCloseState = true;
XTRACE(kLogEnteringCloseState, 5, 5);
break;
case kIrLocalBusyClearedEvent:
XTRACE(kPriReceiveClrLocBsyPendEvent, 0, 0);
XASSERT(fClrLocalBusyPending);
break;
case kIrDiscoverRequestEvent:
case kIrListenRequestEvent:
case kIrConnectRequestEvent:
XTRACE(kUnexpectedEvent, fState, event);
RejectRequest(GetCurrentEvent(), kIrDAErrWrongState); break;
default:
XTRACE(kUnexpectedEvent, fState, event);
break;
}
}
void TIrLAP::HandlePriCloseStateEvent(ULong event)
{
switch (event) {
case kIrFinalTimerExpiredEvent:
XTRACE(kPriCloseFinalTimeoutEvent, 0, 0);
StopInput();
if (++fRetryCount >= kMaxDisconnectRetries) {
DisconnectComplete(kIrDAErrTimeout);
}
else {
OutputControlFrame(kIrLAPCmdDISC); }
break;
case kIrOutputCompleteEvent:
XTRACE(kPriCloseOutputDoneEvent, fNextCmdRspToSend, 0);
switch (fNextCmdRspToSend) {
case kIrLAPCmdDISC:
if (fEnteringCloseState) {
fEnteringCloseState = false;
fRetryCount = 0;
}
StartTimer(fFinalTimerTimeout, kIrFinalTimerExpiredEvent);
StartInput(fIOBufferItem);
break;
default:
DebugLog("TIrLAP::HandlePriCloseStateEvent: bad output state");
break;
}
break;
case kIrInputCompleteEvent:
XTRACE(kPriCloseRecdInputEvent, fRecdCmdRsp, (fRecdNs << 8) | fRecdNr);
if (RecdFinalRsp(kIrLAPRspUA) || RecdFinalRsp(kIrLAPRspDM)) {
DisconnectComplete(kIrDAErrCancel);
}
else {
StartInput(fIOBufferItem);
}
break;
case kIrCancelPutRequestEvent:
CancelPutRequest();
break;
case kIrPutDataRequestEvent:
NotConnectedCompletion(); break;
case kIrDiscoverRequestEvent:
case kIrListenRequestEvent:
case kIrConnectRequestEvent:
XTRACE(kUnexpectedEvent, fState, event);
RejectRequest(GetCurrentEvent(), kIrDAErrWrongState); break;
case kIrDisconnectRequestEvent: XTRACE(kPriCloseDisconnectRequest, 0, 0);
fPendingRequests->InsertLast(GetCurrentEvent());
break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TIrLAP::HandlePriCloseStateEvent: bad event");
break;
}
}
void TIrLAP::HandleSecReceiveStateEvent(ULong event)
{
switch (event) {
case kIrWatchdogTimerExpiredEvent:
GetIrDevice->Stats_ReceiveTimeout();
XTRACE(kSecReceiveWDTimeoutEvent, 0, 0);
if (fRetryCount >= fDisconnectLinkLimit) {
StopInput();
DisconnectComplete(kIrDAErrTimeout);
}
else {
if (fRetryCount == fDisconnectWarningLimit) {
fInBrokenBeam = true;
}
fRetryCount++;
StartTimer(fWatchdogTimeout, kIrWatchdogTimerExpiredEvent);
}
break;
case kIrTurnaroundTimerExpiredEvent:
if (fEnteringCloseState) {
fNextCmdRspToSend = fRespondingToDisconnect ? kIrLAPRspUA : kIrLAPRspRD;
fState = kIrLAPSecCloseState;
}
else if (fFRMRPending) {
OutputFRMRResponse();
fFRMRPending = false;
break;
}
else if (fSetLocalBusyPending) {
XTRACE(kSetLocalBusyEvent, 0, 0);
fNextCmdRspToSend = kIrLAPFrameRNR;
fLocalBusy = true;
fSetLocalBusyPending = false;
}
else if (fClrLocalBusyPending) {
XTRACE(kClrLocalBusyEvent, 0, 0);
fNextCmdRspToSend = kIrLAPFrameRR;
fLocalBusy = false;
fClrLocalBusyPending = false;
}
else if (fNextCmdRspToSend == kIrLAPFrameINFO) {
if (fRemoteBusy || fPendingPutRequests->IsEmpty()) {
fNextCmdRspToSend = fLocalBusy ? kIrLAPFrameRNR : kIrLAPFrameRR;
}
else {
fValidRecdNr = 0;
fState = kIrLAPSecTransmitState;
NextState(kIrTurnaroundTimerExpiredEvent);
break;
}
}
OutputControlFrame(fNextCmdRspToSend); break;
case kIrOutputCompleteEvent:
XTRACE(kSecReceiveOutputDoneEvent, fNextCmdRspToSend, 0);
switch (fNextCmdRspToSend) {
case kIrLAPFrameRR:
case kIrLAPFrameRNR:
case kIrLAPRspFRMR:
StartDataReceive();
StartTimer(fWatchdogTimeout, kIrWatchdogTimerExpiredEvent);
break;
default:
DebugLog("TIrLAP::HandleSecReceiveStateEvent: bad output state");
break;
}
break;
case kIrInputCompleteEvent:
XTRACE(kSecReceiveRecdInputEvent, fRecdCmdRsp, (fRecdNs << 8) | fRecdNr);
if (RecdPoll()) {
StopTimer();
}
fRetryCount = 0;
#if forMac
fInitialRetryTime = 0;
fInBrokenBeam = false;
#endif
fNextCmdRspToSend = kIrLAPFrameINFO;
if (fFRMRPending && !RecdPoll()) {
}
else if (!RecdUFrame() || RecdCmd(kIrLAPRspUI)) {
if (RecdInvalidNrOrNs()) {
fProtocolErrs++;
PrepareFRMRResponse();
}
else {
ProcessRecdInfoOrSuperFrame();
}
}
else if (RecdPollCmd(kIrLAPCmdDISC)) {
fEnteringCloseState = true;
XTRACE(kLogEnteringCloseState, 6, 6);
fRespondingToDisconnect = true;
}
else if (RecdPollCmd(kIrLAPCmdSNRM)) {
if (fRecdAddr == fConnAddr) {
fEnteringCloseState = true;
XTRACE(kLogEnteringCloseState, 7, 7);
fRespondingToDisconnect = false;
}
else {
fRecdPF = 0;
}
}
else if (RecdFinalRsp(kIrLAPRspDM)) {
DisconnectComplete(kIrDAErrCancel);
}
else {
fProtocolErrs++;
PrepareFRMRResponse();
}
if (fState == kIrLAPSecReceiveState) {
if (RecdPoll()) {
StartTimer(fMinTurnAroundTimeout, kIrTurnaroundTimerExpiredEvent);
}
else {
StartDataReceive();
}
}
break;
case kIrPutDataRequestEvent:
XTRACE(kSecReceivePutDataEvent, 0, 0);
PostponePutRequest();
break;
case kIrCancelPutRequestEvent:
CancelPutRequest();
break;
case kIrDisconnectRequestEvent:
XTRACE(kSecReceiveDisconnectEvent, 0, 0);
XASSERT(fPendingDisconnect == nil);
fPendingDisconnect = GetCurrentEvent();
fEnteringCloseState = true;
XTRACE(kLogEnteringCloseState, 8, 8);
fRespondingToDisconnect = false;
break;
case kIrLocalBusyClearedEvent:
XTRACE(kSecReceiveClrLocBsyPendEvent, 0, 0);
XASSERT(fClrLocalBusyPending);
break;
case kIrConnectRequestEvent: case kIrListenRequestEvent: XTRACE(kSecReceiveConnLstnRequest, 0, 0);
check(fCurrentRequest == nil);
fCurrentRequest = GetCurrentEvent(); ConnLstnComplete(noErr);
break;
case kIrDiscoverRequestEvent:
XTRACE(kUnexpectedEvent, fState, event);
RejectRequest(GetCurrentEvent(), kIrDAErrWrongState); break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TIrLAP::HandleSecReceiveStateEvent: bad event");
break;
}
}
void TIrLAP::HandleSecTransmitStateEvent(ULong event)
{
switch (event) {
case kIrTurnaroundTimerExpiredEvent:
{
XTRACE(kSecTransmitEnterEvent, 0, 0);
XASSERT(!fPendingPutRequests->IsEmpty() && !fRemoteBusy);
TIrPutRequest* putRequest = (TIrPutRequest*)fPendingPutRequests->Last();
XASSERT(putRequest != nil);
fPendingPutRequests->RemoveLast();
fPutReqsPending = !fPendingPutRequests->IsEmpty();
OutputDataFrame(putRequest, !fLocalBusy && ((fWindow == 1) || !fPutReqsPending));
}
break;
case kIrOutputCompleteEvent:
XTRACE(kSecTransmitOutputDoneEvent, fNextCmdRspToSend, 0);
switch (fNextCmdRspToSend) {
case kIrLAPFrameINFO:
if ((--fWindow > 0) && fPutReqsPending) {
TIrPutRequest* putRequest = (TIrPutRequest*)fPendingPutRequests->Last();
XASSERT(putRequest != nil);
fPendingPutRequests->RemoveLast();
fPutReqsPending = !fPendingPutRequests->IsEmpty();
OutputDataFrame(putRequest, !fLocalBusy && ((fWindow == 1) || !fPutReqsPending));
break;
}
else {
fWindow = fPeerWindowSize;
if (fLocalBusy) {
OutputControlFrame(kIrLAPFrameRNR); break;
}
else {
}
}
case kIrLAPFrameRR:
case kIrLAPFrameRNR:
StartTimer(fWatchdogTimeout, kIrWatchdogTimerExpiredEvent);
fState = kIrLAPSecReceiveState;
StartDataReceive(); break;
default:
DebugLog("TIrLAP::HandleSecTransmitStateEvent: bad output state");
break;
}
break;
case kIrPutDataRequestEvent:
XTRACE(kSecTransmitPutDataEvent, 0, 0);
PostponePutRequest();
break;
case kIrCancelPutRequestEvent:
CancelPutRequest();
break;
case kIrDisconnectRequestEvent:
XTRACE(kSecTransmitDisconnectEvent, 0, 0);
XASSERT(fPendingDisconnect == nil);
fPendingDisconnect = GetCurrentEvent();
fEnteringCloseState = true;
XTRACE(kLogEnteringCloseState, 9, 9);
break;
case kIrLocalBusyClearedEvent:
XTRACE(kSecTransmitClrLocBsyPendEvent, 0, 0);
XASSERT(fClrLocalBusyPending);
break;
case kIrConnectRequestEvent: case kIrListenRequestEvent: XTRACE(kSecTransmitConnLstnRequest, 0, 0);
check(fCurrentRequest == nil);
fCurrentRequest = GetCurrentEvent(); ConnLstnComplete(noErr);
break;
case kIrDiscoverRequestEvent:
XTRACE(kUnexpectedEvent, fState, event);
RejectRequest(GetCurrentEvent(), kIrDAErrWrongState); break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TIrLAP::HandleSecTransmitStateEvent: bad event");
break;
}
}
void TIrLAP::HandleSecCloseStateEvent(ULong event)
{
switch (event) {
case kIrWatchdogTimerExpiredEvent:
XTRACE(kSecCloseWDTimeoutEvent, 0, 0);
StopInput();
DisconnectComplete(kIrDAErrTimeout);
break;
case kIrTurnaroundTimerExpiredEvent:
OutputControlFrame(fNextCmdRspToSend); break;
case kIrOutputCompleteEvent:
XTRACE(kSecCloseOutputDoneEvent, fNextCmdRspToSend, 0);
switch (fNextCmdRspToSend) {
case kIrLAPRspRD:
fEnteringCloseState = false;
StartTimer(fWatchdogTimeout, kIrWatchdogTimerExpiredEvent);
StartInput(fIOBufferItem);
break;
case kIrLAPRspUA:
DisconnectComplete(kIrDAErrCancel);
break;
default:
DebugLog("TIrLAP::HandleSecCloseStateEvent: bad output state");
break;
}
break;
case kIrInputCompleteEvent:
XTRACE(kSecCloseRecdInputEvent, fRecdCmdRsp, 0);
StopTimer();
if (RecdPollCmd(kIrLAPCmdDISC)) {
fNextCmdRspToSend = kIrLAPRspUA;
StartTimer(fMinTurnAroundTimeout, kIrTurnaroundTimerExpiredEvent);
}
else if (RecdFinalRsp(kIrLAPRspDM)) {
DisconnectComplete(kIrDAErrCancel);
}
else if (RecdPoll()) {
fNextCmdRspToSend = kIrLAPRspRD;
StartTimer(fMinTurnAroundTimeout, kIrTurnaroundTimerExpiredEvent);
}
else {
StartTimer(fWatchdogTimeout, kIrWatchdogTimerExpiredEvent);
StartInput(fIOBufferItem);
}
break;
case kIrCancelPutRequestEvent:
CancelPutRequest();
break;
case kIrPutDataRequestEvent:
NotConnectedCompletion(); break;
case kIrDiscoverRequestEvent:
case kIrListenRequestEvent:
case kIrConnectRequestEvent:
XTRACE(kUnexpectedEvent, fState, event);
RejectRequest(GetCurrentEvent(), kIrDAErrWrongState); break;
case kIrDisconnectRequestEvent: XTRACE(kSecCloseDisconnectRequest, 0, 0);
fPendingRequests->InsertLast(GetCurrentEvent());
break;
default:
XTRACE(kUnexpectedEvent, fState, event);
DebugLog("TIrLAP::HandleSecCloseStateEvent: bad event");
break;
}
}
void TIrLAP::UpdateNrReceived()
{
XTRACE(kUpdateNrReceived, fNextToAck, fRecdNr);
while (fNextToAck != fRecdNr) {
TIrPutReply* putReply = (TIrPutReply*)fPutRequests[fNextToAck];
fPutRequests[fNextToAck] = nil;
PutComplete(putReply, noErr);
fValidRecdNr &= ~(1 << fNextToAck);
fNextToAck = (fNextToAck + 1) & 0x7;
}
}
void TIrLAP::ResendRejectedFrames()
{
ULong index = (fVs - 1) & 0x7;
XTRACE(kResendRejectedFrames, 0, index);
while (true) {
TIrPutRequest* putRequest = fPutRequests[index];
XASSERT(putRequest != nil);
if (putRequest == nil) {
break;
}
XTRACE(kResendRejectedFrames, 1, index);
fPendingPutRequests->InsertLast(putRequest);
fPutRequests[index] = nil;
fDataRetries++;
#if forMac
GetIrDevice->Stats_PacketResent();
#endif
if (index == fRecdNr) {
break;
} else {
index = (index - 1) & 0x7;
}
}
fVs = fRecdNr;
XTRACE(kResendRejectedFrames, 2, fVs);
}
void TIrLAP::ProcessRecdInfoOrSuperFrame()
{
XTRACE(kProcessISFrame, RecdCmd(), RecdRsp());
if (!Recd(kIrLAPRspUI)) {
if ((fPrimary && RecdCmd()) || (!fPrimary && RecdRsp())) {
fProtocolErrs++;
DisconnectComplete(kIrDAErrPacket);
return;
}
UpdateNrReceived();
}
switch(fRecdCmdRsp) {
case kIrLAPFrameINFO:
if (!fLocalBusy && !fSetLocalBusyPending) {
if (RecdUnexpectedNs()) {
fNextCmdRspToSend = kIrLAPFrameRR;
#if forMac
GetIrDevice->Stats_PacketDropped();
#endif
}
else {
XASSERT(fInputBuffer != fIOBufferItem);
if (fInputBuffer == fIOBufferItem) { DebugLog("oops, fInputbuffer == fIObufferItem 0x%lx", (uintptr_t) fInputBuffer);
}
GetLMP->Demultiplexor(fInputBuffer);
fValidRecdNs &= ~(1 << fVr);
fValidRecdNs |= 1 << ((fVr + fMyWindowSize) & 0x7);
fVr = (fVr + 1) & 0x7;
fInputBuffer = nil;
if (fGetBufferAvail == 0) {
XTRACE(kSetLocalBusyPendingEvent, 0, 0);
fSetLocalBusyPending = true;
}
if (RecdUnexpectedNr()) {
ResendRejectedFrames();
}
}
}
#if forMac
else
GetIrDevice->Stats_PacketDropped(); #endif
break;
case kIrLAPFrameRR:
fRemoteBusy = false;
if (RecdUnexpectedNr() && !fLocalBusy) {
ResendRejectedFrames();
}
#if forMac
GetIrDevice->Stats_RRRec();
#endif
break;
case kIrLAPFrameREJ:
ResendRejectedFrames();
#if forMac
GetIrDevice->Stats_REJRec();
#endif
break;
case kIrLAPFrameSREJ:
ResendRejectedFrames();
#if forMac
GetIrDevice->Stats_SREJRec();
#endif
break;
case kIrLAPFrameRNR:
fRemoteBusy = true;
fNextCmdRspToSend = fLocalBusy ? kIrLAPFrameRNR : kIrLAPFrameRR;
#if forMac
GetIrDevice->Stats_RNRRec(); #endif
break;
default:
XASSERT(fRecdCmdRsp == kIrLAPRspUI);
if (!fLocalBusy) {
}
break;
}
}
void TIrLAP::CopyStatsTo(TCMOSlowIRStats* irStats)
{
#if forMac
#pragma unused(irStats)
#else
irStats->dataRetries = fDataRetries;
irStats->protocolErrs = fProtocolErrs;
#endif
}
void TIrLAP::ResetStats()
{
fDataRetries = 0;
fProtocolErrs = 0;
}
IrDAErr TIrLAP::ParseNegotiateAndInitConnState(Boolean primary)
{
IrDAErr result;
ULong numBuffers;
ULong bufferSize;
CBufferSegment* bufferItem;
TTimeout retryTimeUnit;
TTimeout disconnectLinkTime;
fPrimary = primary;
result = fPeerQOS->ExtractInfoFromBuffer(fInputBuffer);
XREQUIRENOT(result, Fail_QOS_ExtractInfo);
result = fMyQOS->NegotiateWith(fPeerQOS);
XREQUIRENOT(result, Fail_QOS_NegotiateMe);
result = fPeerQOS->NegotiateWith(fMyQOS);
XREQUIRENOT(result, Fail_QOS_NegotiatePeer);
XASSERT(fMyQOS->GetBaudRate() == fPeerQOS->GetBaudRate());
XTRACE(kQOSSetBaudRateEvent, 0, fMyQOS->GetBaudRate());
fPollTimerTimeout = fMyQOS->GetMaxTurnAroundTime();
fFinalTimerTimeout = fPeerQOS->GetMaxTurnAroundTime();
fWatchdogTimeout = fPeerQOS->GetMaxTurnAroundTime() + (fPeerQOS->GetMaxTurnAroundTime() >> 2);
fMinTurnAroundTimeout = fPeerQOS->GetMinTurnAroundTime();
retryTimeUnit = primary ? fFinalTimerTimeout : fWatchdogTimeout;
disconnectLinkTime = fMyQOS->GetLinkDiscThresholdTime();
fDisconnectLinkLimit = (disconnectLinkTime + (retryTimeUnit >> 1)) / retryTimeUnit;
fDisconnectLinkLimitTime = fDisconnectLinkLimit * retryTimeUnit - retryTimeUnit;
if (disconnectLinkTime == kIrDisconnectWarningTimeout) {
fDisconnectWarningLimit = 0;
}
else {
fDisconnectWarningLimit = ((kIrDisconnectWarningTimeout + (retryTimeUnit >> 1)) / retryTimeUnit) - 1;
}
fPeerWindowSize = (UByte)fPeerQOS->GetWindowSize();
fMyWindowSize = (UByte)fMyQOS->GetWindowSize();
numBuffers = fMyQOS->GetWindowSize() * 2; bufferSize = fMyQOS->GetDataSize()+5;
check(numBuffers <= (sizeof(fGetBuffers) / sizeof(fGetBuffers[0]))); check(numBuffers < 32); for (fGetBufferAvail = 0, fNumGetBuffers = 0; fNumGetBuffers < numBuffers; fNumGetBuffers++) {
result = kIrDAErrNoMemory;
bufferItem = CBufferSegment::New( bufferSize );
XREQUIRE(bufferItem, Fail_BufferItem_New);
fGetBuffers[fNumGetBuffers] = bufferItem;
fGetBufferAvail |= (ULong) (1 << fNumGetBuffers);
}
XTRACE(kQOSBufferInfoEvent, fMyQOS->GetWindowSize(), fMyQOS->GetDataSize());
XTRACE(kQOSLeadInCountEvent, 0, fMyQOS->GetExtraBOFs());
XTRACE(kQOSMinTurnAroundEvent, 0, fMyQOS->GetMinTurnAroundTime() / kMicroseconds);
XTRACE(kQOSMaxTurnAroundEvent, 0, fMyQOS->GetMaxTurnAroundTime() / kMilliseconds);
XTRACE(kQOSBufferInfoEvent, fPeerQOS->GetWindowSize(), fPeerQOS->GetDataSize());
XTRACE(kQOSLeadInCountEvent, 1, fPeerQOS->GetExtraBOFs());
XTRACE(kQOSMinTurnAroundEvent, 1, fPeerQOS->GetMinTurnAroundTime() / kMicroseconds);
XTRACE(kQOSMaxTurnAroundEvent, 1, fPeerQOS->GetMaxTurnAroundTime() / kMilliseconds);
fVr = 0;
fVs = 0;
fWindow = fPeerWindowSize;
fValidRecdNs = 0xFF >> (8 - fMyWindowSize);
fRetryCount = 0;
#if forMac
fInitialRetryTime = 0;
fInBrokenBeam = false;
#endif
fRemoteBusy = false;
fLocalBusy = false;
fSetLocalBusyPending = false;
fClrLocalBusyPending = false;
fRecdNr = 0;
fRecdNs = 0;
fNextToAck = 0;
return noErr;
Fail_BufferItem_New:
FreeGetBuffers();
Fail_QOS_NegotiatePeer:
Fail_QOS_NegotiateMe:
Fail_QOS_ExtractInfo:
ConnLstnComplete(result);
return result;
}
void TIrLAP::ConnLstnComplete(IrDAErr result)
{
TIrConnLstnReply* connLstnReply = (TIrConnLstnReply*)fCurrentRequest;
XTRACE(kConnLstnComplete, fPeerDevAddr >> 16, fPeerDevAddr);
fCurrentRequest = nil;
if (connLstnReply) { if ((connLstnReply->fEvent == kIrConnectRequestEvent) || (connLstnReply->fEvent == kIrListenRequestEvent)) {
connLstnReply->fEvent = (UByte)RequestIdToReplyId(connLstnReply->fEvent);
connLstnReply->fPassiveConnect = (connLstnReply->fEvent == kIrConnectReplyEvent) && !fPrimary;
connLstnReply->fResult = result;
connLstnReply->fDevAddr = fPeerDevAddr; }
else { if (connLstnReply->fEvent == kIrDiscoverRequestEvent) {
RejectRequest(connLstnReply, kIrDAErrRetry); connLstnReply = nil; }
else {
XTRACE(kConnLstnComplete, (UInt16)-2, (UInt16)-2); }
}
}
else {
XTRACE(kConnLstnComplete, (UInt16)-1, (UInt16)-1); }
if (result != noErr) {
fState = kIrLAPDisconnectedState;
}
if (connLstnReply) GetLMP->EnqueueEvent(connLstnReply);
}
void TIrLAP::DisconnectComplete(IrDAErr result)
{
XASSERT(result != noErr);
StopTimer();
XASSERT(!fInputInProgress);
XASSERT(!fOutputInProgress);
StopInput();
StopOutput();
CancelPendingPutRequests(nil, kIrDAErrCancel);
#if forMac
fInBrokenBeam = false;
fConnected = false; fNickName[0] = 0;
#endif
fLocalBusy = false;
fSetLocalBusyPending = false;
fEnteringCloseState = false;
fFRMRPending = false;
fState = kIrLAPDisconnectedState;
if (fPendingDisconnect) {
TIrDisconnectReply* disconnectReply = (TIrDisconnectReply*)fPendingDisconnect;
fPendingDisconnect = nil;
disconnectReply->fEvent = kIrDisconnectReplyEvent;
disconnectReply->fResult = result;
XTRACE(kNRMDisconnectReply, fState, 0);
GetLMP->EnqueueEvent(disconnectReply);
fIrDA->Disconnected(false); Reset(); }
else {
XTRACE(kNRMDisconnectAsyncReply, fState, 0); fIrDA->Disconnected(true); }
ApplyDefaultConnParms();
if (fPendingRequests && !fPendingRequests->Empty()) {
CListIterator *iter = CListIterator::cListIterator(fPendingRequests);
TIrEvent *request;
for (request = (TIrEvent*)iter->FirstItem();
iter->More(); request = (TIrEvent*)iter->NextItem()) {
XTRACE(kNRMDisconnectRequeue,0, request->fEvent);
this->EnqueueEvent(request);
}
iter->release();
while (!fPendingRequests->Empty()) fPendingRequests->RemoveLast();
}
}
void TIrLAP::CancelPutRequest()
{
TIrCancelPutRequest* cancelPutRequest = (TIrCancelPutRequest*)GetCurrentEvent();
CancelPendingPutRequests(cancelPutRequest->fLSAPConn, kIrDAErrRequestCanceled);
cancelPutRequest->fEvent = kIrCancelPutReplyEvent;
cancelPutRequest->fResult = noErr;
cancelPutRequest->fLSAPConn->EnqueueEvent(cancelPutRequest);
}
void TIrLAP::CancelPendingPutRequests(TLSAPConn* lsapConn, IrDAErr returnCode)
{
FastInt index;
TIrPutReply* putReply;
for (index = 0; index < 8; index++) {
putReply = (TIrPutReply*)fPutRequests[index];
if ((putReply != nil) && ((lsapConn == nil) || (lsapConn == putReply->fLSAPConn))) {
fPutRequests[index] = nil;
PutComplete(putReply, returnCode);
}
}
for (index = fPendingPutRequests->GetArraySize() - 1; index >= 0 ; index--) {
putReply = (TIrPutReply*)fPendingPutRequests->At(index);
if ((putReply != nil) && ((lsapConn == nil) || (lsapConn == putReply->fLSAPConn))) {
fPendingPutRequests->RemoveAt(index);
PutComplete(putReply, returnCode);
}
}
}
void TIrLAP::PutComplete(TIrPutReply* putReply, IrDAErr result)
{
if (putReply == nil) {
}
else if (putReply->fLSAPConn != nil) {
putReply->fEvent = kIrPutDataReplyEvent;
putReply->fResult = result;
putReply->fLSAPConn->EnqueueEvent(putReply);
}
else {
fIrDA->ReleaseEventBlock(putReply);
}
}
void TIrLAP::NotConnectedCompletion()
{
TIrLSAPConnEvent* request = (TIrLSAPConnEvent*)GetCurrentEvent();
switch (request->fEvent) {
case kIrPutDataRequestEvent:
request->fEvent = kIrPutDataReplyEvent;
break;
default:
DebugLog("TIrLAP::NotConnectedCompletion: unexpected request");
break;
}
request->fResult = kIrDAErrNotConnected;
request->fLSAPConn->EnqueueEvent(request);
}
void TIrLAP::ApplyDefaultConnParms()
{
GetIrDevice->ChangeSpeed(k9600bps);
fLeadInCount = kIrDefaultLeadinCount;
}
void TIrLAP::StartDataReceive()
{
CBufferSegment* inputBuffer;
if (fInputBuffer == fIOBufferItem) fInputBuffer = nil;
if (fInputBuffer) { inputBuffer = fInputBuffer;
XTRACE( kReusingBuffer, 0, fInputBuffer );
}
else {
ULong flags; ULong index;
inputBuffer = fIOBufferItem;
for (index = 0, flags = 1; index < fNumGetBuffers; index++, flags <<= 1) {
if (fGetBufferAvail & flags) { fGetBufferAvail &= ~flags; inputBuffer = fGetBuffers[index];
XTRACE(kLogStartDataRcv1, 0, inputBuffer);
XTRACE(kLogStartDataRcv2, flags, index);
break;
}
}
}
if (inputBuffer == fIOBufferItem ) XTRACE( kUsingDefaultBuffer, 0, fIOBufferItem );
require(inputBuffer, Bogus);
StartInput(inputBuffer);
Bogus:
return;
}
void TIrLAP::ReleaseInputBuffer(CBufferSegment* inputBuffer)
{
ULong flags;
ULong index;
Boolean bufferFound = false;
XTRACE(kLogReleaseInputBuffer, 0, inputBuffer);
for (index = 0, flags = 1; index < fNumGetBuffers; index++, flags <<= 1) {
if (fGetBuffers[index] == inputBuffer) {
XASSERT((fGetBufferAvail & flags) == 0);
fGetBufferAvail |= flags;
bufferFound = true;
XTRACE(kLogReleaseInputBuffer2, flags, index);
}
}
require(bufferFound, BufferNotFound);
if (fSetLocalBusyPending) {
XTRACE(kAbortLocalBusyPendingEvent, 0, 0);
XASSERT(!fLocalBusy);
fSetLocalBusyPending = false;
}
else if (fLocalBusy && !fClrLocalBusyPending) {
XTRACE(kClrLocalBusyPendingEvent, 0, 0);
fLocalBusyClearedEvent->fEvent = kIrLocalBusyClearedEvent;
fLocalBusyClearedEvent->fResult = noErr;
fClrLocalBusyPending = true;
this->EnqueueEvent(fLocalBusyClearedEvent);
}
BufferNotFound:
return;
}
void TIrLAP::PostponePutRequest()
{
fPendingPutRequests->InsertFirst(GetCurrentEvent());
}
void TIrLAP::PrepareFRMRResponse()
{
fFRMRRejCtrlField = fRecdCtrl;
fFRMRMyNrAndNs = (fVr << kIrLAPNrShift) | (fVs << kIrLAPNsShift) | (fRecdCR ? kIrFRMRCrBit : 0);
if (RecdInvalidNr()) {
fFRMRReasonFlags = kIrFRMRFlagInvalidNrCount;
}
else if (RecdInvalidNs()) {
fFRMRReasonFlags = 0;
}
else {
fFRMRReasonFlags = kIrFRMRFlagUndefinedCtrl;
}
fFRMRPending = true;
}
void TIrLAP::OutputXIDCommand()
{
ULong deviceInfoLength = 0;
TIrDscInfo* myDscInfo;
TXIDPacket* xidCmd = (TXIDPacket*)fIOBufferItem->GetBufferPtr();
XTRACE(kDiscoverXIDCmdEvent, fDiscoverSlot, 0);
fNextCmdRspToSend = kIrLAPCmdXID;
xidCmd->fAddress = (kIrLAPBroadcastAddr << 1) | kIrLAPCommandBit;
xidCmd->fCmdRsp = kIrLAPCmdXID | kIrLAPPollBit;
xidCmd->fFormatId = kIrLAPDiscoveryXIDFormat;
xidCmd->fSrcDevAddr = fMyDevAddr;
xidCmd->fDstDevAddr = fConflictDevAddr;
xidCmd->fFlags = fDiscoverFlags;
xidCmd->fSlotNum = fDiscoverSlot;
xidCmd->fVersion = kIrLAPVersionNumber;
if (fDiscoverSlot == kIrLAPFinalSlot) {
#if forMac
myDscInfo = GetDiscovery->GetDiscoveryInfo();
#else
myDscInfo = fIrDA->GetMyDscInfo();
#endif
deviceInfoLength = myDscInfo->AddDevInfoToBuffer(&xidCmd->fDevInfo[0],
kMaxUnconnectedPacketSize - kTXIDPacketSize);
}
fPutBuffer->SetControlBuffer(&xidCmd->fAddress, kTXIDPacketSize + deviceInfoLength, true);
check(fLeadInCount == kIrDefaultLeadinCount); StartOutput(fPutBuffer, kIrDefaultLeadinCount );
}
void TIrLAP::OutputXIDResponse(TXIDPacket& xidCmd)
{
ULong deviceInfoLength;
UByte xidFlags = xidCmd.fFlags;
TIrDscInfo* myDscInfo;
TXIDPacket* xidRsp = (TXIDPacket*)fIOBufferItem->GetBufferPtr();
XTRACE(kDiscoverXIDRspEvent, fDiscoverSlot, xidFlags);
fNextCmdRspToSend = kIrLAPRspXID;
#if forMac
if( xidFlags & kIrLAPDiscoverFlagsNewAddr )
fReplacementDevAddr = ( UInt32 ) ( random() % 0xFFFFFFFE + 1 );
else
fReplacementDevAddr = 0;
#else
fReplacementDevAddr = xidFlags & kIrLAPDiscoverFlagsNewAddr ? (ULong)rand() % 0xFFFFFFFE + 1 : 0;
#endif
xidRsp->fAddress = kIrLAPBroadcastAddr << 1;
xidRsp->fCmdRsp = kIrLAPRspXID | kIrLAPFinalBit;
xidRsp->fFormatId = kIrLAPDiscoveryXIDFormat;
xidRsp->fSrcDevAddr = fReplacementDevAddr ? fReplacementDevAddr : fMyDevAddr;
xidRsp->fDstDevAddr = xidCmd.fSrcDevAddr;
xidRsp->fFlags = xidFlags & (kIrLAPDiscoverFlagsNewAddr | kIrLAPDiscoverFlagsSlotMask);
xidRsp->fSlotNum = fDiscoverSlot;
xidRsp->fVersion = kIrLAPVersionNumber;
#if forMac
myDscInfo = GetDiscovery->GetDiscoveryInfo();
#else
myDscInfo = fIrDA->GetMyDscInfo();
#endif
deviceInfoLength = myDscInfo->AddDevInfoToBuffer(&xidRsp->fDevInfo[0],
kMaxUnconnectedPacketSize - kTXIDPacketSize);
fPutBuffer->SetControlBuffer(&xidRsp->fAddress, kTXIDPacketSize + deviceInfoLength, true);
StartOutput(fPutBuffer, 10);
}
void TIrLAP::OutputSNRMCommand()
{
ULong qosDataLength;
TSNRMPacket* snrmCmd = (TSNRMPacket*)fIOBufferItem->GetBufferPtr();
fNextCmdRspToSend = kIrLAPCmdSNRM;
snrmCmd->fAddress = (kIrLAPBroadcastAddr << 1) | kIrLAPCommandBit;
snrmCmd->fCmdRsp = kIrLAPCmdSNRM | kIrLAPPollBit;
snrmCmd->fSrcDevAddr = fMyDevAddr;
snrmCmd->fDstDevAddr = fPeerDevAddr;
snrmCmd->fConnAddr = fConnAddr << 1;
qosDataLength = fMyQOS->AddInfoToBuffer(&snrmCmd->fQOSParmData[0],
kMaxUnconnectedPacketSize - kTSNRMPacketSize);
fPutBuffer->SetControlBuffer(&snrmCmd->fAddress, kTSNRMPacketSize + qosDataLength, true);
StartOutput(fPutBuffer, fLeadInCount);
}
void TIrLAP::OutputUAResponse()
{
ULong qosDataLength;
TUAPacket* uaRsp = (TUAPacket*)fIOBufferItem->GetBufferPtr();
#if forMac
if (!fConnected) { fConnected = true; GetDiscovery->GetRemoteDeviceName( fPeerDevAddr, fNickName, sizeof(fNickName) );
}
#endif
fNextCmdRspToSend = kIrLAPRspUA;
uaRsp->fAddress = fConnAddr << 1;
uaRsp->fCmdRsp = kIrLAPRspUA | kIrLAPFinalBit;
uaRsp->fSrcDevAddr = fMyDevAddr;
uaRsp->fDstDevAddr = fPeerDevAddr;
qosDataLength = fMyQOS->AddInfoToBuffer(&uaRsp->fQOSParmData[0],
kMaxUnconnectedPacketSize - kTUAPacketSize);
fPutBuffer->SetControlBuffer(&uaRsp->fAddress, kTUAPacketSize + qosDataLength, true);
XTRACE(kOutputUACommandEvent, uaRsp->fCmdRsp, uaRsp->fAddress );
XTRACE(kOutputUACommandEvent, qosDataLength >> 16, qosDataLength );
StartOutput(fPutBuffer, fLeadInCount);
}
void TIrLAP::OutputFRMRResponse()
{
TFRMRPacket* frmrRsp = (TFRMRPacket*)fIOBufferItem->GetBufferPtr();
fNextCmdRspToSend = kIrLAPRspFRMR;
frmrRsp->fAddress = fConnAddr << 1;
frmrRsp->fCmdRsp = kIrLAPRspFRMR | kIrLAPFinalBit;
frmrRsp->fRejCtrlField = fFRMRRejCtrlField;
frmrRsp->fMyNrAndNs = fFRMRMyNrAndNs;
frmrRsp->fReasonFlags = fFRMRReasonFlags;
fPutBuffer->SetControlBuffer(&frmrRsp->fAddress, kTFRMRPacketSize, true);
StartOutput(fPutBuffer, fLeadInCount);
}
void TIrLAP::OutputControlFrame(UByte cmdRsp)
{
TControlPacket* frame = (TControlPacket*)fIOBufferItem->GetBufferPtr();
fNextCmdRspToSend = cmdRsp;
frame->fAddress = (fConnAddr << 1) | (fPrimary ? kIrLAPCommandBit : 0);
frame->fCmdRsp = cmdRsp | kIrLAPPollBit;
if ((cmdRsp & kIrLAPUSIMask) != kIrLAPUnnumbered) {
frame->fCmdRsp |= fVr << kIrLAPNrShift;
}
if (cmdRsp == kIrLAPFrameRR) XTRACE(kOutputControlFrameRR, 0, fVr);
else XTRACE(kOutputControlFrame, cmdRsp, fVr);
fPutBuffer->SetControlBuffer(&frame->fAddress, kTControlPacketSize, true);
StartOutput(fPutBuffer, fLeadInCount);
#if forMac
switch( cmdRsp ) { case kIrLAPFrameRR:
GetIrDevice->Stats_RRSent();
break;
case kIrLAPFrameRNR:
GetIrDevice->Stats_RNRSent();
break;
case kIrLAPFrameREJ:
GetIrDevice->Stats_REJSent();
break;
case kIrLAPFrameSREJ:
GetIrDevice->Stats_SREJSent();
break;
}
#endif
}
void TIrLAP::OutputDataFrame(TIrPutRequest* request, Boolean finalOrPollFlag)
{
ULong lmPDULength;
UByte finalPollBit = finalOrPollFlag ? kIrLAPFinalBit : 0; TControlPacket* frame = (TControlPacket*)fIOBufferItem->GetBufferPtr();
if (finalPollBit) XTRACE(kOutputDataFrame, fVs, fVr);
else XTRACE(kOutputDataFrameNotFinal, fVs, fVr);
fNextCmdRspToSend = kIrLAPFrameINFO;
fPutRequests[fVs] = request;
fValidRecdNr |= 1 << fVs;
frame->fAddress = (fConnAddr << 1) | (fPrimary ? kIrLAPCommandBit : 0);
frame->fCmdRsp = kIrLAPFrameINFO | finalPollBit | (fVr << kIrLAPNrShift) | (fVs << kIrLAPNsShift);
fVs = (fVs + 1) & 0x7;
lmPDULength = GetLMP->FillInLMPDUHeader(request, frame->fLMPDUData);
fPutBuffer->SetControlBuffer(&frame->fAddress, kTControlPacketSize + lmPDULength, true);
fPutBuffer->SetDataBuffer(request->fData, request->fOffset, request->fLength);
StartOutput(fPutBuffer, (UInt32)fLeadInCount);
#if forMac
GetIrDevice->Stats_IFrameSent();
#endif
}
Boolean TIrLAP::GotData(UByte *data, ULong size)
{
ULong result;
result = fInputBuffer->Getn(data, size); XTRACE(kLogGotData, size, result); return (result == size);
}
Boolean TIrLAP::RecdCmd(UByte cmdPattern)
{
return fRecdCR && (fRecdCmdRsp == cmdPattern);
}
Boolean TIrLAP::RecdPollCmd(UByte cmdPattern)
{
return fRecdPF && RecdCmd(cmdPattern);
}
Boolean TIrLAP::RecdRsp(UByte rspPattern)
{
return !fRecdCR && (fRecdCmdRsp == rspPattern);
}
Boolean TIrLAP::RecdFinalRsp(UByte rspPattern)
{
return fRecdPF && RecdRsp(rspPattern);
}
void TIrLAP::StartTimer(TTimeout timeDelay, int refCon)
{
XTRACE(kLogStartTimer, timeDelay, refCon);
fIrDA->StartTimer(kTimer_LAP, timeDelay, refCon);
}
void TIrLAP::StopTimer()
{
XTRACE(kLogStopTimer, 0, 0);
fIrDA->StopTimer(kTimer_LAP);
}
void TIrLAP::TimerComplete(ULong refCon)
{
XTRACE(kLogTimerComplete, 0, refCon);
check((refCon >= kIrFirstIrLAPTimerEvent) && (refCon <= kIrLastIrLAPTimerEvent));
NextState(refCon);
}
void TIrLAP::StartOutput(TIrLAPPutBuffer* outputBuffer, ULong leadInCount)
{
fOutputInProgress = true;
fLastCmdRsp = fNextCmdRspToSend; #if forMac
GetIrDevice->StartTransmit(outputBuffer, leadInCount);
#else
fIrDA->StartTransmit(outputBuffer, leadInCount);
#endif
}
void TIrLAP::StopOutput()
{
fOutputInProgress = false;
#if !forMac // Packet was completely written during StartOutput
fIrDA->StopTransmit();
#endif
}
void TIrLAP::StartInput(CBufferSegment* inputBuffer)
{
XTRACE(kLogStartInput, 0, inputBuffer);
XTRACE(kLogStartInput2, 0, fInputBuffer);
require(inputBuffer, Bogus);
if (fInputBuffer && fInputBuffer != fIOBufferItem && inputBuffer != fInputBuffer) {
XTRACE(kLogStartInput3, 0xfeed, 0xbeef);
require(inputBuffer == fIOBufferItem, SanityLacks);
ReleaseInputBuffer(fInputBuffer); }
SanityLacks:
fInputInProgress = true;
fInputBuffer = inputBuffer; inputBuffer->Reset();
GetIrDevice->StartReceive(inputBuffer);
Bogus:
return;
}
void TIrLAP::StopInput()
{
fInputInProgress = false;
GetIrDevice->StopReceive();
}
void TIrLAP::OutputComplete()
{
fOutputInProgress = false;
#ifdef IRDA_TEST_FRAME_SUPPORTED
if (fHandlingTestFrame) {
TestFrameComplete();
}
else
#endif
{
XTRACE( kPacketOutput, 0, 0 );
NextState(kIrOutputCompleteEvent);
}
}
void TIrLAP::ChangeSpeedComplete()
{
if (fState == kIrLAPConnectState || fState == kIrLAPListenState)
NextState(kIrChangeSpeedCompleteEvent);
else {
XTRACE(kLogChangeSpeedCompleteIgnored, 0, 0);
}
}
Boolean TIrLAP::InputAborted()
{
XTRACE(kInputAborted, 0, 0);
if (fState == kIrLAPPriReceiveState && fMyWindowSize == 1) { StartTimer(fMinTurnAroundTimeout, kIrFinalTimerExpiredEvent);
return true;
}
return false;
}
void TIrLAP::InputComplete(UByte aField, UByte cField)
{
fRecdCR = aField & kIrLAPCommandBit;
fRecdAddr = aField >> 1;
fRecdPF = cField & kIrLAPPFMask;
UByte nrMask = 0;
UByte nsMask = 0;
fNrNsFlags = 0;
if ((cField & kIrLAPUSIMask) != kIrLAPUnnumbered) {
nrMask = kIrLAPNrMask;
fRecdNr = (cField & nrMask) >> kIrLAPNrShift;
if (fRecdNr != fVs) {
fNrNsFlags |= kIrLAPUnexpectedNr;
XTRACE(kUnexpectedNr, fRecdNr, fVs);
if ((fValidRecdNr & (1 << fRecdNr)) == 0) {
fNrNsFlags |= kIrLAPInvalidNr;
XTRACE(kInvalidNr, fValidRecdNr, fRecdNr); }
}
}
if ((cField & kIrLAPIMask) == kIrLAPInformation) {
nsMask = kIrLAPNsMask;
fRecdNs = (cField & nsMask) >> kIrLAPNsShift;
if (fRecdNs != fVr) {
fNrNsFlags |= kIrLAPUnexpectedNs;
XTRACE(kUnexpectedNs, fRecdNs, fVr);
if ((fValidRecdNs & (1 << fRecdNs)) == 0) {
fNrNsFlags |= kIrLAPInvalidNs;
XTRACE(kInvalidNs, fValidRecdNs, fRecdNs); }
}
}
fRecdCmdRsp = cField & ~(kIrLAPPFMask | nrMask | nsMask);
if (RecdSFrame()) { if (RecdPollOrFinal()) {
if (fRecdCmdRsp == kIrLAPFrameRR) XTRACE(kInputControlFrameRR, 0, fRecdNr);
else XTRACE(kInputControlFrame, fRecdCmdRsp, fRecdNr);
}
else {
XTRACE(kInputControlFrameNotFinal, cField, fRecdNr); }
}
else if (RecdIFrame()) { #if forMac
GetIrDevice->Stats_IFrameRec();
#endif
if (RecdPollOrFinal()) XTRACE(kInputDataFrame, fRecdNs, fRecdNr);
else {
XTRACE(kInputDataFrameNotFinal, fRecdNs, fRecdNr);
}
}
else if( RecdUFrame() ) {
GetIrDevice->Stats_UFrameRec();
}
fRecdCtrl = cField;
XASSERT ((fRecdAddr == kIrLAPBroadcastAddr) || (fRecdAddr == fConnAddr));
#ifdef IRDA_TEST_FRAME_SUPPORTED
if (fRecdCmdRsp == kIrLAPCmdTEST) {
HandleTestFrame();
}
else
#endif
if (fInputInProgress) { XTRACE( kValidPacketReceived, fState, 0 );
fInputInProgress = false; NextState(kIrInputCompleteEvent);
}
else {
XTRACE(kLogPacketDropped, 0, 0);
}
}
#ifdef IRDA_TEST_FRAME_SUPPORTED
void TIrLAP::HandleTestFrame()
{
XTRACE(kTestFrameReceivedEvent, fRecdAddr, 0);
ULong testFrameLength = fInputBuffer->GetSize();
ULong* testFrame = (ULong*)fInputBuffer->GetBufferPtr();
if ((fRecdAddr == fConnAddr) ||
((testFrameLength >= 8) && ((testFrame[1] == fMyDevAddr) || (testFrame[1] == kIrLAPSniffeeDevAddr) || (testFrame[1] == kIrLAPBroadcastDevAddr)))) {
if ((testFrame[1] == kIrLAPSniffeeDevAddr) &&
(fCurrentRequest != nil) && (fCurrentRequest->fEvent == kIrListenRequestEvent)) {
TestFrameComplete();
}
else {
fHandlingTestFrame = true;
fTestHeader.fAddress = (fRecdAddr << 1) | (fPrimary ? kIrLAPCommandBit : 0);
fTestHeader.fCmdRsp = kIrLAPRspTEST | kIrLAPFinalBit;
if (fRecdAddr == kIrLAPBroadcastAddr) {
testFrame[1] = testFrame[0];
testFrame[0] = fMyDevAddr;
}
fPutBuffer->SetControlBuffer(&fTestHeader.fAddress, kTTestHdrPacketSize, true);
fPutBuffer->SetDataBuffer(fInputBuffer, 0, testFrameLength);
StartOutput(fPutBuffer, fLeadInCount);
}
}
else {
TestFrameComplete();
}
} #endif
#ifdef IRDA_TEST_FRAME_SUPPORTED
void TIrLAP::TestFrameComplete()
{
XTRACE(kTestFrameOutputDoneEvent, 0, 0);
fHandlingTestFrame = false;
StartInput(fInputBuffer);
} #endif
void TIrLAP::RejectRequest(TIrEvent *request, IrDAErr err)
{
XTRACE(kRejectRequest, request->fEvent, err);
request->fEvent = (UByte)RequestIdToReplyId(request->fEvent);
request->fResult = err;
GetLMP->EnqueueEvent(request);
}
#if forMac
void LAPTimerNotifier( UInt32 refCon, UInt32 sig )
{
check( refCon );
TIrLAP * obj = ( TIrLAP * )refCon;
obj->TimerComplete( sig );
}
#endif
#undef super
#define super OSObject
OSDefineMetaClassAndStructors(TIrLAPPutBuffer, OSObject);
TIrLAPPutBuffer *
TIrLAPPutBuffer::tIrLAPPutBuffer()
{
TIrLAPPutBuffer *obj = new TIrLAPPutBuffer;
if (obj && !obj->init()) {
obj->release();
obj = nil;
}
return obj;
}
bool TIrLAPPutBuffer::init()
{
if (!super::init()) return false;
fCtrlBuf = nil;
fCtrlBufLength = 0;
fCtrlBufPos = 0;
fDataBuf = nil;
fDataBufOffset = 0;
fDataBufLength = 0;
fDataBufPos = 0;
return true;
}
void TIrLAPPutBuffer::free(void)
{
super::free();
}
void TIrLAPPutBuffer::SetControlBuffer(UByte* buffer, ULong length, Boolean initFirst)
{
if (initFirst) {
init();
}
fCtrlBuf = buffer;
fCtrlBufLength = length;
fCtrlBufPos = 0;
}
void TIrLAPPutBuffer::SetDataBuffer(CBuffer* buffer, ULong offset, ULong length)
{
fDataBuf = buffer;
fDataBufOffset = offset;
fDataBufLength = length;
fDataBufPos = 0;
}
UByte TIrLAPPutBuffer::Get(void)
{
UByte nextChar;
if (fCtrlBufPos < fCtrlBufLength) {
XASSERT(fCtrlBuf);
nextChar = fCtrlBuf[fCtrlBufPos++];
}
else if (fDataBufPos < fDataBufLength) {
nextChar = fDataBuf->Get();
fDataBufPos++;
}
else {
DebugLog("TIrLAPPutBuffer::Get: getting past end of buffer(s)");
nextChar = 0xFF;
}
return nextChar;
}
void TIrLAPPutBuffer::Seek(Long off, int dir)
{
#pragma unused(off)
XASSERT(((dir == kPosBeg) && (off == 0)) || ((dir == kPosCur) && (off == -1)));
if (dir == kPosBeg) {
fCtrlBufPos = 0;
if (fDataBuf) {
fDataBuf->Seek(fDataBufOffset, kPosBeg);
fDataBufPos = 0;
}
}
else {
if (fDataBufPos) {
XASSERT(fDataBuf);
fDataBuf->Seek(-1, kPosCur);
fDataBufPos--;
}
else if (fCtrlBufPos) {
fCtrlBufPos--;
}
}
}
Boolean TIrLAPPutBuffer::AtEOF(void) const
{
return (fCtrlBufPos == fCtrlBufLength) && (fDataBufPos == fDataBufLength);
}