/* Validates a received MPDU (MAC Protocol Data Unit).
Copyright (c) 2004-2005 The Regents of the University of California.
All rights reserved.
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, copy, modify, and distribute this
software and its documentation for any purpose, provided that the above=
copyright notice and the following two paragraphs appear in all copies
of this software.
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
ENHANCEMENTS, OR MODIFICATIONS.
PT_COPYRIGHT_VERSION_2
COPYRIGHTENDKEY
*/
package ptolemy.domains.wireless.lib.network.mac;
import ptolemy.actor.TypedIOPort;
import ptolemy.actor.util.Time;
import ptolemy.data.DoubleToken;
import ptolemy.data.IntToken;
import ptolemy.data.RecordToken;
import ptolemy.data.Token;
import ptolemy.data.UnionToken;
import ptolemy.data.type.BaseType;
import ptolemy.kernel.CompositeEntity;
import ptolemy.kernel.util.IllegalActionException;
import ptolemy.kernel.util.NameDuplicationException;
////////////////////////////////////////////////////////////////////////=
//
//// ValidateMpdu
/**
ValidateMpdu class checks the status field of the RxEnd message. If it indicates
no error, the received data is forwarded to FilterMpdu process. Otherwise,
the data is dropped and ChannelState process will be notified of using EIFS
as IFS (interframe space). In the case of correctly received data, this class
also check its data type. If it is a RTS packet, a timer is set. The duration
is set to be the time needed to receive a CTS, plus some guard time. If no CTS
is received before this timer expires, a RTSTimeout signal is sent to ChannelState
process, which will clear the channel reservation made earlier by the above
RTS packet.
@author Charlie Zhong, Xiaojun Liu and Yang Zhao
@version ValidateMpdu.java,v 1.18 2005/02/28 17:10:01 cxh Exp
@since Ptolemy II 4.0
@Pt.ProposedRating Red (czhong)
@Pt.AcceptedRating Red (reviewmoderator)
*/
public class ValidateMpdu extends MACActorBase {
/** Construct an actor with the specified name and container.
* The container argument must not be null, or a
* NullPointerException will be thrown.
* If the name argument is null, then the name is set to the empty
* string.
* This constructor write-synchronizes on the workspace.
* @param container The container.
* @param name The name of the actor.
* @exception IllegalActionException If the container is incompatible
* with this actor.
* @exception NameDuplicationException If the name coincides with
* an actor already in the container.
*/
public ValidateMpdu(CompositeEntity container, String name)
throws IllegalActionException, NameDuplicationException {
super(container, name);
// create ports
fromPHYLayer = new TypedIOPort(this, "fromPHYLayer", true, false);
// fromPHYLayer.setTypeEquals(BaseType.GENERAL);
toChannelState = new TypedIOPort(this, "toChannelState", false, true);
toChannelState.setTypeEquals(BaseType.GENERAL);
toFilterMpdu = new TypedIOPort(this, "toFilterMpdu", false, true);
toFilterMpdu.setTypeEquals(BaseType.GENERAL);
}
///////////////////////////////////////////////////////////////////
//// public variables ////
/** Port receiving messages from the PHY
*/
public TypedIOPort fromPHYLayer;
/** Port sending messages to the ChannelState process
*/
public TypedIOPort toChannelState;
/** Port sending received data packets to the FilterMpdu process
*/
public TypedIOPort toFilterMpdu;
///////////////////////////////////////////////////////////////////
//// public methods ////
public void fire() throws IllegalActionException {
super.fire();
int UseIfs;
// perform the actions/computation done in the handleMessage()
// method
int kind = whoTimeout(); // check if a timer times out and which
Time currentTime = getDirector().getModelTime();
switch (_currentState) {
case Rx_Idle:
if (kind == RtsTimeout) {
// send RtsTimeout message to ChannelState process
Token[] values = { new IntToken(RtsTimeout) };
RecordToken msgout = new RecordToken(RtsTimeoutMsgFields,
values);
toChannelState.send(0, msgout);
} else if (fromPHYLayer.hasToken(0)) {
// RecordToken msg = (RecordToken) fromPHYLayer.get(0);
UnionToken inputToken = (UnionToken) fromPHYLayer.get(0);
RecordToken msg = (RecordToken) inputToken.value();
if (((IntToken) msg.get("kind")).intValue() == RxStart) {
if (_debugging) {
_debug("the msg token received from PHY is : "
+ msg.toString());
}
IntToken t = (IntToken) msg.get("rxRate");
_rxRate = t.intValue();
// cancel the RTS timer
cancelTimer(_timer);
_currentState = Rx_Frame;
}
}
break;
case Rx_Frame:
if (fromPHYLayer.hasToken(0)) {
//RecordToken msg = (RecordToken) fromPHYLayer.get(0);
UnionToken inputToken = (UnionToken) fromPHYLayer.get(0);
RecordToken msg = (RecordToken) inputToken.value();
switch (((IntToken) msg.get("kind")).intValue()) {
case RxEnd:
_endRx = currentTime.subtract(_D1 * 1e-6);
if (((IntToken) msg.get("status")).intValue() == NoError) {
// if the received message is RTS, set RtsTimeout timer
if ((((IntToken) _pdu.get("Type")).intValue() == ControlType)
&& (((IntToken) _pdu.get("Subtype")).intValue() == Rts)) {
_dRts = (2 * _aSifsTime) + (2 * _aSlotTime)
+ (_sAckCtsLng / _rxRate)
+ _aPreambleLength + _aPlcpHeaderLength;
_timer = setTimer(RtsTimeout, currentTime
.add(_dRts * 1e-6));
}
// working with record tokens to represent messages
Token[] RxMpduvalues = { new IntToken(RxMpdu), _pdu,
new DoubleToken(_endRx.getDoubleValue()),
new IntToken(_rxRate) };
RecordToken msgout = new RecordToken(RxMpduMsgFields,
RxMpduvalues);
// forward the packet to FilterMpdu process
toFilterMpdu.send(0, msgout);
// use DIFS as IFS for normal packets
UseIfs = UseDifs;
} else {
// use EIFS as IFS if a packet is corrupted
UseIfs = UseEifs;
}
// send UseIfs message to ChannelState process
Token[] Ifsvalues = { new IntToken(UseIfs),
new DoubleToken(_endRx.getDoubleValue()) };
RecordToken msgout = new RecordToken(UseIfsMsgFields,
Ifsvalues);
toChannelState.send(0, msgout);
// go back to Rx_Idle state
_currentState = Rx_Idle;
break;
case RxData:
// store the packet and process it after RxEnd is received
_pdu = (RecordToken) msg.get("pdu");
//_pdu=msg;
break;
}
}
break;
}
}
/** Initialize the private variables.
* @exception IllegalActionException If thrown by the base class.
*/
public void initialize() throws IllegalActionException {
super.initialize();
_D1 = _aRxRfDelay + _aRxPlcpDelay;
_currentState = Rx_Idle;
_endRx = new Time(getDirector());
}
///////////////////////////////////////////////////////////////////
//// private variables ////
private int _dRts;
private int _rxRate;
private Time _endRx;
private RecordToken _pdu;
private Timer _timer;
private int _D1;
// define states in FSM
private static final int Rx_Idle = 0;
private static final int Rx_Frame = 1;
private int _currentState = Rx_Idle;
}