/// <summary>
        /// Provides overriden implementation for Main Loop Service method.  Reflects associated IPort ConnState changes into this object.
        /// Services the underlying port read and port write actions to implement the basic functionality of this object.
        /// </summary>
        protected override void PerformMainLoopService()
        {
            System.Threading.Thread.Sleep(1);

            IBaseState portBaseState = portBaseStateObserver.Object;

            if (portBaseStateObserver.IsUpdateNeeded)
            {
                portBaseStateObserver.Update();

                IBaseState updatedBaseState = portBaseStateObserver.Object;

                if (updatedBaseState.ConnState != BaseState.ConnState)
                {
                    SetBaseState(updatedBaseState.ConnState, "Port ConnState changed", true);
                }

                portBaseState = updatedBaseState;
            }

            if (portBaseState.IsConnected)
            {
                if (portRdAction.ActionState.IsComplete && portRdActionParam.ActionResultEnum != ActionResultEnum.None)
                {
                    if (portRdActionParam.BytesRead > 0 && portWrAction.ActionState.CanStart)
                    {
                        portRdActionParam.ActionResultEnum = ActionResultEnum.None;
                        portWrActionParam.BytesToWrite     = portRdActionParam.BytesRead;
                        portWrAction.Start();
                    }
                }
                else if (portWrAction.ActionState.IsComplete && portWrActionParam.ActionResultEnum != ActionResultEnum.None)
                {
                    portWrActionParam.ActionResultEnum = ActionResultEnum.None;
                    portRdAction.Start();
                }
                else if (portRdAction.ActionState.CanStart && portWrAction.ActionState.CanStart)
                {
                    portWrActionParam.Reset();
                    portRdAction.Start();
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Provides the server specific version of the Part's Main Loop Service method.
        /// </summary>
        protected override void PerformMainLoopService()
        {
            base.PerformMainLoopService();

            InnerServiceFCServerAndStateRelay();

            bool portIsConnected = portBaseStateObserver.Object.IsConnected;

            if (portWriteAction.ActionState.IsPendingCompletion || portFlushAction.ActionState.IsPendingCompletion || portReinitializeAction.ActionState.IsPendingCompletion)
            {
                // we cannot service a new request until the write, flush, and/or reinitialize actions started in any prior service loop have completed.
                return;
            }

            bool resyncCommandStream = false;
            bool startWrite          = false;

            if (portIsConnected && portReadAction.ActionState.CanStart)
            {
                if (portReadAction.ActionState.IsComplete)
                {
                    serverFunctionContainer.requestAdu.PktBuf.numBytes = portReadActionParam.BytesRead;

                    string   ec        = null;
                    TimeSpan bufferAge = bufferFillStartTime.Age;
                    if (serverFunctionContainer.AttemptToDecodeRequestPkt(out ec))
                    {
                        if (String.IsNullOrEmpty(ec))
                        {
                            Log.Trace.Emit("Attempting to perform request ADU:{0}", serverFunctionContainer.requestAdu);

                            if (serverFunctionContainer.ServiceDecodedRequest(fcServer))
                            {
                                startWrite = true;
                            }
                            else
                            {
                                Log.Trace.Emit("Decoded request produced no response [ADU:{0}]", serverFunctionContainer.requestAdu);
                            }
                        }
                        else
                        {
                            Log.Error.Emit("Invalid request received: {0} [numBytes:{1}]", ec, portReadActionParam.BytesRead);
                            resyncCommandStream = true;
                        }

                        portReadActionParam.BytesRead = 0;
                    }
                    else if (portReadActionParam.BytesRead > 0)
                    {
                        if (port.PortBehavior.IsDatagramPort)
                        {
                            Log.Warning.Emit("Invalid partial request received from datagram port.  Discarding {0} bytes", portReadActionParam.BytesRead);

                            portReadActionParam.BytesRead = 0;
                        }
                        else if (bufferAge > Timeout)
                        {
                            Log.Warning.Emit("Incomplete Partial Request timeout after {0:f3} seconds.  Discarding {0} bytes", bufferAge.TotalSeconds, portReadActionParam.BytesRead);

                            portReadActionParam.BytesRead = 0;
                        }
                    }
                    else
                    {
                        Log.Trace.Emit("Empty read completed");
                    }
                }

                if (!resyncCommandStream)
                {
                    // start the read immediately even if we are also starting a write (keep the interface primed)
                    // do not start the next read if we need to resync the command stream

                    if (portReadActionParam.BytesRead == 0)
                    {
                        bufferFillStartTime = QpcTimeStamp.Now;
                    }

                    if (portReadActionParam.Buffer == null)
                    {
                        portReadActionParam.Buffer      = serverFunctionContainer.requestAdu.PktBuf.bytes;
                        portReadActionParam.BytesToRead = serverFunctionContainer.requestAdu.PktBuf.bytes.Length;
                    }

                    portReadAction.Start();
                }
            }
            else if (portReadAction.ActionState.IsComplete && portReadActionParam.BytesRead > 0)
            {
                Log.Debug.Emit("Discarding {0} bytes of read data: port is no longer connected");
                portReadActionParam.BytesRead = 0;
            }

            if (!portIsConnected)
            {
            }
            else if (startWrite)
            {
                Log.Trace.Emit("Writing response ADU:{0}", serverFunctionContainer.responseAdu);

                portWriteActionParam.Buffer       = serverFunctionContainer.responseAdu.PktBuf.bytes;
                portWriteActionParam.BytesToWrite = serverFunctionContainer.responseAdu.PktBuf.numBytes;
                portWriteActionParam.BytesWritten = 0;

                portWriteAction.Start();
            }
            else if (resyncCommandStream)
            {
                IPortBehavior portBehavior = port.PortBehavior;

                if (portBehavior.IsDatagramPort)
                {
                    // there is nothing to do for datagram ports.
                    // Each message is a seperate item so there is no "leftover" bytes from prior requests that we might need to get rid of.
                }
                else if (portBehavior.IsByteStreamPort && portBehavior.IsNetworkPort)
                {
                    Log.Debug.Emit("Forcing port to reset current connection after protocol decode error (drop and immediately reconnect)");
                    portReinitializeAction.Start();
                }
                else
                {
                    portFlushAction.Start();
                }
            }
        }