示例工程版本提升至net462,项目添加了部分空引用检测逻辑。累了,消不完的空引用警告(T.T)

This commit is contained in:
fengjiayi
2024-09-30 22:20:02 +08:00
parent 8ecbdfa7a6
commit e4aa3b6185
45 changed files with 562 additions and 581 deletions

View File

@@ -0,0 +1,18 @@
using Net462DllTest.LogicControl;
using Serein.Library.Attributes;
using Serein.Library.NodeFlow.Tool;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Net462DllTest.Device
{
[AutoRegister]
public class PrakingDevice : ChannelFlowTrigger<ParkingCommand>
{
}
}

View File

@@ -0,0 +1,293 @@
using IoTClient;
using IoTClient.Clients.PLC;
using IoTClient.Enums;
using Net462DllTest.Enums;
using Net462DllTest.Signal;
using Serein.Library.Attributes;
using Serein.Library.NodeFlow.Tool;
using System;
namespace Net462DllTest.Device
{
/// <summary>
/// 官方文档如果没有主动Open则会每次读写操作的时候自动打开自动和关闭连接这样会使读写效率大大减低。所以建议手动Open和Close。
/// </summary>
[AutoRegister]
public class SiemensPlcDevice : ChannelFlowTrigger<CommandSignal>
{
public SiemensClient Client { get; set; }
public IoTClient.Common.Enums.SiemensVersion Version { get; set; }
public string IP { get; set; }
public int Port { get; set; }
public PlcState State { get; set; } = PlcState.PowerOff;
public void Init(IoTClient.Common.Enums.SiemensVersion version,string ip, int port)
{
Client = new SiemensClient(version, ip, port);
Version = version;
IP = ip;
Port = port;
}
public void ResetDevice()
{
Client?.Close();
Client = null;
}
public void Write(PlcVarInfo plcValue, object value)
{
try
{
Client.WriteToPlcValue(plcValue, value);
}
catch (Exception ex)
{
Console.WriteLine($"写入出错:{this}{plcValue}。{ex.Message}");
throw;
}
}
public object Read(PlcVarInfo plcValue)
{
try
{
return Client.ReadToPlcValue(plcValue);
}
catch (Exception ex)
{
Console.WriteLine($"读取出错:{this}{plcValue}。{ex.Message}");
throw;
}
}
public override string ToString()
{
return $"西门子Plc[{this.Version}-{this.IP}:{this.Port}]";
}
}
/// <summary>
/// PLC方法
/// </summary>
public static class PlcExtension
{
public static DataTypeEnum ToDataTypeEnum(this PlcVarInfo varInfo)
{
Type dataType = varInfo.DataType;
DataTypeEnum plcDataType;
switch (dataType)
{
case Type _ when dataType == typeof(string):
plcDataType = DataTypeEnum.String;
break;
case Type _ when dataType == typeof(char):
plcDataType = DataTypeEnum.String;
break;
case Type _ when dataType == typeof(bool):
plcDataType = DataTypeEnum.Bool;
break;
case Type _ when dataType == typeof(float):
plcDataType = DataTypeEnum.Float;
break;
case Type _ when dataType == typeof(double):
plcDataType = DataTypeEnum.Double;
break;
case Type _ when dataType == typeof(byte):
plcDataType = DataTypeEnum.Byte;
break;
case Type _ when dataType == typeof(short):
plcDataType = DataTypeEnum.Int16;
break;
case Type _ when dataType == typeof(ushort):
plcDataType = DataTypeEnum.UInt16;
break;
case Type _ when dataType == typeof(int):
plcDataType = DataTypeEnum.Int32;
break;
case Type _ when dataType == typeof(uint):
plcDataType = DataTypeEnum.UInt32;
break;
case Type _ when dataType == typeof(long):
plcDataType = DataTypeEnum.Int64;
break;
case Type _ when dataType == typeof(ulong):
plcDataType = DataTypeEnum.UInt64;
break;
default:
plcDataType = DataTypeEnum.None;
break;
}
return plcDataType;
}
/// <summary>
/// 读取设备的值
/// </summary>
/// <param name="client"></param>
/// <param name="varInfo"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static object ReadToPlcValue(this SiemensClient client, PlcVarInfo varInfo)
{
Type dataType = varInfo.DataType;
object resultvalue;
if (dataType == typeof(string))
{
var result = client.ReadString(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(char))
{
var result = client.ReadString(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(bool))
{
var result = client.ReadBoolean(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(float))
{
var result = client.ReadFloat(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(double))
{
var result = client.ReadDouble(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(byte))
{
var result = client.ReadByte(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(short))
{
var result = client.ReadInt16(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(ushort))
{
var result = client.ReadUInt16(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(int))
{
var result = client.ReadInt32(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(uint))
{
var result = client.ReadUInt32(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(long))
{
var result = client.ReadInt64(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(ulong))
{
var result = client.ReadUInt64(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else
{
resultvalue = default;
}
return resultvalue;
}
public static void WriteToPlcValue(this SiemensClient client, PlcVarInfo varInfo, object value)
{
if (client == null) throw new ArgumentNullException("client");
Type dataType = varInfo.DataType;
Result result = null;
if (dataType == typeof(string))
{
result = client.Write(varInfo.VarAddress, value.ToString());
}
else if (dataType == typeof(char))
{
result = client.Write(varInfo.VarAddress, value.ToString());
}
else if (dataType == typeof(bool))
{
var @bool = bool.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @bool);
}
else if (dataType == typeof(float))
{
var @float = float.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @float);
}
else if (dataType == typeof(double))
{
var @double = double.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @double);
}
else if (dataType == typeof(byte))
{
var @byte = byte.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @byte);
}
else if (dataType == typeof(short))
{
var @short = short.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @short);
}
else if (dataType == typeof(ushort))
{
var @ushort = ushort.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @ushort);
}
else if (dataType == typeof(int))
{
var @int = int.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @int);
}
else if (dataType == typeof(uint))
{
var @uint = uint.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @uint);
}
else if (dataType == typeof(long))
{
var @long = long.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @long);
}
else if (dataType == typeof(ulong))
{
var @ulong = ulong.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @ulong);
}
if (result is null)
{
throw new Exception($"未定义的数据类型");
}
if (!result.IsSucceed)
{
throw new Exception(result.Err);
}
}
}
}

View File

@@ -0,0 +1,19 @@
using Net462DllTest.View;
using Serein.Library.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Net462DllTest.Signal
{
public enum FromValue
{
None,
[BindValue(typeof(FromWorkBenchView))]
FromWorkBenchView,
[BindValue(typeof(TestFormView))]
TestFormView,
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Net462DllTest.Enums
{
public enum PlcState
{
/// <summary>
/// 关机
/// </summary>
PowerOff,
/// <summary>
/// 正在运行
/// </summary>
Runing,
/// <summary>
/// 发生异常
/// </summary>
Error,
/// <summary>
/// 维护中
/// </summary>
Maintenance,
}
}

View File

@@ -0,0 +1,129 @@
using Net462DllTest.Signal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Net462DllTest.Signal.PlcValueAttribute;
namespace Net462DllTest.Enums
{
/// <summary>
/// PLC变量
/// </summary>
public enum PlcVarEnum
{
None,
/// <summary>
/// 车位号
/// </summary>
[PlcValue(typeof(short), "V100", VarType.Writable)]
SpaceNum,
/// <summary>
/// 上位机指令
/// </summary>
[PlcValue(typeof(short), "V102", VarType.Writable)]
CmdForPLC,
/// <summary>
/// PLC当前存取车位号
/// </summary>
[PlcValue(typeof(short), "V110", VarType.ReadOnly)]
DoingSpaceNum,
/// <summary>
/// 下位机状态
/// </summary>
[PlcValue(typeof(short), "V112", VarType.ReadOnly)]
PLCState,
/// <summary>
/// 门1正常待机车位号存车完成地面车位0
/// </summary>
[PlcValue(typeof(short), "V114", VarType.ReadOnly)]
Door1CurSpaceNum,
/// <summary>
/// 门2正常待机车位号存车完成地面车位0
/// </summary>
[PlcValue(typeof(short), "V124", VarType.ReadOnly)]
Door2CurSpaceNum,
/// <summary>
/// 下位机运行模式
/// </summary>
[PlcValue(typeof(short), "V116", VarType.Writable)]
PLCRunMode,
/// <summary>
/// 执行的门号
/// </summary>
[PlcValue(typeof(short), "V104", VarType.Writable)]
DoorVar,
/// <summary>
/// 门1是否开到位
/// </summary>
[PlcValue(typeof(bool), "V207.0", VarType.ReadOnly)]
IsDoor1OpenDone,
/// <summary>
/// 门1是否关到位
/// </summary>
[PlcValue(typeof(bool), "V207.1", VarType.ReadOnly)]
IsDoor1ClosedDone,
/// <summary>
/// 门2是否开到位
/// </summary>
[PlcValue(typeof(bool), "V207.3", VarType.ReadOnly)]
IsDoor2OpenDone,
/// <summary>
/// 门2是否关到位
/// </summary>
[PlcValue(typeof(bool), "V207.4", VarType.ReadOnly)]
IsDoor2ClosedDone,
/// <summary>
/// 通道1是否有车
/// </summary>
[PlcValue(typeof(bool), "V284.7", VarType.ReadOnly)]
HasCarInTone1,
/// <summary>
/// 通道2是否有车
/// </summary>
[PlcValue(typeof(bool), "V286.7", VarType.ReadOnly)]
HasCarInTone2,
/// <summary>
/// 下位机异常代码
/// </summary>
[PlcValue(typeof(short), "V2", VarType.ReadOnly)]
ErrorCode,
/// <summary>
/// 2层以上的空板是否在待机
/// </summary>
[PlcValue(typeof(bool), "V200.7", VarType.ReadOnly)]
IsOver2FlowStanded,
/// <summary>
/// 1号门指示灯
/// </summary>
[PlcValue(typeof(bool), "Q17.0", VarType.ReadOnly)]
Gate1Light,
/// <summary>
/// 2号门指示灯
/// </summary>
[PlcValue(typeof(bool), "Q17.3", VarType.ReadOnly)]
Gate2Light,
}
}

View File

@@ -0,0 +1,86 @@
using Net462DllTest.Device;
using Net462DllTest.Signal;
using Net462DllTest.ViewModel;
using Serein.Library.Api;
using Serein.Library.Attributes;
using Serein.Library.Enums;
using Serein.Library.Ex;
using Serein.Library.Framework.NodeFlow;
using Serein.Library.NodeFlow.Tool;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Net462DllTest.LogicControl
{
public enum ParkingCommand
{
GetPparkingSpace,
}
[AutoRegister]
[DynamicFlow]
public class ParkingLogicControl
{
private readonly PrakingDevice PrakingDevice;
public ParkingLogicControl(PrakingDevice PrakingDevice)
{
this.PrakingDevice = PrakingDevice;
}
[NodeAction(NodeType.Flipflop, "等待车位调取命令",ReturnType=typeof(string))]
public async Task<IFlipflopContext> GetPparkingSpace(ParkingCommand parkingCommand = ParkingCommand.GetPparkingSpace)
{
try
{
TriggerData triggerData = await PrakingDevice.CreateChannelWithTimeoutAsync(parkingCommand, TimeSpan.FromMinutes(5), 0);
if (triggerData.Type == TriggerType.Overtime)
{
throw new FlipflopException("超时取消");
}
if(triggerData.Value is string spaceNum)
{
await Console.Out.WriteLineAsync("收到命令:调取车位,车位号"+ spaceNum);
return new FlipflopContext(FlipflopStateType.Succeed, spaceNum);
}
else
{
throw new FlipflopException("并非车位号");
}
}
catch (FlipflopException)
{
throw;
}
catch (Exception)
{
return new FlipflopContext(FlipflopStateType.Error);
}
}
[NodeAction(NodeType.Action, "手动触发模拟调取车位")]
public void Storage(string spaceNum = "101")
{
if (PrakingDevice.TriggerSignal(ParkingCommand.GetPparkingSpace, spaceNum))
{
Console.WriteLine("发送命令成功:调取车位" + spaceNum);
}
else
{
Console.WriteLine("发送命令失败:调取车位" + spaceNum);
}
}
}
}

View File

@@ -0,0 +1,205 @@
using IoTClient.Clients.PLC;
using IoTClient.Common.Enums;
using Net462DllTest.Device;
using Net462DllTest.Enums;
using Net462DllTest.Signal;
using Net462DllTest.Web;
using Serein.Library.Api;
using Serein.Library.Attributes;
using Serein.Library.Enums;
using Serein.Library.Ex;
using Serein.Library.Framework.NodeFlow;
using Serein.Library.NodeFlow.Tool;
using Serein.Library.Utils;
using Serein.Library.Web;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Threading.Tasks;
namespace Net462DllTest.LogicControl
{
[AutoRegister]
[DynamicFlow]
public class PlcLogicControl
{
private readonly SiemensPlcDevice MyPlc;
public PlcLogicControl(SiemensPlcDevice MyPlc)
{
this.MyPlc = MyPlc;
}
#region 退
[NodeAction(NodeType.Init)] // Init 初始化事件,流程启动时执行
public void Init(IDynamicContext context)
{
context.Env.IOC.Register<IRouter, Router>();
context.Env.IOC.Register<WebServer>();
}
[NodeAction(NodeType.Loading)] // Loading 初始化完成已注入依赖项,可以开始逻辑上的操作
public void Loading(IDynamicContext context)
{
// 注册控制器
context.Env.IOC.Run<IRouter, WebServer>((router, web) => {
try
{
router.RegisterController(typeof(CommandController));
web.Start("http://*:8089/"); // 开启 Web 服务
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
});
}
[NodeAction(NodeType.Exit)] // 流程结束时自动执行
public void Exit(IDynamicContext context)
{
context.Env.IOC.Run<WebServer>((web) =>
{
web?.Stop(); // 关闭 Web 服务
});
MyPlc.ResetDevice();
MyPlc.CancelAllTasks();
}
#endregion
#region
[NodeAction(NodeType.Flipflop, "等待信号触发", ReturnType = typeof(int))]
public async Task<IFlipflopContext> WaitTask(CommandSignal order = CommandSignal.Command_1)
{
try
{
TriggerData triggerData = await MyPlc.CreateChannelWithTimeoutAsync(order, TimeSpan.FromMinutes(5), 0);
if (triggerData.Type == TriggerType.Overtime)
{
throw new FlipflopException("超时取消");
}
//int.TryParse(triggerData.Value.ToString(),out int result);
return new FlipflopContext(FlipflopStateType.Succeed, triggerData.Value);
}
catch (FlipflopException)
{
throw;
}
catch (Exception)
{
return new FlipflopContext(FlipflopStateType.Error);
}
}
#endregion
#region
[NodeAction(NodeType.Action, "初始化")]
public SiemensPlcDevice PlcInit(SiemensVersion version = SiemensVersion.None,
string ip = "192.168.10.100",
int port = 102)
{
if (MyPlc.Client is null)
{
try
{
MyPlc.Init(version, ip, port);
Console.WriteLine($"西门子PLC初始化成功[{version},{ip}:{port}]");
}
catch (Exception ex)
{
Console.WriteLine($"西门子PLC[{version},{ip}:{port}]初始化异常:{ex.Message}");
}
}
else
{
Console.WriteLine( $"西门子PLC已经初始化[{version},{ip}:{port}]");
}
return MyPlc;
}
[NodeAction(NodeType.Action, "设置PLC状态")]
public SiemensPlcDevice SetState(PlcState state = PlcState.PowerOff)
{
if(MyPlc.Client != null)
{
var oldState = MyPlc.State;
MyPlc.State = state;
Console.WriteLine($"PLC状态从[{oldState}]转为[{state}]");
return MyPlc;
}
else
{
Console.WriteLine($"PLC尚未初始化");
return MyPlc;
}
}
[NodeAction(NodeType.Action, "PLC获取变量")]
public object ReadVar(PlcVarEnum plcVarEnum)
{
var varInfo = ToVarInfo(plcVarEnum);
var result = MyPlc.Read(varInfo);
Console.WriteLine($"获取变量成功:({varInfo})\t result = {result}");
return result;
}
[NodeAction(NodeType.Action, "PLC写入变量")]
public SiemensPlcDevice WriteVar2(object value, PlcVarEnum plcVarEnum)
{
var varInfo = ToVarInfo(plcVarEnum);
if (MyPlc.State == PlcState.Runing)
{
if (varInfo.IsProtected)
{
Console.WriteLine($"PLC变量{varInfo}当前禁止写入");
}
else
{
MyPlc.Write(varInfo, value);
Console.WriteLine($"PLC变量{varInfo}写入数据:{value}");
}
}
else
{
Console.WriteLine($"PLC处于非预期状态{MyPlc.State}");
}
return MyPlc;
}
/// <summary>
/// 缓存变量信息
/// </summary>
private readonly Dictionary<PlcVarEnum, PlcVarInfo> VarInfoDict = new Dictionary<PlcVarEnum, PlcVarInfo>();
private PlcVarInfo ToVarInfo(PlcVarEnum plcVarEnum)
{
if (VarInfoDict.ContainsKey(plcVarEnum))
{
return VarInfoDict[plcVarEnum];
}
if (plcVarEnum == PlcVarEnum.None)
{
throw new Exception("非预期枚举值");
}
var plcValue = EnumHelper.GetBoundValue<PlcVarEnum, PlcValueAttribute, PlcVarInfo>(plcVarEnum, attr => attr.PlcInfo)
?? throw new Exception($"获取变量异常:{plcVarEnum}没有标记PlcValueAttribute");
if (string.IsNullOrEmpty(plcValue.VarAddress))
{
throw new Exception($"获取变量异常:{plcVarEnum},变量地址为空");
}
VarInfoDict.Add(plcVarEnum, plcValue);
return plcValue;
}
#endregion
}
}

View File

@@ -0,0 +1,98 @@
using Net462DllTest.Device;
using Net462DllTest.Signal;
using Net462DllTest.ViewModel;
using Serein.Library.Api;
using Serein.Library.Attributes;
using Serein.Library.Enums;
using Serein.Library.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace Net462DllTest.LogicControl
{
/// <summary>
/// 视图管理
/// </summary>
[AutoRegister]
public class ViewManagement
{
private List<Form> forms = new List<Form>();
/// <summary>
/// 打开窗口
/// </summary>
/// <param name="form">要打开的窗口类型</param>
/// <param name="isTop">是否置顶</param>
public void OpenView(Form form, bool isTop)
{
form.TopMost = isTop;
form.Show();
forms.Add(form);
}
public void CloseView(Type formType)
{
var remoteForms = forms.Where(f => f.GetType() == formType).ToArray();
foreach (Form f in remoteForms)
{
f.Close();
f.Dispose();
this.forms.Remove(f);
}
}
}
[DynamicFlow]
public class ViewLogicControl
{
private readonly ViewManagement ViewManagement;
public ViewLogicControl(ViewManagement ViewManagement)
{
this.ViewManagement = ViewManagement;
}
[NodeAction(NodeType.Init)]
public void Init(IDynamicContext context)
{
context.Env.IOC.Register<ViewManagement>();
context.Env.IOC.Register<FromWorkBenchViewModel>();
}
[NodeAction(NodeType.Action, "打开窗体(指定枚举值)")]
public void OpenForm(IDynamicContext context, FromValue fromId = FromValue.None, bool isTop = true)
{
var fromType = EnumHelper.GetBoundValue<FromValue, Type>(fromId, attr => attr.Value);
if (fromType is null) return;
if (context.Env.IOC.Instantiate(fromType) is Form form)
{
ViewManagement.OpenView(form, isTop);
}
}
[NodeAction(NodeType.Action, "打开窗体(使用转换器)")]
public void OpenForm2([EnumTypeConvertor(typeof(FromValue))] Form form, bool isTop = true)
{
ViewManagement.OpenView(form, isTop);
}
[NodeAction(NodeType.Action, "关闭窗体")]
public void CloseForm(IDynamicContext context, FromValue fromId = FromValue.None)
{
var fromType = EnumHelper.GetBoundValue<FromValue, Type>(fromId, attr => attr.Value);
if (fromType is null) return;
ViewManagement.CloseView(fromType);
}
}
}

View File

@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E40EE629-1A38-4011-88E3-9AD036869987}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>Net462DllTest</RootNamespace>
<AssemblyName>Net462DllTest</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="IoTClient, Version=1.0.40.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\IoTClient.1.0.40\lib\netstandard2.0\IoTClient.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Ports, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Ports.4.6.0\lib\net461\System.IO.Ports.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Device\SiemensPlcDevice.cs" />
<Compile Include="Device\PrakingDevice.cs" />
<Compile Include="Enums\PlcState.cs" />
<Compile Include="Enums\PlcVarEnum.cs" />
<Compile Include="LogicControl\PlcLogicControl.cs" />
<Compile Include="LogicControl\ParkingLogicControl.cs" />
<Compile Include="LogicControl\ViewLogicControl.cs" />
<Compile Include="Enums\FromValue.cs" />
<Compile Include="Signal\CommandSignal.cs" />
<Compile Include="Signal\PLCVarSignal.cs" />
<Compile Include="Utils\ToValue.cs" />
<Compile Include="ViewModel\FromWorkBenchViewModel.cs" />
<Compile Include="View\FromWorkBenchView.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="View\FromWorkBenchView.Designer.cs">
<DependentUpon>FromWorkBenchView.cs</DependentUpon>
</Compile>
<Compile Include="View\TestFormView.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="View\TestFormView.Designer.cs">
<DependentUpon>TestFormView.cs</DependentUpon>
</Compile>
<Compile Include="Web\CommandController_1.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\DynamicControl\SereinFlow\Library.Framework\Serein.Library.Framework.csproj">
<Project>{73B272E8-222D-4D08-A030-F1E1DB70B9D1}</Project>
<Name>Serein.Library.Framework</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\DynamicControl\SereinFlow\Library\Serein.Library.csproj">
<Project>{9FCE93C2-2278-46F3-96AB-CDAAFF27A55F}</Project>
<Name>Serein.Library</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="View\FromWorkBenchView.resx">
<DependentUpon>FromWorkBenchView.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="View\TestFormView.resx">
<DependentUpon>TestFormView.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -0,0 +1,15 @@
namespace Net462DllTest.Signal
{
public enum CommandSignal
{
Command_1,
Command_2,
Command_3,
Command_4,
Command_5,
Command_6,
Command_7,
Command_8,
Command_9,
}
}

View File

@@ -0,0 +1,64 @@
using Serein.Library.Attributes;
using System;
using static Net462DllTest.Signal.PlcValueAttribute;
namespace Net462DllTest.Signal
{
[AttributeUsage(AttributeTargets.Field)]
public class PlcValueAttribute : Attribute
{
/// <summary>
/// 变量类型
/// </summary>
public enum VarType
{
/// <summary>
/// 只读取的值
/// </summary>
ReadOnly,
/// <summary>
/// 可写入的值
/// </summary>
Writable,
}
/// <summary>
/// 变量属性
/// </summary>
public PlcVarInfo PlcInfo { get; }
public PlcValueAttribute(Type type,
string @var,
VarType varType
)
{
PlcInfo = new PlcVarInfo(type, var, varType);
}
}
public class PlcVarInfo
{
public PlcVarInfo(Type type,
string @var,
VarType varType
)
{
DataType = type;
VarAddress = @var;
Type = varType;
}
public bool IsProtected { get; }
public Type DataType { get; }
public string VarAddress { get; }
public VarType Type { get; }
public override string ToString()
{
return $"数据类型:{DataType} 地址:{VarAddress}";
}
}
}

View File

@@ -0,0 +1,231 @@
using IoTClient;
using IoTClient.Clients.PLC;
using IoTClient.Enums;
using Net462DllTest.Signal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Net462DllTest.Utils
{
internal static class MyPlcExtension
{
public static DataTypeEnum ToDataTypeEnum(this PlcVarInfo varInfo)
{
Type dataType = varInfo.DataType;
DataTypeEnum plcDataType;
switch (dataType)
{
case Type _ when dataType == typeof(string):
plcDataType = DataTypeEnum.String;
break;
case Type _ when dataType == typeof(char):
plcDataType = DataTypeEnum.String;
break;
case Type _ when dataType == typeof(bool):
plcDataType = DataTypeEnum.Bool;
break;
case Type _ when dataType == typeof(float):
plcDataType = DataTypeEnum.Float;
break;
case Type _ when dataType == typeof(double):
plcDataType = DataTypeEnum.Double;
break;
case Type _ when dataType == typeof(byte):
plcDataType = DataTypeEnum.Byte;
break;
case Type _ when dataType == typeof(short):
plcDataType = DataTypeEnum.Int16;
break;
case Type _ when dataType == typeof(ushort):
plcDataType = DataTypeEnum.UInt16;
break;
case Type _ when dataType == typeof(int):
plcDataType = DataTypeEnum.Int32;
break;
case Type _ when dataType == typeof(uint):
plcDataType = DataTypeEnum.UInt32;
break;
case Type _ when dataType == typeof(long):
plcDataType = DataTypeEnum.Int64;
break;
case Type _ when dataType == typeof(ulong):
plcDataType = DataTypeEnum.UInt64;
break;
default:
plcDataType = DataTypeEnum.None;
break;
}
return plcDataType;
}
/// <summary>
/// 读取设备的值
/// </summary>
/// <param name="client"></param>
/// <param name="varInfo"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static object ReadToPlcValue(this SiemensClient client,PlcVarInfo varInfo)
{
Type dataType = varInfo.DataType;
object resultvalue;
if (dataType == typeof(string))
{
var result = client.ReadString(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(char))
{
var result = client.ReadString(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(bool))
{
var result = client.ReadBoolean(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(float))
{
var result = client.ReadFloat(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(double))
{
var result = client.ReadDouble(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(byte))
{
var result = client.ReadByte(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(short))
{
var result = client.ReadInt16(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(ushort))
{
var result = client.ReadUInt16(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(int))
{
var result = client.ReadInt32(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(uint))
{
var result = client.ReadUInt32(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(long))
{
var result = client.ReadInt64(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else if (dataType == typeof(ulong))
{
var result = client.ReadUInt64(varInfo.VarAddress);
if (!result.IsSucceed) throw new Exception(result.Err);
resultvalue = result.Value;
}
else
{
resultvalue = default;
}
return resultvalue;
}
public static void WriteToPlcValue(this SiemensClient client, PlcVarInfo varInfo ,object value)
{
if(client == null) throw new ArgumentNullException("client");
Type dataType = varInfo.DataType;
Result result = null;
if (dataType == typeof(string))
{
result = client.Write(varInfo.VarAddress, value.ToString());
}
else if (dataType == typeof(char))
{
result = client.Write(varInfo.VarAddress, value.ToString());
}
else if (dataType == typeof(bool))
{
var @bool = bool.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @bool);
}
else if (dataType == typeof(float))
{
var @float = float.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @float);
}
else if (dataType == typeof(double))
{
var @double = double.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @double);
}
else if (dataType == typeof(byte))
{
var @byte = byte.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @byte);
}
else if (dataType == typeof(short))
{
var @short = short.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @short);
}
else if (dataType == typeof(ushort))
{
var @ushort = ushort.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @ushort);
}
else if (dataType == typeof(int))
{
var @int = int.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @int);
}
else if (dataType == typeof(uint))
{
var @uint = uint.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @uint);
}
else if (dataType == typeof(long))
{
var @long = long.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @long);
}
else if (dataType == typeof(ulong))
{
var @ulong = ulong.Parse(value.ToString());
result = client.Write(varInfo.VarAddress, @ulong);
}
if (result is null)
{
throw new Exception($"未定义的数据类型");
}
if(!result.IsSucceed)
{
throw new Exception(result.Err);
}
}
}
}

View File

@@ -0,0 +1,108 @@
namespace Net462DllTest
{
partial class FromWorkBenchView
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.textBoxPlcInfo = new System.Windows.Forms.TextBox();
this.button2 = new System.Windows.Forms.Button();
this.listBox1 = new System.Windows.Forms.ListBox();
this.textBoxSpaceNum = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(220, 56);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(65, 23);
this.button1.TabIndex = 0;
this.button1.Text = "查看状态";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// textBoxPlcInfo
//
this.textBoxPlcInfo.Location = new System.Drawing.Point(35, 24);
this.textBoxPlcInfo.Name = "textBoxPlcInfo";
this.textBoxPlcInfo.ReadOnly = true;
this.textBoxPlcInfo.Size = new System.Drawing.Size(250, 21);
this.textBoxPlcInfo.TabIndex = 1;
//
// button2
//
this.button2.Location = new System.Drawing.Point(205, 181);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(80, 23);
this.button2.TabIndex = 2;
this.button2.Text = "触发";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// listBox1
//
this.listBox1.FormattingEnabled = true;
this.listBox1.ItemHeight = 12;
this.listBox1.Location = new System.Drawing.Point(35, 85);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(250, 88);
this.listBox1.TabIndex = 6;
//
// textBoxSpaceNum
//
this.textBoxSpaceNum.Location = new System.Drawing.Point(35, 183);
this.textBoxSpaceNum.Name = "textBoxSpaceNum";
this.textBoxSpaceNum.Size = new System.Drawing.Size(106, 21);
this.textBoxSpaceNum.TabIndex = 7;
this.textBoxSpaceNum.Text = "104";
//
// FromWorkBenchView
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(341, 251);
this.Controls.Add(this.textBoxSpaceNum);
this.Controls.Add(this.listBox1);
this.Controls.Add(this.button2);
this.Controls.Add(this.textBoxPlcInfo);
this.Controls.Add(this.button1);
this.Name = "FromWorkBenchView";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox textBoxPlcInfo;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.ListBox listBox1;
private System.Windows.Forms.TextBox textBoxSpaceNum;
}
}

View File

@@ -0,0 +1,62 @@
using Net462DllTest.Device;
using Net462DllTest.Signal;
using Net462DllTest.ViewModel;
using Serein.Library.Api;
using Serein.Library.Attributes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Net462DllTest
{
public partial class FromWorkBenchView : Form
{
private FromWorkBenchViewModel ViewModel;
public FromWorkBenchView(IFlowEnvironment env)
{
ViewModel = env.IOC.Instantiate<FromWorkBenchViewModel>(); // 创建对象并注入依赖项
InitializeComponent();
Init();
}
public void Init()
{
listBox1.Items.Clear();
var enumValues = Enum.GetValues(typeof(CommandSignal)).Cast<CommandSignal>();
foreach (var value in enumValues)
{
listBox1.Items.Add(value.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
textBoxPlcInfo.Text = ViewModel.GetDeviceInfo();
}
private void button2_Click(object sender, EventArgs e)
{
if(listBox1.SelectedItem is null)
{
return;
}
string type = listBox1.SelectedItem.ToString();
if (!string.IsNullOrEmpty(type) && Enum.TryParse(type, out CommandSignal signal) && Enum.IsDefined(typeof(CommandSignal), signal))
{
Console.WriteLine($"Trigger : {type}");
ViewModel.Trigger(signal,textBoxSpaceNum.Text);
}
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,62 @@
using System;
namespace Net462DllTest.View
{
partial class TestFormView
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(167, 58);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "测试";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// TestFormView
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(254, 118);
this.Controls.Add(this.button1);
this.Name = "TestFormView";
this.Text = "TeseForm";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button button1;
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Windows.Forms;
namespace Net462DllTest.View
{
public partial class TestFormView : Form
{
public TestFormView()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,37 @@
using Net462DllTest.Device;
using Net462DllTest.Signal;
using Serein.Library.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Net462DllTest.ViewModel
{
public class FromWorkBenchViewModel
{
public FromWorkBenchViewModel(SiemensPlcDevice Device)
{
this.Device = Device;
}
private SiemensPlcDevice Device;
public string Name { get; set; }
public string GetDeviceInfo()
{
return Device?.ToString();
}
public void Trigger(CommandSignal signal,string spcaeNumber)
{
_ = Task.Run(() =>
{
Device.TriggerSignal(signal, spcaeNumber);
});
}
}
}

View File

@@ -0,0 +1,47 @@
using Net461DllTest.Device;
using Net461DllTest.Signal;
using Serein.Library.Attributes;
using Serein.Library.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Net461DllTest.Web
{
[AutoHosting]
public class CommandController : ControllerBase
{
private SiemensPlcDevice PlcDevice;
public CommandController(SiemensPlcDevice PlcDevice)
{
this.PlcDevice = PlcDevice;
}
/*
* 类型 POST
* url : http://127.0.0.1:8089/command/trigger?command=
* body [JSON]
*
* {
* "value":0,
* }
*
*/
[WebApi(API.POST)]
public dynamic Trigger([Url] string command, int value)
{
if (Enum.TryParse(command, out CommandSignal signal) && Enum.IsDefined(typeof(CommandSignal), signal))
{
Console.WriteLine($"外部触发 {signal} 信号,信号内容 {value} ");
PlcDevice.TriggerSignal(signal, value);// 通过 Web Api 模拟外部输入信号
return new { state = "succeed" };
}
return new { state = "fail" };
}
}
}

View File

@@ -0,0 +1,42 @@
using Net462DllTest.Device;
using Net462DllTest.Signal;
using Serein.Library.Attributes;
using Serein.Library.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Net462DllTest.Web
{
[AutoHosting]
public class CommandController : ControllerBase
{
[AutoInjection]
public SiemensPlcDevice PlcDevice { get; set; }
/*
* 类型 POST
* url : http://127.0.0.1:8089/command/trigger?command=
* body [JSON]
*
* {
* "value":0,
* }
*
*/
[WebApi(API.POST)]
public dynamic Trigger([Url] string command, int value)
{
if (Enum.TryParse(command, out CommandSignal signal) && Enum.IsDefined(typeof(CommandSignal), signal))
{
Console.WriteLine($"外部触发 {signal} 信号,信号内容 {value} ");
PlcDevice.TriggerSignal(signal, value);// 通过 Web Api 模拟外部输入信号
return new { state = "succeed" };
}
return new { state = "fail" };
}
}
}

11
Net462DllTest/app.config Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.IO.Ports" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/></startup></configuration>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="IoTClient" version="1.0.40" targetFramework="net461" />
<package id="System.IO.Ports" version="4.6.0" targetFramework="net461" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net461" />
</packages>