diff --git a/LolaiService/.config/dotnet-tools.json b/LolaiService/.config/dotnet-tools.json new file mode 100644 index 0000000..b0e38ab --- /dev/null +++ b/LolaiService/.config/dotnet-tools.json @@ -0,0 +1,5 @@ +{ + "version": 1, + "isRoot": true, + "tools": {} +} \ No newline at end of file diff --git a/LolaiService/Controllers/TunnelApiController.cs b/LolaiService/Controllers/TunnelApiController.cs new file mode 100644 index 0000000..b453861 --- /dev/null +++ b/LolaiService/Controllers/TunnelApiController.cs @@ -0,0 +1,71 @@ +using LolaiService.Devices.Tunnel; +using LolaiService.Global; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace LolaiService.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class TunnelApiController : ControllerBase + { + /// + /// 隧道机关门 + /// + /// + [HttpPost("TunnelClose")] + public string TunnelCloseApi() + { + string result = GlobalDeviceInfo.CloseDoorTunnel(); + if (result.Equals("已关门")) + { + return "关门成功"; + } + else + { + return "关门失败"; + } + } + + + /// + /// 隧道机开门 + /// + /// + [HttpPost("TunnelOpen")] + public string TunnelOpenDoorApi() + { + string result = GlobalDeviceInfo.OpenDoorTunnel(); + if (result.Equals("已开门")) + { + return "开门成功"; + } + else + { + return "开门失败"; + } + } + + + [HttpGet("today")] + public IActionResult GetTodayWeather() + { + var data = new { Temp = 22, Condition = "Sunny" }; + return Ok(data); + } + + // GET api/weather/week + [HttpGet("week")] + public IActionResult GetWeekForecast() + { + var data = new[] + { + new { Day = "Mon", Temp = 21, Condition = "Cloudy" }, + new { Day = "Tue", Temp = 23, Condition = "Sunny" }, + new { Day = "Wed", Temp = 19, Condition = "Rain" }, + }; + return Ok(data); + } + + } +} diff --git a/LolaiService/Devices/Tunnel/IRfidTunnel.cs b/LolaiService/Devices/Tunnel/IRfidTunnel.cs new file mode 100644 index 0000000..452ab37 --- /dev/null +++ b/LolaiService/Devices/Tunnel/IRfidTunnel.cs @@ -0,0 +1,63 @@ +using Rovinj.Device; +using Rovinj.Reader.Silion; +using Rovinj.Tunnel; + +namespace LolaiService.Devices.Tunnel +{ + /// + /// 隧道机接口 + /// + public interface IRfidTunnel + { + /// + /// 连接通道机 + /// + bool ConnectTunnel(SilionReaderConfig readerConfig, ConnectionConfig plcConnectionConfig, TunnelConfig tunnelConfig); + + /// + /// 关闭通道机 + /// + /// + void CloseTunnel(); + + /// + /// 标签报告事件 + /// + /// + /// + void Tunnel_TagsReported(ITunnel tunnel, TunnelTagsReportedEventArgs e); + /// + /// 通道机读写器状态变化事件 + /// + /// + /// + void Tunnel_ReaderStateChanged(ITunnel tunnel, TunnelReaderStateChangedEventArgs e); + /// + /// 通道机PLC状态变化事件 + /// + /// + /// + void Tunnel_PlcStateChanged(ITunnel tunnel, TunnelPlcStateChangedEventArgs e); + + /// + /// 通道机错误事件 + /// + /// + /// + void Tunnel_ErrorReceived(ITunnel tunnel, TunnelErrorReceivedEventArgs e); + + /// + /// 隧道关门 + /// + /// + string CloseDoor(); + + /// + /// 隧道开门 + /// + /// + /// + string OpenDoor(); + + } +} diff --git a/LolaiService/Devices/Tunnel/RfidTunnel.cs b/LolaiService/Devices/Tunnel/RfidTunnel.cs new file mode 100644 index 0000000..a98dcd7 --- /dev/null +++ b/LolaiService/Devices/Tunnel/RfidTunnel.cs @@ -0,0 +1,285 @@ +using LolaiService.Global; +using Rovinj.Device; +using Rovinj.Log; +using Rovinj.Reader; +using Rovinj.Reader.Silion; +using Rovinj.Tunnel; +using Rovinj.Tunnel.Plc; + +namespace LolaiService.Devices.Tunnel +{ + /// + /// 隧道机实现类 + /// + public class RfidTunnel : IRfidTunnel + { + /// + /// 是否开始校验数量 + /// + private volatile bool isStartCheckTags; + /// + /// 扫描ID的标签 + /// + private string tagsScanId; + /// + /// 标签ID列表,可以是EPC或TID + /// + private List tagIdList = new List(); + /// + /// 当前PLC的状态 + /// + private PlcStatus currentPlcStatus; + /// + /// 隧道是否已连接 + /// + //private bool isTunnelConnected; + /// + ///通道机接口 + /// + //private ITunnel tunnel; + /// + /// 线程退出标识 + /// + private CancellationTokenSource cancellationTokenSource; + /// + /// 检查标签线程 + /// + private Thread checkTagsThread; + /// + /// Silion读写器,支持R2000/E310/E710芯片,支持1、2、3、4、8、16口天线 + /// + private SilionReader silionReader; + + + /// + /// 通道机读写器状态变化事件 + /// + /// + /// + public void Tunnel_ReaderStateChanged(ITunnel tunnel, TunnelReaderStateChangedEventArgs e) + { + LogHelper.Error("e.RunningState:" + e.RunningState); + if (e.RunningState == 0) + { + //停止业务 + LogHelper.Info("停止业务"); + } + else if (e.RunningState == 1) + { + //启动业务 + tagsScanId = e.ScanId; + LogHelper.Info("启动业务"); + } + else + { + LogHelper.Info("其他状态"); + //其他状态 + } + } + + /// + /// 标签报告事件 + /// + /// + /// + public void Tunnel_TagsReported(ITunnel tunnel, TunnelTagsReportedEventArgs e) + { + LogHelper.Error("e.Tags.Count:" + e.Tags.Count); + for (int i = 0; i < e.Tags.Count; i++) + { + Tag tag = e.Tags[i]; + //过滤掉不符合扫描ID的标签 + if (tag.ScanId != tagsScanId) + continue; + + //如果配置为"TID"且TID不为空,则使用TID;否则使用EPC。检查标签ID是否已存在于 tagIdList 中,避免重复添加。 + if (tunnel.TunnelConfig.TagIdFieldName == "TID" && !string.IsNullOrEmpty(tag.TID)) + { + if (tagIdList.Contains(tag.TID)) + continue; + + tagIdList.Add(tag.TID); + LogHelper.Info("tag.TID:" + tag.TID); + } + else + { + if (tagIdList.Contains(tag.EPC)) + continue; + + tagIdList.Add(tag.EPC); + LogHelper.Info("tag.TID:" + tag.TID); + } + } + } + + + /// + /// 通道机PLC状态变化事件 + /// + /// + /// + public void Tunnel_PlcStateChanged(ITunnel tunnel, TunnelPlcStateChangedEventArgs e) + { + currentPlcStatus = e.PlcStatus;//记录当前PLC状态 + LogHelper.Info("通道机PLC状态变化事件:" + e.PlcStatus); + } + + /// + /// 通道机错误接收事件 + /// + /// + /// + /// + public void Tunnel_ErrorReceived(ITunnel tunnel, TunnelErrorReceivedEventArgs e) + { + // 在控制台输出错误信息,包括错误消息和异常详情 + Console.WriteLine($"错误信息:{e.ErrorMessage},异常:{e.Exception}"); + LogHelper.Error("通道机错误接收事件:" + $"错误信息:{e.ErrorMessage},异常:{e.Exception}"); + } + + /// + /// 关闭通道机连接 + /// + /// + /// + public void CloseTunnel() + { + if (GlobalData.tunnel == null) + return; + + if (GlobalData.tunnel.Reader.IsStarted) + { + GlobalData.tunnel.StopReader(); + } + + StopTunnel(); + GlobalData.tunnel.Close(); + GlobalData.tunnel = null; + GlobalData.isTunnelConnected = false; + } + + /// + /// 停止隧道 + /// + private void StopTunnel() + { + if (GlobalData.tunnel.IsStarted) + GlobalData.tunnel.Stop(); + + isStartCheckTags = false; + + if (cancellationTokenSource != null) + cancellationTokenSource.Cancel(); + + if (checkTagsThread != null) + checkTagsThread.Join(); + + } + + /// + /// 连接隧道 + /// + /// 配置RFID读写器参数 + /// 配置PLC连接方式 + /// 配置读写器连接方式 + public bool ConnectTunnel(SilionReaderConfig readerConfig, ConnectionConfig plcConnectionConfig, TunnelConfig tunnelConfig) + { + if (!GlobalData.isTunnelConnected) + { + //创建并打开隧道 + GlobalData.tunnel = TunnelFactory.CreateTunnel(TunnelType.SC201, tunnelConfig);//根据实际的设备选择对应的类型,这里假设是SC201 + GlobalData.tunnel.TagsReported += Tunnel_TagsReported; //读到标签时触发; + GlobalData.tunnel.ReaderStateChanged += Tunnel_ReaderStateChanged; //读写器状态变化 + GlobalData.tunnel.PlcStateChanged += Tunnel_PlcStateChanged; //PLC 状态变化 + GlobalData.tunnel.ErrorReceived += Tunnel_ErrorReceived; //收到错误时触发 + if (GlobalData.tunnel.Open()) + { + LogHelper.Info("连接成功"); + + GlobalData.isTunnelConnected = true; + + //获取读写器能力(支持的发射功率列表) + silionReader = GlobalData.tunnel.Reader as SilionReader; + if (silionReader.ReaderCapability != null) + { + //发射率列表 + List doubles = new List(); + for (int i = 0; i < silionReader.ReaderCapability.TxPowers.Count; i++) + { + doubles.Add(silionReader.ReaderCapability.TxPowers[i]); + LogHelper.Info("发射率列表:" + silionReader.ReaderCapability.TxPowers[i]); + } + } + + if (GlobalData.tunnel.Initialize())//复位 + { + LogHelper.Info("复位成功"); + //语音提示 + //SoundPlayer player = new SoundPlayer(); + //player.Play(); + } + return true; + } + else + { + LogHelper.Error("连接失败"); + GlobalData.tunnel.Close(); + GlobalData.isTunnelConnected = false; + return false; + } + } + else + { + CloseTunnel(); + return false; + } + } + + /// + /// 隧道关门 + /// + /// + public string CloseDoor() + { + if (GlobalData.tunnel == null) + { + return "隧道机未连接"; + } + if (GlobalData.tunnel.CloseDoor()) + { + return "已关门"; + } + else + { + return "关门失败"; + } + //MessageBox.Show(string.Format(crm.GetString("ExecuteCommandFailed"), btn_CloseDoor.Text)); + + } + /// + /// 隧道开门 + /// + /// + public string OpenDoor() + { + + if (GlobalData.tunnel == null) + { + return "隧道机未连接"; + } + if (GlobalData.tunnel.OpenDoor()) + { + return "已开门"; + } + else + { + return "开门失败"; + } + } + } + + + + + +} diff --git a/LolaiService/Global/GlobalData.cs b/LolaiService/Global/GlobalData.cs new file mode 100644 index 0000000..24d1f59 --- /dev/null +++ b/LolaiService/Global/GlobalData.cs @@ -0,0 +1,16 @@ +using Rovinj.Tunnel; + +namespace LolaiService.Global +{ + public static class GlobalData + { + /// + /// 隧道机是否已连接 + /// + public static bool isTunnelConnected = false; + /// + /// 隧道机接口 + /// + public static ITunnel tunnel; + } +} diff --git a/LolaiService/Global/GlobalDeviceInfo.cs b/LolaiService/Global/GlobalDeviceInfo.cs new file mode 100644 index 0000000..5e66643 --- /dev/null +++ b/LolaiService/Global/GlobalDeviceInfo.cs @@ -0,0 +1,124 @@ +using LolaiService.Devices.Tunnel; +using Rovinj.Device; +using Rovinj.Reader.Silion; +using Rovinj.Tunnel; +using Rovinj.Tunnel.Plc; + +namespace LolaiService.Global +{ + /// + /// 隧道机设备 + /// + public class GlobalDeviceInfo + { + /// + /// 连接设备 + /// + public static bool ConnectDevice() + { + //创建日志目录 + if (!Directory.Exists("log")) + Directory.CreateDirectory("log"); + + //初始化日志组件(仅供测试使用) + Rovinj.Log.LogHelper.InitLogger(new Rovinj.Log.TextLog($"log\\{DateTime.Now:yyyy-MM-dd}.log")); + + //隧道机业务层 + RfidTunnel rfidTunnel = new RfidTunnel(); + + ////配置RFID读写器参数 + #region 配置RFID读写器参数 + SilionReaderConfig readerConfig = new SilionReaderConfig() + { + Qvalue = 5, + Session = 1, + ReadTID = false, + Target = 0, + RfMode = 1, + IsFastRead = true, + QuickModeType = 3, + Antennas = new List(), + }; + double power = 30; //功率 + int antCount = 4; //4个天线 + + //根据用户输入的天线数量(默认 4 个),给每个天线端口配置功率和启用状态。 + for (int i = 0; i < antCount; i++) + { + readerConfig.Antennas.Add(new SilionAntennaConfig() + { + IsEnabled = true, + PortNumber = (ushort)(i + 1), + TxPowerInDbm = power + }); + } + #endregion + + + #region 配置PLC连接方式 + + ConnectionConfig plcConnectionConfig = new ConnectionConfig(); + plcConnectionConfig.ConnectionMode = ConnectionMode.Network; //网口连接模式 + plcConnectionConfig.NetworkAddress = "192.168.1.250"; //PLC IP地址 + plcConnectionConfig.NetworkPort = 502; //PLC 端口号 + #endregion + + + #region 配置读写器连接方式 + + ConnectionConfig readerConnectionConfig = new ConnectionConfig(); + readerConnectionConfig.Args = new object[] { antCount }; //天线数量,默认是4个天线,支持1,2,4,8,16 + readerConnectionConfig.ConnectionMode = ConnectionMode.Network; //网口连接模式 + readerConnectionConfig.NetworkAddress = "192.168.1.100"; + #endregion + + //封装成隧道配置 根据用户选择,判断是三菱还是西门子 PLC。 + TunnelConfig tunnelConfig = new TunnelConfig() + { + PlcType = PlcType.Mitsubishi_FX5U, //PLC类型 + PlcConnectionConfig = plcConnectionConfig, //PLC连接配置 + ReaderConnectionConfig = readerConnectionConfig, //读写器连接配置 + ReaderConfig = readerConfig, //读写器配置 + ReaderType = Rovinj.Tunnel.Reader.ReaderType.Silion //读写器类型 + }; + + ////西门子PLC暂时不支持使用串口的通讯方式 + //if ((tunnelConfig.PlcType == PlcType.Mitsubishi_FX5U || tunnelConfig.PlcType == PlcType.Siemens) + // && tunnelConfig.PlcConnectionConfig.ConnectionMode != ConnectionMode.Network) + //{ + // return false; + //} + + //是否连接成功 + bool result = rfidTunnel.ConnectTunnel(readerConfig, plcConnectionConfig, tunnelConfig); + + return result; + } + + /// + /// 隧道关门 + /// + /// + public static string CloseDoorTunnel() + { + RfidTunnel rfidTunnel = new RfidTunnel(); + + return rfidTunnel.CloseDoor(); + } + + /// + /// 隧道开门 + /// + /// + public static string OpenDoorTunnel() + { + RfidTunnel rfidTunnel = new RfidTunnel(); + + return rfidTunnel.OpenDoor(); + } + + + + + } +} diff --git a/LolaiService/Global/GlobalVar.cs b/LolaiService/Global/GlobalVar.cs new file mode 100644 index 0000000..cad90bf --- /dev/null +++ b/LolaiService/Global/GlobalVar.cs @@ -0,0 +1,16 @@ +namespace LolaiService.Global +{ + + public class GlobalVar + { + /// + /// 初始化设备 + /// + public static void InitData() + { + GlobalDeviceInfo.ConnectDevice(); + } + + + } +} diff --git a/LolaiService/LolaiService.csproj b/LolaiService/LolaiService.csproj new file mode 100644 index 0000000..e7f7ab3 --- /dev/null +++ b/LolaiService/LolaiService.csproj @@ -0,0 +1,35 @@ + + + + net8.0 + enable + enable + x86 + + + + + + + + + + ..\..\demo1.9\Rovinj.Device.dll + + + ..\..\demo1.9\Rovinj.Log.dll + + + ..\..\demo1.9\Rovinj.Reader.dll + + + ..\..\demo1.9\Rovinj.Reader.Silion.dll + + + ..\..\demo1.9\Rovinj.Tunnel.dll + + + + + + diff --git a/LolaiService/LolaiService.http b/LolaiService/LolaiService.http new file mode 100644 index 0000000..d9ffb53 --- /dev/null +++ b/LolaiService/LolaiService.http @@ -0,0 +1,6 @@ +@LolaiService_HostAddress = http://localhost:5049 + +GET {{LolaiService_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/LolaiService/Program.cs b/LolaiService/Program.cs new file mode 100644 index 0000000..49b6b06 --- /dev/null +++ b/LolaiService/Program.cs @@ -0,0 +1,39 @@ + +namespace LolaiService +{ + public class Program + { + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + // Add services to the container. + + builder.Services.AddControllers(); + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + builder.Services.AddEndpointsApiExplorer(); + builder.Services.AddSwaggerGen(); + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + app.UseSwagger(); + app.UseSwaggerUI(); + } + + app.UseHttpsRedirection(); + + app.UseAuthorization(); + + + app.MapControllers(); + + + Global.GlobalDeviceInfo.ConnectDevice(); + + app.Run(); + } + } +} diff --git a/LolaiService/Properties/launchSettings.json b/LolaiService/Properties/launchSettings.json new file mode 100644 index 0000000..0bc5103 --- /dev/null +++ b/LolaiService/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:50686", + "sslPort": 44389 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5049", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:8999;http://localhost:5049", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/LolaiService/WeatherForecast.cs b/LolaiService/WeatherForecast.cs new file mode 100644 index 0000000..418b0a5 --- /dev/null +++ b/LolaiService/WeatherForecast.cs @@ -0,0 +1,13 @@ +namespace LolaiService +{ + public class WeatherForecast + { + public DateOnly Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } + } +} diff --git a/LolaiService/appsettings.Development.json b/LolaiService/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/LolaiService/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/LolaiService/appsettings.json b/LolaiService/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/LolaiService/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/LolaiService/tunnelPlc.dll b/LolaiService/tunnelPlc.dll new file mode 100644 index 0000000..d38d4a4 Binary files /dev/null and b/LolaiService/tunnelPlc.dll differ diff --git a/LolaiSysService.sln b/LolaiSysService.sln new file mode 100644 index 0000000..6bebf19 --- /dev/null +++ b/LolaiSysService.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36623.8 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LolaiService", "LolaiService\LolaiService.csproj", "{9EF3747E-AF77-46F0-9F5B-624765C748E1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9EF3747E-AF77-46F0-9F5B-624765C748E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9EF3747E-AF77-46F0-9F5B-624765C748E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9EF3747E-AF77-46F0-9F5B-624765C748E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9EF3747E-AF77-46F0-9F5B-624765C748E1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4273D124-83C5-4283-AD67-CDC24E9BE380} + EndGlobalSection +EndGlobal