--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dbgagents/trkagent/engine/TrkFramingLayer.cpp Tue Mar 02 10:33:16 2010 +0530
@@ -0,0 +1,514 @@
+/*
+* Copyright (c) 2004 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+#include "TrkFramingLayer.h"
+
+#ifdef __USE_NEW_DEBUG_API__
+#include "trkdispatchlayer2.h"
+#else
+#include "TrkDispatchLayer.h"
+#endif
+
+#include "serframe.h"
+
+_LIT8(kPPP_FLAG, "~");
+_LIT8(kPPP_ESCAPE, "}");
+
+
+//
+//
+// CTrkFramingLayer implementation
+//
+//
+
+//
+// CTrkFramingLayer constructor
+//
+CTrkFramingLayer::CTrkFramingLayer(CTrkCommPort* aPort)
+ : iPort(aPort),
+ iFramingState(CTrkFramingLayer::eWaiting),
+ iEscape(0),
+ iFCS(0),
+ iSequenceId(0),
+ iOutSequenceId(1)
+{
+ // check the target endianness
+ TUint32 test;
+ TUint8 *byte_alias = (TUint8 *)&test;
+
+ // Write a specific 4-byte sequence and then read it as
+ // a 32-bit word. Big-endian systems yield one value and
+ // little-endian systems yield another.
+
+ byte_alias[ 0 ] = 0x12;
+ byte_alias[ 1 ] = 0x34;
+ byte_alias[ 2 ] = 0x56;
+ byte_alias[ 3 ] = 0x78;
+
+ if (test == 0x12345678)
+ iIsBigEndian = ETrue;
+ else
+ iIsBigEndian = EFalse;
+}
+
+//
+// CTrkFramingLayer destructor
+//
+CTrkFramingLayer::~CTrkFramingLayer()
+{
+ if (iPort)
+ {
+ iPort->ClosePort();
+ SafeDelete(iPort);
+ }
+
+ SafeDelete(iLastReply);
+}
+
+//
+// CTrkFramingLayer::Listen
+//
+// Start listening for incoming messages from the host debugger
+//
+void CTrkFramingLayer::Listen(CTrkDispatchLayer *aDispatchLayer)
+{
+ // Start listening asynchronously for incoming messages
+ iDispatchLayer = aDispatchLayer;
+
+ iPort->Listen(this);
+}
+
+//
+// CTrkFramingLayer::StopListening
+//
+// Stop listening for incoming messages from the host debugger
+//
+void CTrkFramingLayer::StopListening()
+{
+ iDispatchLayer = 0;
+ iPort->StopListening();
+}
+
+//
+// CTrkFramingLayer::HandleByte
+//
+// Handle a single incoming byte with a state machine
+//
+void CTrkFramingLayer::HandleByte(TUint8 aByte)
+{
+ // discard existing escape if needed
+ if (iFramingState != eInFrame)
+ iEscape = EFalse;
+
+ // handle state machine
+ switch (iFramingState)
+ {
+ case eWaiting:
+ {
+ // Start of a new packet
+ if (PPP_FLAG == aByte)
+ {
+ iFCS = PPPINITFCS;
+ iFramingState = eFound; // next state
+ }
+ break;
+ }
+
+ case eFound:
+ {
+ if (PPP_FLAG == aByte) // discard multiple flags
+ break;
+
+ iFramingState = eInFrame;
+
+ // fall through to eInFrame, receive first char
+ }
+
+ case eInFrame:
+ {
+ if (PPP_FLAG == aByte)
+ {
+ if (iEscape)
+ {
+ // [..., escape, flag] is bad frame; drop it
+ // send a NAK with the error.
+ RespondErr(kDSReplyNAK, kDSReplyEscapeError);
+
+ // clear the buffer
+ DiscardFrame();
+ }
+ else
+ {
+ // normal case, good packet
+ if (ProcessFrame())
+ {
+ iDispatchLayer->HandleMsg(iBuffer);
+ }
+
+ // now start all over again
+ DiscardFrame();
+ }
+ break;
+ }
+ else if (iEscape)
+ {
+ aByte ^= PPP_TRANS; // change character to new code
+ iEscape = EFalse; // no longer escaped character
+ }
+ else if (PPP_ESCAPE == aByte)
+ {
+ iEscape = ETrue; // next character is escaped
+ break;
+ }
+
+ // make sure our buffer is not full
+ if (iBuffer.Length() == iBuffer.MaxLength())
+ {
+ // overflow. send out a NAK immediately. go into an overflow state
+ // which will wait for the end of the packet.
+ RespondErr(kDSReplyNAK, kDSReplyOverflow);
+
+ iFramingState = eFrameOverflow;
+ break;
+ }
+
+ // append byte to buffer and compute running FCS (checksum)
+ iBuffer.Append(aByte);
+
+ iFCS = PPPFCS(iFCS, aByte);
+ break;
+ }
+
+ case eFrameOverflow:
+ {
+ // overflow occurred. throw away all characters and wait for a flag
+ if (PPP_FLAG == aByte)
+ {
+ DiscardFrame();
+ }
+ break;
+ }
+
+ default:
+ {
+ User::Panic(_L("Invalid Framing State"), __LINE__);
+ break;
+ }
+ }
+}
+
+//
+// CTrkFramingLayer::RespondOkL
+//
+// Send an ACK to the host debugger
+//
+void CTrkFramingLayer::RespondOkL(const TDesC8& aMsg)
+{
+ // compose the standard ACK message
+ TBuf8<3> reply;
+ reply.Zero();
+
+ reply.Append(kDSReplyACK);
+ reply.Append(iSequenceId);
+ reply.Append(kDSReplyNoError);
+
+ // now append the rest of the response if necessary
+ HBufC8 *ack = HBufC8::NewLC(aMsg.Length() + 3);
+ ack->Des().Copy(aMsg.Ptr(), aMsg.Length());
+
+ TPtr8 ptr(ack->Des());
+ ptr.Insert(0, reply);
+
+ // send it out
+ TUint ackTries = 3;
+ TInt leaveCode = KErrGeneral;
+
+ do
+ {
+ TRAP(leaveCode, SendMsgL(*ack));
+ ackTries--;
+ } while ((leaveCode != KErrNone) && ackTries > 0);
+
+ // now increment the sequence id
+ IncrementSequenceId();
+
+ // save this in case we need to resend it
+ SafeDelete(iLastReply);
+ iLastReply = ack->Des().AllocL();
+
+ CleanupStack::PopAndDestroy(ack);
+}
+
+//
+// CTrkFramingLayer::RespondErr
+//
+// Send an NAK to the host debugger
+//
+void CTrkFramingLayer::RespondErr(TUint8 aType, TUint8 aErr)
+{
+ // compose the standard NAK message
+ TBuf8<3> ack;
+ TUint ackTries = 3;
+ TInt leaveCode = KErrGeneral;
+
+ ack.Zero();
+ ack.Append(aType);
+ ack.Append(iSequenceId);
+ ack.Append(aErr);
+
+ // send it out
+ do
+ {
+ TRAP(leaveCode, SendMsgL(ack));
+ ackTries--;
+ } while ((leaveCode != KErrNone) && ackTries > 0);
+
+ if (kDSReplySequenceMissing != aErr)
+ {
+ // now increment the sequence id
+ IncrementSequenceId();
+ }
+
+ // save this in case we need to resend it
+ SafeDelete(iLastReply);
+ iLastReply = ack.Alloc();
+
+ if (!iLastReply)
+ User::Panic(_L("Failed to allocate reply buffer"), __LINE__);
+}
+
+//
+// CTrkFramingLayer::InformEventL
+//
+// Queue up an event on the target
+//
+void CTrkFramingLayer::InformEventL(const TDesC8& aMsg)
+{
+ // compose the message
+ TBuf8<1> id;
+ id.Zero();
+ id.Append(iOutSequenceId);
+ IncrementOutSequenceId();
+
+ HBufC8 *msg = HBufC8::NewLC(aMsg.Length() + 1);
+ msg->Des().Copy(aMsg.Ptr(), aMsg.Length());
+
+ TPtr8 ptr(msg->Des());
+ ptr.Insert(1, id);
+
+ // now send it out
+ TUint ackTries = 3;
+ TInt leaveCode = KErrGeneral;
+
+ do
+ {
+ TRAP(leaveCode, SendMsgL(*msg));
+ ackTries--;
+ } while ((leaveCode != KErrNone) && ackTries > 0);
+
+ CleanupStack::PopAndDestroy(msg);
+
+ if (leaveCode != KErrNone)
+ User::Leave(leaveCode);
+}
+
+//
+// CTrkFramingLayer::SendRawMsgL
+//
+// Frames a message and sends it back to the host debugger
+//
+void CTrkFramingLayer::SendRawMsgL(const TDesC8& aMsg)
+{
+ iPort->SendDataL(aMsg);
+}
+
+
+//
+// CTrkFramingLayer::SendMsgL
+//
+// Frames a message and sends it back to the host debugger
+//
+void CTrkFramingLayer::SendMsgL(const TDesC8& aMsg)
+{
+ FCSType fcs;
+ FCSType acc;
+
+ // allocate room for this message with ample space for escape sequences and framing
+ HBufC8 *msg = HBufC8::NewLC(aMsg.Length() + 100);
+
+ TPtr8 ptr(msg->Des());
+
+ // walk through buffer, computing frame check sequence
+ // (checksum).
+
+ fcs = PPPINITFCS;
+
+ for (TInt i=0; i<aMsg.Length(); i++)
+ fcs = PPPFCS(fcs, aMsg[i]);
+
+ fcs = fcs ^ PPPCOMPFCS; // finish by complementing
+
+ // send bytes out the comm channel:
+ // [0x7E (frame flag)] [...data...] [FCS:8 or FCS:16 or FCS:32] [0x7E (frame flag)]
+
+ // FLAG
+ ptr.Append(kPPP_FLAG);
+
+ // DATA
+ TBuf8<1> byte;
+
+ for (TInt i=0; i<aMsg.Length(); i++)
+ {
+ byte.Zero();
+ byte.Append(aMsg[i]);
+
+ // escape if necessary
+ if (byte[0] == PPP_FLAG || byte[0] == PPP_ESCAPE)
+ {
+ ptr.Append(kPPP_ESCAPE);
+ byte[0] ^= PPP_TRANS;
+ }
+
+ ptr.Append(byte);
+ }
+
+ // FCS always goes out in little endian (LSB, ... , MSB) order
+ acc = fcs; // accumulator
+
+ TInt fcsSize = sizeof(FCSType);
+
+ for (TInt i=0; i<fcsSize; i++)
+ {
+ byte.Zero();
+ byte.Append(acc & 0xFF);
+
+ acc >>= 8;
+
+ // escape if necessary
+ if (byte[0] == PPP_FLAG || byte[0] == PPP_ESCAPE)
+ {
+ ptr.Append(kPPP_ESCAPE);
+ byte[0] ^= PPP_TRANS;
+ }
+
+ ptr.Append(byte);
+ }
+
+ // FLAG
+ ptr.Append(kPPP_FLAG);
+
+ iPort->SendDataL(*msg);
+
+ CleanupStack::PopAndDestroy(msg);
+}
+
+//
+// CTrkFramingLayer::DiscardFrame
+//
+// Trash the existing message and reset the state machine
+//
+void CTrkFramingLayer::DiscardFrame()
+{
+ iBuffer.Zero();
+ iFramingState = eWaiting;
+}
+
+//
+// CTrkFramingLayer::ProcessFrame
+//
+// Checks a complete message for correct format
+//
+TBool CTrkFramingLayer::ProcessFrame()
+{
+ // the buffer contains data in the following form:
+ // [data] [FCS8]
+ // or:
+ // [data] [FCS16]
+ // or:
+ // [data] [FCS32]
+ //
+ // where data is arbitrary length and FCSxx is 1, 2 or 4 bytes
+
+ TInt minSize = 2 + sizeof(FCSType);
+
+ if (iBuffer.Length() < minSize)
+ {
+ // data received is too short
+ RespondErr(kDSReplyNAK, kDSReplyPacketSizeError);
+ DiscardFrame();
+ return EFalse;
+ }
+
+ // check for FCS
+ if (PPPGOODFCS != iFCS)
+ {
+ // bad checksum (FCS)
+ RespondErr(kDSReplyNAK, kDSReplyBadFCS);
+ DiscardFrame();
+ return EFalse;
+ }
+
+ // make sure the sequence id is correct, then increment
+ if (iBuffer[TRK_MSG_SID_INDEX] == 0)
+ {
+ // special case - resets both sequence ids
+ iSequenceId = 0;
+ iOutSequenceId = 1;
+ }
+ else
+ {
+ // see which id we're dealing with
+ if ((iBuffer[0] != kDSReplyACK) && (iBuffer[0] != kDSReplyNAK))
+ {
+ // a command from the host
+ if (iBuffer[TRK_MSG_SID_INDEX] == iSequenceId)
+ {
+ // got the expected sequence id - do nothing
+ }
+ else if (iBuffer[TRK_MSG_SID_INDEX] == (iSequenceId - 1))
+ {
+ // we need to resend the last reply
+ TUint ackTries = 3;
+ TInt leaveCode = KErrGeneral;
+
+ do
+ {
+ TRAP(leaveCode, SendMsgL(*iLastReply));
+ ackTries--;
+ } while ((leaveCode != KErrNone) && ackTries > 0);
+
+ return EFalse;
+ }
+ else
+ {
+ // bad sequence id
+ RespondErr(kDSReplyNAK, kDSReplySequenceMissing);
+ DiscardFrame();
+ return EFalse;
+ }
+ }
+ }
+
+ // trim back packet, eliminating FCS
+ iBuffer.Delete(iBuffer.Length()-1, 1);
+
+ // remove sequence id
+ iBuffer.Delete(1, 1);
+
+ return ETrue;
+}