예제 #1
0
        /// <summary>Contructor</summary>
        public ModbusServerFunctionPortAdapter(string partID, SerialIO.PortConfig portConfig, IModbusFCServer fcServer, ADUType aduType, byte unitID, bool responseToAllUnits)
            : base(partID, initialSettings: SimpleActivePartBaseSettings.DefaultVersion2.Build(waitTimeLimit: (0.2).FromSeconds()))
        {
            this.fcServer = fcServer;

            Timeout = portConfig.ReadTimeout;
            portConfig.ReadTimeout = TimeSpan.FromSeconds(Math.Max(0.1, Timeout.TotalSeconds));

            port = SerialIO.Factory.CreatePort(portConfig);
            portBaseStateObserver = new SequencedRefObjectSourceObserver <IBaseState, Int32>(port.BaseStateNotifier);

            IPortBehavior portBehavior = port.PortBehavior;

            IDictionary <string, Logging.IMesgEmitter> emitters = new Dictionary <string, Logging.IMesgEmitter>()
            {
                { "Issue", Log.Error }, { "Debug", Log.Debug }, { "Trace", Log.Trace }
            };

            serverFunctionContainer = new ServerFunctionContainer()
            {
                ADUType = aduType, Emitters = emitters, UnitID = unitID, RTUAddr = unitID, MBAPUnitID = unitID, RespondToAllTargets = responseToAllUnits
            };

            FlushPeriod = (portBehavior.IsDatagramPort ? TimeSpan.FromSeconds(0.0) : TimeSpan.FromSeconds(0.1));

            portReadAction = port.CreateReadAction(portReadActionParam = new ReadActionParam()
            {
                WaitForAllBytes = false
            });
            portWriteAction        = port.CreateWriteAction(portWriteActionParam = new WriteActionParam());
            portFlushAction        = port.CreateFlushAction(FlushPeriod);
            portReinitializeAction = port.CreateGoOnlineAction(true);

            portReadAction.NotifyOnComplete.AddItem(threadWakeupNotifier);
            portWriteAction.NotifyOnComplete.AddItem(threadWakeupNotifier);
            portFlushAction.NotifyOnComplete.AddItem(threadWakeupNotifier);
            portReinitializeAction.NotifyOnComplete.AddItem(threadWakeupNotifier);

            port.BaseStateNotifier.NotificationList.AddItem(threadWakeupNotifier);

            AddMainThreadStartingAction(() => port.StartPart());
            AddMainThreadStoppingAction(() => port.StopPart());

            AddExplicitDisposeAction(() => Fcns.DisposeOfObject(ref port));
        }
