/* Generates acknowledgements, routes data frames to the network layer and indicates receipt of Ack and Cts to TxCoordination process. 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.expr.Variable; import ptolemy.data.type.BaseType; import ptolemy.kernel.CompositeEntity; import ptolemy.kernel.util.IllegalActionException; import ptolemy.kernel.util.NameDuplicationException; import ptolemy.kernel.util.NamedObj; ////////////////////////////////////////////////////////////////////////= // //// RxCoordination /** RxCoordination class is responsible for the sequence of events in response to a session setup request. When a RTS packet is received, RxCoordination sends a CTS back after SIFS seconds if NAV is zero (i.e. channel is available); when a data packet is received, a Ack is sent back after SIFS seconds and the data packet received will be forwarded to the network layer. RxCoordination also notifies TxCoordination process of the receipt of either CTS or Ack. @author Charlie Zhong @version RxCoordination.java,v 1.11 2004/04/22 19:46:17 ellen_zh Exp @since Ptolemy II 4.0 @Pt.ProposedRating Red (czhong) @Pt.AcceptedRating Red (reviewmoderator) */ public class RxCoordination 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 RxCoordination(CompositeEntity container, String name) throws IllegalActionException, NameDuplicationException { super(container, name); // create ports fromReception = new TypedIOPort(this, "fromReception", true, false); fromReception.setTypeEquals(BaseType.GENERAL); RXTXConfirm = new TypedIOPort(this, "RXTXConfirm", true, false); RXTXConfirm.setTypeEquals(BaseType.GENERAL); SinkRequest = new TypedIOPort(this, "SinkRequest", false, true); SinkRequest.setTypeEquals(BaseType.GENERAL); toPowerControl = new TypedIOPort(this, "toPowerControl", false, true); toPowerControl.setTypeEquals(BaseType.GENERAL); GotAck = new TypedIOPort(this, "GotAck", false, true); GotAck.setTypeEquals(BaseType.GENERAL); RXTXRequest = new TypedIOPort(this, "RXTXRequest", false, true); RXTXRequest.setTypeEquals(BaseType.GENERAL); } /////////////////////////////////////////////////////////////////// //// public variables //// /** Port receiving messages from the Reception block */ public TypedIOPort fromReception; /** Port receiving confirmation on RXTxRequest from the Reception block */ public TypedIOPort RXTXConfirm; /** Port sending messages to the network layer */ public TypedIOPort SinkRequest; /** Port sending messages to the PowerControl block */ public TypedIOPort toPowerControl; /** Port notifying the TxCoordination process of the receipt of Ack or Cts */ public TypedIOPort GotAck; /** Port sending messages to the Reception block */ public TypedIOPort RXTXRequest; /////////////////////////////////////////////////////////////////// //// public methods //// public void fire() throws IllegalActionException { super.fire(); int dAck; int ackto; Time endRx; RecordToken pdu; // perform the actions/computation done in the handleMessage() // method switch (_currentState) { case RxC_Idle: if (fromReception.hasToken(0)) { RecordToken msg = (RecordToken) fromReception.get(0); switch (((IntToken) msg.get("kind")).intValue()) { case NeedAck: if (_debugging) { _debug("Got NeedAck msg"); } dAck = ((IntToken) msg.get("dAck")).intValue(); ackto = ((IntToken) msg.get("ackto")).intValue(); endRx = new Time(getDirector(), ((DoubleToken) msg .get("endRx")).doubleValue()); if (dAck > 0) { dAck = dAck - _dRsp; } // create Ack _rspdu = _createPacket(Ack, dAck, ackto); // schedule SIFS timer setTimer(SifsTimeout, endRx.add(_dSifsDly * 1e-6)); _currentState = Wait_Sifs; break; case RxIndicate: pdu = (RecordToken) msg.get("pdu"); endRx = new Time(getDirector(), ((DoubleToken) msg .get("endRx")).doubleValue()); int Type = ((IntToken) pdu.get("Type")).intValue(); int Subtype = ((IntToken) pdu.get("Subtype")).intValue(); int durId = ((IntToken) pdu.get("durId")).intValue(); _rate = ((IntToken) msg.get("rxRate")).intValue(); switch (Type) { case ControlType: switch (Subtype) { case Ack: Token[] GotAckvalues = { new IntToken(GotAckMsg), new DoubleToken(endRx.getDoubleValue()) }; RecordToken GotAckmsg = new RecordToken( GotCtsMsgFields, GotAckvalues); // send the message to the TxCoordination process GotAck.send(0, GotAckmsg); break; case Cts: Token[] GotCtsvalues = { new IntToken(GotCts), new DoubleToken(endRx.getDoubleValue()) }; RecordToken GotCtsmsg = new RecordToken( GotCtsMsgFields, GotCtsvalues); // send the message to the TxCoordination process GotAck.send(0, GotCtsmsg); break; case Rts: Time currentTime = getDirector().getModelTime(); Time navEnd = currentTime.add(1.0); if ((_tNavEnd != null) && _tNavEnd instanceof Variable) { Token token = ((Variable) _tNavEnd).getToken(); navEnd = new Time(getDirector(), ((DoubleToken) token).doubleValue()); } //FIXME: assume it is instanceof variable. if (navEnd.compareTo(currentTime) <= 0) { // generate Cts int Addr2 = ((IntToken) pdu.get("Addr2")) .intValue(); _rspdu = _createPacket(Cts, durId - _dRsp, Addr2); setTimer(SifsTimeout, endRx .add(_dSifsDly * 1e-6)); _currentState = Wait_Sifs; } break; } break; case DataType: if (Subtype == Data) { RecordToken payload = (RecordToken) pdu .get("payload"); int payload_kind = ((IntToken) payload.get("kind")) .intValue(); // except power control messages, all others are sent // to the network layer if ((payload_kind >= PCmin) && (payload_kind <= PCmax)) { toPowerControl.send(0, payload); } else { SinkRequest.send(0, payload); } } break; } break; } } break; case Wait_Sifs: int kind = whoTimeout(); // check if a timer times out and which if (kind == SifsTimeout) { Token[] TXRequestvalues = { new IntToken(TxRequest), _rspdu, new IntToken(_rate) }; RecordToken txrq = new RecordToken(TxRequestMsgFields, TXRequestvalues); // send the message to the Transmission block RXTXRequest.send(0, txrq); _currentState = Wait_TxDone; } break; case Wait_TxDone: if (RXTXConfirm.hasToken(0)) { RXTXConfirm.get(0); _currentState = RxC_Idle; } break; } } /** Initialize the private variables. * @exception IllegalActionException If thrown by the base class. */ public void initialize() throws IllegalActionException { super.initialize(); _dSifsDly = _aSifsTime - _aRxTxTurnaroundTime; _dRsp = _aSifsTime + _aPreambleLength + _aPlcpHeaderLength + (_sAckCtsLng / _mBrate); _currentState = RxC_Idle; NamedObj macComposite = getContainer().getContainer(); if (macComposite.getAttribute("tNavEnd") != null) { _tNavEnd = macComposite.getAttribute("tNavEnd"); } else { _tNavEnd = null; throw new IllegalActionException("the MAC compositor " + "dosen't contain a parameter named tNavEnd"); } } private RecordToken _createPacket(int subtype, int duration, int RA) throws IllegalActionException { Token[] AckPacketValues = { new IntToken(0), new IntToken(ControlType), new IntToken(subtype), new IntToken(0), new IntToken(0), new IntToken(0), new IntToken(0), new IntToken(0), new IntToken(0), new IntToken(0), new IntToken(0), new IntToken(123), new IntToken(duration), new IntToken(RA), new IntToken(14 * 8) }; RecordToken pkt = new RecordToken(AckPacket, AckPacketValues); return pkt; } /////////////////////////////////////////////////////////////////// //// private variables //// private int _dSifsDly; /////////////////////////////////////////////////////////////////// //// private variables //// private int _dRsp; /////////////////////////////////////////////////////////////////// //// private variables //// private int _rate; private RecordToken _rspdu; private static final int SifsTimeout = 1; // define states in FSM private static final int RxC_Idle = 0; private static final int Wait_Sifs = 1; private static final int Wait_TxDone = 2; private int _currentState = RxC_Idle; }