/// <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)); }
/// <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; } }
/// <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); } }
/// <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)); }