예제 #2
0
        /// <summary>
        /// Services the previously decoded request ADU packet by invoking the correspondingly selected method in the given IModbusFCServer instance and using
        /// the response and data that it provides to generate the response packet (if any) that can be sent back to the client.
        /// Returns true if a response packet is available to send or false if this request produced no response packet.
        /// </summary>
        /// <returns>true if a response packet is available to send or false if this request produced no response packet.</returns>
        public bool ServiceDecodedRequest(IModbusFCServer fcServer)
        {
            fcServer.Service();

            // update the responseAdu as an appropriate response to the requestAdu
            responseAdu.PktBuf.Clear();

            responseAdu.FCInfo = requestAdu.FCInfo;
            responseAdu.ADUType = requestAdu.ADUType;
            responseAdu.NumItemsInResponse = requestAdu.NumReadItemsInRequest;
            responseAdu.ExceptionCodeToSend = ExceptionCode.None;

            if (RespondToAllTargets)
            {
                // respond as whatever target the request was aimed at
                if (ADUType == ADUType.RTU)
                    responseAdu.RTUAddr = requestAdu.RTUAddr;
                else
                    responseAdu.UnitID = requestAdu.UnitID;
            }
            else
            {
                if (ADUType == ADUType.RTU)
                {
                    if (requestAdu.RTUAddr != RTUAddr)
                    {
                        Debug.Emitter.Emit("Ignoring miss-addressed request {0} {1} RTUAddr:{2}", requestAdu.ADUType, requestAdu.FCInfo.FC, requestAdu.RTUAddr);
                        return false;   // the request is not for us
                    }
                    responseAdu.RTUAddr = RTUAddr;
                }
                else
                {
                    if (requestAdu.UnitID != MBAPUnitID)
                    {
                        Debug.Emitter.Emit("Ignoring miss-addressed request {0} {1} UnitID:{2}", requestAdu.ADUType, requestAdu.FCInfo.FC, requestAdu.UnitID);
                        return false;   // the request is not for us
                    }
                    responseAdu.UnitID = MBAPUnitID;
                }
            }

            responseAdu.InitializeResponsePDU();       // sets up internal pointer to count/length values for later use.

            ExceptionCode exceptionCode = ExceptionCode.None;

            try
            {
                // extract the relevant data from the requestADU
                if (exceptionCode == ExceptionCode.None)
                {
                    // get the correct data from the request
                    bool getDataSuccess = true;

                    switch (requestAdu.FCInfo.FC)
                    {
                        case FunctionCode.FC0f_WriteMultipleCoils: getDataSuccess = GetDiscretes(false, coilArray, 0, requestAdu.NumWriteItemsInRequest); break;
                        case FunctionCode.FC10_WriteMutlipleHoldingRegisters: getDataSuccess = GetRegisters(false, holdingRegisterArray, 0, requestAdu.NumWriteItemsInRequest); break;
                        case FunctionCode.FC17_ReadWriteMultipleRegisters: getDataSuccess = GetRegisters(false, holdingRegisterArray, 0, requestAdu.NumWriteItemsInRequest); break;
                        default: break;
                    }

                    if (!getDataSuccess)
                        exceptionCode = ExceptionCode.IllegalDataValue;
                }

                // ask the fcServer to perform the requested action
                if (exceptionCode == ExceptionCode.None)
                {
                    switch (requestAdu.FCInfo.FC)
                    {
                        case FunctionCode.FC00_None: exceptionCode = ExceptionCode.IllegalFunction; break;
                        case FunctionCode.FC01_ReadCoils: exceptionCode = fcServer.FC01_ReadCoils(requestAdu.FirstReadItemAddrInRequest, requestAdu.NumReadItemsInRequest, coilArray); break;
                        case FunctionCode.FC02_ReadDiscretes: exceptionCode = fcServer.FC02_ReadDiscretes(requestAdu.FirstReadItemAddrInRequest, requestAdu.NumReadItemsInRequest, discreteArray); break;
                        case FunctionCode.FC03_ReadHoldingRegisters: exceptionCode = fcServer.FC03_ReadHoldingRegisters(requestAdu.FirstReadItemAddrInRequest, requestAdu.NumReadItemsInRequest, holdingRegisterArray); break;
                        case FunctionCode.FC04_ReadInputRegisters: exceptionCode = fcServer.FC04_ReadInputRegisters(requestAdu.FirstReadItemAddrInRequest, requestAdu.NumReadItemsInRequest, inputRegisterArray); break;
                        case FunctionCode.FC05_WriteSingleCoil: exceptionCode = fcServer.FC05_WriteSingleCoil(requestAdu.FirstWriteItemAddrInRequest, (HeaderWord2 != 0)); break;
                        case FunctionCode.FC06_WriteSingleHoldingRegister: exceptionCode = fcServer.FC06_WriteSingleHoldingRegister(requestAdu.FirstWriteItemAddrInRequest, unchecked((Int16) HeaderWord2)); break;
                        case FunctionCode.FC08_Diagnostics: exceptionCode = ExceptionCode.IllegalFunction; break;
                        case FunctionCode.FC0f_WriteMultipleCoils: exceptionCode = fcServer.FC0f_WriteCoils(requestAdu.FirstWriteItemAddrInRequest, requestAdu.NumWriteItemsInRequest, coilArray); break;
                        case FunctionCode.FC10_WriteMutlipleHoldingRegisters: exceptionCode = fcServer.FC10_WriteMutlipleHoldingRegisters(requestAdu.FirstWriteItemAddrInRequest, requestAdu.NumWriteItemsInRequest, holdingRegisterArray); break;
                        case FunctionCode.FC16_MaskWriteRegister: exceptionCode = fcServer.FC16_MaskWriteRegister(requestAdu.FirstWriteItemAddrInRequest, unchecked((Int16) HeaderWord2), unchecked((Int16) HeaderWord3)); break;
                        case FunctionCode.FC17_ReadWriteMultipleRegisters: exceptionCode = fcServer.FC17_ReadWriteMultipleRegisters(requestAdu.FirstReadItemAddrInRequest, requestAdu.NumReadItemsInRequest, inputRegisterArray, requestAdu.FirstWriteItemAddrInRequest, requestAdu.NumWriteItemsInRequest, holdingRegisterArray); break;
                        case FunctionCode.FC2b_EncapsulatedInterfaceTransport: exceptionCode = ExceptionCode.IllegalFunction; break;
                        default: exceptionCode = ExceptionCode.IllegalFunction; break;
                    }
                }

                // if the fcServer operation succeeded then build a normal response packet
                if (exceptionCode == ExceptionCode.None)
                {
                    // put the correct data into the response
                    bool putDataSuccess = true;

                    switch (requestAdu.FCInfo.FC)
                    {
                        case FunctionCode.FC01_ReadCoils: putDataSuccess = SetDiscretes(true, coilArray, 0, responseAdu.NumItemsInResponse); break;
                        case FunctionCode.FC02_ReadDiscretes: putDataSuccess = SetDiscretes(true, discreteArray, 0, responseAdu.NumItemsInResponse); break;
                        case FunctionCode.FC03_ReadHoldingRegisters: putDataSuccess = SetRegisters(true, holdingRegisterArray, 0, responseAdu.NumItemsInResponse); break;
                        case FunctionCode.FC04_ReadInputRegisters: putDataSuccess = SetRegisters(true, inputRegisterArray, 0, responseAdu.NumItemsInResponse); break;
                        case FunctionCode.FC17_ReadWriteMultipleRegisters: putDataSuccess = SetRegisters(true, inputRegisterArray, 0, responseAdu.NumItemsInResponse); break;
                        default: break;
                    }

                    if (!putDataSuccess)
                        exceptionCode = ExceptionCode.IllegalDataValue;
                }

                if (exceptionCode == ExceptionCode.None)
                {
                    responseAdu.InitializeResponsePDUForSend();
                    responseAdu.PrepareToSendResponse(requestAdu);

                    return true;
                }
            }
            catch (System.Exception ex)
            {
                Issue.Emitter.Emit("Modbus Servier '{0}' threw unexpected exception: fc:{1} ex:{2}", fcServer.Name, requestAdu.FCInfo.FC, ex);
                exceptionCode = ExceptionCode.SlaveDeviceFailure;
            }

            if (exceptionCode != ExceptionCode.IgnoreRequest)
            {
                // build an excpetion response packet
                responseAdu.ExceptionCodeToSend = exceptionCode;

                responseAdu.InitializeResponsePDUForSend();
                responseAdu.PrepareToSendResponse(requestAdu);

                return true;
            }
            else
            {
                // make this packet invalid so that it cannot be sent
                responseAdu.PktBuf.Invalidate();
                return false;
            }
        }
예제 #3
0
        /// <summary>
        /// Services the previously decoded request ADU packet by invoking the correspondingly selected method in the given IModbusFCServer instance and using
        /// the response and data that it provides to generate the response packet (if any) that can be sent back to the client.
        /// Returns true if a response packet is available to send or false if this request produced no response packet.
        /// </summary>
        /// <returns>true if a response packet is available to send or false if this request produced no response packet.</returns>
        public bool ServiceDecodedRequest(IModbusFCServer fcServer)
        {
            fcServer.Service();

            // update the responseAdu as an appropriate response to the requestAdu
            responseAdu.PktBuf.Clear();

            responseAdu.FCInfo              = requestAdu.FCInfo;
            responseAdu.ADUType             = requestAdu.ADUType;
            responseAdu.NumItemsInResponse  = requestAdu.NumReadItemsInRequest;
            responseAdu.ExceptionCodeToSend = ExceptionCode.None;

            if (RespondToAllTargets)
            {
                // respond as whatever target the request was aimed at
                if (ADUType == ADUType.RTU)
                {
                    responseAdu.RTUAddr = requestAdu.RTUAddr;
                }
                else
                {
                    responseAdu.UnitID = requestAdu.UnitID;
                }
            }
            else
            {
                if (ADUType == ADUType.RTU)
                {
                    if (requestAdu.RTUAddr != RTUAddr)
                    {
                        Debug.Emitter.Emit("Ignoring miss-addressed request {0} {1} RTUAddr:{2}", requestAdu.ADUType, requestAdu.FCInfo.FC, requestAdu.RTUAddr);
                        return(false);   // the request is not for us
                    }
                    responseAdu.RTUAddr = RTUAddr;
                }
                else
                {
                    if (requestAdu.UnitID != MBAPUnitID)
                    {
                        Debug.Emitter.Emit("Ignoring miss-addressed request {0} {1} UnitID:{2}", requestAdu.ADUType, requestAdu.FCInfo.FC, requestAdu.UnitID);
                        return(false);   // the request is not for us
                    }
                    responseAdu.UnitID = MBAPUnitID;
                }
            }

            responseAdu.InitializeResponsePDU();       // sets up internal pointer to count/length values for later use.

            ExceptionCode exceptionCode = ExceptionCode.None;

            try
            {
                // extract the relevant data from the requestADU
                if (exceptionCode == ExceptionCode.None)
                {
                    // get the correct data from the request
                    bool getDataSuccess = true;

                    switch (requestAdu.FCInfo.FC)
                    {
                    case FunctionCode.FC0f_WriteMultipleCoils: getDataSuccess = GetDiscretes(false, coilArray, 0, requestAdu.NumWriteItemsInRequest); break;

                    case FunctionCode.FC10_WriteMutlipleHoldingRegisters: getDataSuccess = GetRegisters(false, holdingRegisterArray, 0, requestAdu.NumWriteItemsInRequest); break;

                    case FunctionCode.FC17_ReadWriteMultipleRegisters: getDataSuccess = GetRegisters(false, holdingRegisterArray, 0, requestAdu.NumWriteItemsInRequest); break;

                    default: break;
                    }

                    if (!getDataSuccess)
                    {
                        exceptionCode = ExceptionCode.IllegalDataValue;
                    }
                }

                // ask the fcServer to perform the requested action
                if (exceptionCode == ExceptionCode.None)
                {
                    switch (requestAdu.FCInfo.FC)
                    {
                    case FunctionCode.FC00_None: exceptionCode = ExceptionCode.IllegalFunction; break;

                    case FunctionCode.FC01_ReadCoils: exceptionCode = fcServer.FC01_ReadCoils(requestAdu.FirstReadItemAddrInRequest, requestAdu.NumReadItemsInRequest, coilArray); break;

                    case FunctionCode.FC02_ReadDiscretes: exceptionCode = fcServer.FC02_ReadDiscretes(requestAdu.FirstReadItemAddrInRequest, requestAdu.NumReadItemsInRequest, discreteArray); break;

                    case FunctionCode.FC03_ReadHoldingRegisters: exceptionCode = fcServer.FC03_ReadHoldingRegisters(requestAdu.FirstReadItemAddrInRequest, requestAdu.NumReadItemsInRequest, holdingRegisterArray); break;

                    case FunctionCode.FC04_ReadInputRegisters: exceptionCode = fcServer.FC04_ReadInputRegisters(requestAdu.FirstReadItemAddrInRequest, requestAdu.NumReadItemsInRequest, inputRegisterArray); break;

                    case FunctionCode.FC05_WriteSingleCoil: exceptionCode = fcServer.FC05_WriteSingleCoil(requestAdu.FirstWriteItemAddrInRequest, (HeaderWord2 != 0)); break;

                    case FunctionCode.FC06_WriteSingleHoldingRegister: exceptionCode = fcServer.FC06_WriteSingleHoldingRegister(requestAdu.FirstWriteItemAddrInRequest, unchecked ((Int16)HeaderWord2)); break;

                    case FunctionCode.FC08_Diagnostics: exceptionCode = ExceptionCode.IllegalFunction; break;

                    case FunctionCode.FC0f_WriteMultipleCoils: exceptionCode = fcServer.FC0f_WriteCoils(requestAdu.FirstWriteItemAddrInRequest, requestAdu.NumWriteItemsInRequest, coilArray); break;

                    case FunctionCode.FC10_WriteMutlipleHoldingRegisters: exceptionCode = fcServer.FC10_WriteMutlipleHoldingRegisters(requestAdu.FirstWriteItemAddrInRequest, requestAdu.NumWriteItemsInRequest, holdingRegisterArray); break;

                    case FunctionCode.FC16_MaskWriteRegister: exceptionCode = fcServer.FC16_MaskWriteRegister(requestAdu.FirstWriteItemAddrInRequest, unchecked ((Int16)HeaderWord2), unchecked ((Int16)HeaderWord3)); break;

                    case FunctionCode.FC17_ReadWriteMultipleRegisters: exceptionCode = fcServer.FC17_ReadWriteMultipleRegisters(requestAdu.FirstReadItemAddrInRequest, requestAdu.NumReadItemsInRequest, inputRegisterArray, requestAdu.FirstWriteItemAddrInRequest, requestAdu.NumWriteItemsInRequest, holdingRegisterArray); break;

                    case FunctionCode.FC2b_EncapsulatedInterfaceTransport: exceptionCode = ExceptionCode.IllegalFunction; break;

                    default: exceptionCode = ExceptionCode.IllegalFunction; break;
                    }
                }

                // if the fcServer operation succeeded then build a normal response packet
                if (exceptionCode == ExceptionCode.None)
                {
                    // put the correct data into the response
                    bool putDataSuccess = true;

                    switch (requestAdu.FCInfo.FC)
                    {
                    case FunctionCode.FC01_ReadCoils: putDataSuccess = SetDiscretes(true, coilArray, 0, responseAdu.NumItemsInResponse); break;

                    case FunctionCode.FC02_ReadDiscretes: putDataSuccess = SetDiscretes(true, discreteArray, 0, responseAdu.NumItemsInResponse); break;

                    case FunctionCode.FC03_ReadHoldingRegisters: putDataSuccess = SetRegisters(true, holdingRegisterArray, 0, responseAdu.NumItemsInResponse); break;

                    case FunctionCode.FC04_ReadInputRegisters: putDataSuccess = SetRegisters(true, inputRegisterArray, 0, responseAdu.NumItemsInResponse); break;

                    case FunctionCode.FC17_ReadWriteMultipleRegisters: putDataSuccess = SetRegisters(true, inputRegisterArray, 0, responseAdu.NumItemsInResponse); break;

                    default: break;
                    }

                    if (!putDataSuccess)
                    {
                        exceptionCode = ExceptionCode.IllegalDataValue;
                    }
                }

                if (exceptionCode == ExceptionCode.None)
                {
                    responseAdu.InitializeResponsePDUForSend();
                    responseAdu.PrepareToSendResponse(requestAdu);

                    return(true);
                }
            }
            catch (System.Exception ex)
            {
                Issue.Emitter.Emit("Modbus Server '{0}' threw unexpected exception: fc:{1} {2}", fcServer.Name, requestAdu.FCInfo.FC, ex.ToString(ExceptionFormat.TypeAndMessage));
                Debug.Emitter.Emit(ex.ToString(ExceptionFormat.Full));
                exceptionCode = ExceptionCode.SlaveDeviceFailure;
            }

            if (exceptionCode != ExceptionCode.IgnoreRequest)
            {
                // build an exception response packet
                responseAdu.ExceptionCodeToSend = exceptionCode;

                responseAdu.InitializeResponsePDUForSend();
                responseAdu.PrepareToSendResponse(requestAdu);

                return(true);
            }
            else
            {
                // make this packet invalid so that it cannot be sent
                responseAdu.PktBuf.Invalidate();
                return(false);
            }
        }
예제 #4
0
        /// <summary>Contructor</summary>
        public ModbusServerFunctionPortAdapter(string partID, SerialIO.PortConfig portConfig, IModbusFCServer fcServer, ADUType aduType, byte unitID, bool responseToAllUnits)
            : base(partID, TimeSpan.FromSeconds(0.2))
        {
            this.fcServer = fcServer;

            Timeout = portConfig.ReadTimeout;
            portConfig.ReadTimeout = TimeSpan.FromSeconds(Math.Min(0.1, Timeout.TotalSeconds));

            port = SerialIO.Factory.CreatePort(portConfig);
            portBaseStateObserver = new SequencedRefObjectSourceObserver<IBaseState, Int32>(port.BaseStateNotifier);

            IPortBehavior portBehavior = port.PortBehavior;

            IDictionary<string, Logging.IMesgEmitter> emitters = new Dictionary<string,Logging.IMesgEmitter>() { { "Issue", Log.Error }, {"Debug", Log.Debug}, {"Trace", Log.Trace} };

            serverFunctionContainer = new ServerFunctionContainer() { ADUType = aduType, Emitters = emitters, UnitID = unitID, RTUAddr = unitID, MBAPUnitID = unitID, RespondToAllTargets = responseToAllUnits };

            FlushPeriod = (portBehavior.IsDatagramPort ? TimeSpan.FromSeconds(0.0) : TimeSpan.FromSeconds(0.1));

            portReadAction = port.CreateReadAction(portReadActionParam = new ReadActionParam() { WaitForAllBytes = false });
            portWriteAction = port.CreateWriteAction(portWriteActionParam = new WriteActionParam());
            portFlushAction = port.CreateFlushAction(FlushPeriod);

            portReadAction.NotifyOnComplete.AddItem(threadWakeupNotifier);
            portWriteAction.NotifyOnComplete.AddItem(threadWakeupNotifier);
            portFlushAction.NotifyOnComplete.AddItem(threadWakeupNotifier);

            port.BaseStateNotifier.NotificationList.AddItem(threadWakeupNotifier);

            AddExplicitDisposeAction(() => Fcns.DisposeOfObject(ref port));
        }