diff --git a/Modbus.Net/CrossLampControl.WebApi/Web.config b/Modbus.Net/CrossLampControl.WebApi/Web.config index a16f83e..b35f853 100644 --- a/Modbus.Net/CrossLampControl.WebApi/Web.config +++ b/Modbus.Net/CrossLampControl.WebApi/Web.config @@ -1,4 +1,4 @@ - + -
+
- + - + - - - + + + - + - - - - + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - + \ No newline at end of file diff --git a/Modbus.Net/ModBus.Net/AddressCombiner.cs b/Modbus.Net/ModBus.Net/AddressCombiner.cs index e920b6d..77df7da 100644 --- a/Modbus.Net/ModBus.Net/AddressCombiner.cs +++ b/Modbus.Net/ModBus.Net/AddressCombiner.cs @@ -36,32 +36,61 @@ namespace ModBus.Net int preNum = -1; Type preType = null; int getCount = 0; - foreach (var address in groupedAddress.OrderBy(address=>address.Address)) + foreach (var address in groupedAddress.OrderBy(address => address.Address)) { if (initNum < 0) { initNum = address.Address; - getCount = (int)BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]; + getCount = (int) BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]; } else { if (address.Address > preNum + BigEndianValueHelper.Instance.ByteLength[preType.FullName]) { - ans.Add(new CommunicationUnit(){Area = area, Address = initNum, GetCount = getCount, DataType = typeof(byte)}); + ans.Add(new CommunicationUnit() + { + Area = area, + Address = initNum, + GetCount = getCount, + DataType = typeof (byte) + }); initNum = address.Address; - getCount = (int)BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]; + getCount = (int) BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]; } else { - getCount += (int)BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]; + getCount += (int) BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]; } } preNum = address.Address; preType = address.DataType; } - ans.Add(new CommunicationUnit() { Area = area, Address = initNum, GetCount = getCount, DataType = typeof(byte) }); + ans.Add(new CommunicationUnit() + { + Area = area, + Address = initNum, + GetCount = getCount, + DataType = typeof (byte) + }); } return ans; } } + + public class AddressCombinerSingle : AddressCombiner + { + public override IEnumerable Combine(IEnumerable addresses) + { + return + addresses.Select( + address => + new CommunicationUnit() + { + Area = address.Area, + Address = address.Address, + DataType = address.DataType, + GetCount = 1 + }).ToList(); + } + } } diff --git a/Modbus.Net/ModBus.Net/BaseMachine.cs b/Modbus.Net/ModBus.Net/BaseMachine.cs index 03539ed..b98c812 100644 --- a/Modbus.Net/ModBus.Net/BaseMachine.cs +++ b/Modbus.Net/ModBus.Net/BaseMachine.cs @@ -144,7 +144,11 @@ namespace ModBus.Net BigEndianValueHelper.Instance.ByteLength[ communicateAddress.DataType.FullName])); //如果没有数据,终止 - if (datas == null || datas.Length == 0) return null; + if (datas == null || datas.Length == 0 || datas.Length != + (int) + Math.Ceiling(communicateAddress.GetCount * + BigEndianValueHelper.Instance.ByteLength[ + communicateAddress.DataType.FullName])) return null; int pos = 0; //解码数据 while (pos < communicateAddress.GetCount) diff --git a/Modbus.Net/ModBus.Net/ConfigurationManager.Designer.cs b/Modbus.Net/ModBus.Net/ConfigurationManager.Designer.cs index 3e90557..55208f8 100644 --- a/Modbus.Net/ModBus.Net/ConfigurationManager.Designer.cs +++ b/Modbus.Net/ModBus.Net/ConfigurationManager.Designer.cs @@ -69,6 +69,15 @@ namespace ModBus.Net { } } + /// + /// 查找类似 opcda://localhost/FBoxOpcServer 的本地化字符串。 + /// + internal static string FBoxOpcDaHost { + get { + return ResourceManager.GetString("FBoxOpcDaHost", resourceCulture); + } + } + /// /// 查找类似 192.168.1.1 的本地化字符串。 /// @@ -96,6 +105,15 @@ namespace ModBus.Net { } } + /// + /// 查找类似 opcda://localhost/... 的本地化字符串。 + /// + internal static string OpcDaHost { + get { + return ResourceManager.GetString("OpcDaHost", resourceCulture); + } + } + /// /// 查找类似 102 的本地化字符串。 /// diff --git a/Modbus.Net/ModBus.Net/ConfigurationManager.resx b/Modbus.Net/ModBus.Net/ConfigurationManager.resx index 720ced4..ea86858 100644 --- a/Modbus.Net/ModBus.Net/ConfigurationManager.resx +++ b/Modbus.Net/ModBus.Net/ConfigurationManager.resx @@ -120,6 +120,9 @@ COM1 + + opcda://localhost/FBoxOpcServer + 192.168.1.1 @@ -129,6 +132,9 @@ 502 + + opcda://localhost/... + 102 diff --git a/Modbus.Net/ModBus.Net/FBox/FBoxConnector.cs b/Modbus.Net/ModBus.Net/FBox/FBoxConnector.cs new file mode 100644 index 0000000..fc54a85 --- /dev/null +++ b/Modbus.Net/ModBus.Net/FBox/FBoxConnector.cs @@ -0,0 +1,621 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNet.SignalR.Client; +using Newtonsoft.Json; +using Thinktecture.IdentityModel.Client; + +namespace ModBus.Net.FBox +{ + public struct SignalRSigninMsg + { + public string ClientId { get; set; } + public string ClientSecret { get; set; } + public string UserId { get; set; } + public string Password { get; set; } + public string SigninAdditionalValues { get; set; } + public SignalRServer SignalRServer { get; set; } + } + + public class FBoxConnector : BaseConnector + { + private OAuth2Client _oauth2; + private string _refreshToken; + + private HttpClient _httpClient; + private HttpClient _httpClient2; + private HubConnection _hubConnection; + private SignalRSigninMsg _msg; + protected SignalRSigninMsg Msg => _msg; + private DMonGroup _dataGroup; + private int _state; + private string _groupUid; + private string _boxUid; + private string _boxNo; + private int _boxSessionId; + private int _connectionState; + private Dictionary _data; + private Dictionary _dataType; + + private DateTime _timeStamp = DateTime.MinValue; + + public override string ConnectionToken { get; } + + private AsyncLock _lock = new AsyncLock(); + + private Timer _timer; + + private string MachineId => ConnectionToken.Split(',')[0]; + + private string LocalSequence => ConnectionToken.Split(',')[1]; + + private bool _connected; + public override bool IsConnected => _connected; + + private bool Connected + { + get { return _connected; } + set + { + if (value == false) + { + Disconnect(); + } + _connected = value; + + } + } + + private Constants _constants; + private Constants Constants => _constants ?? (_constants = new Constants()); + + public FBoxConnector(string machineId, string localSequence, SignalRSigninMsg msg) + { + Constants.SignalRServer = msg.SignalRServer; + System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; + ConnectionToken = machineId + "," + localSequence; + _msg = msg; + _data = new Dictionary(); + _dataType = new Dictionary(); + } + + private async void ChangeToken(object sender) + { + try + { + + var tokenResponse = await _oauth2.RequestRefreshTokenAsync(_refreshToken); + _refreshToken = tokenResponse.RefreshToken; + _httpClient.SetBearerToken(tokenResponse.AccessToken); + + _httpClient2.SetBearerToken(tokenResponse.AccessToken); + _hubConnection.Stop(); + _hubConnection.Headers["Authorization"] = "Bearer " + tokenResponse.AccessToken; + await _hubConnection.Start(); + await + _httpClient2.PostAsync( + "dmon/group/" + _dataGroup.Uid + "/start", null); + + } + catch (Exception e) + { + Console.WriteLine("Retoken failed." + e.Message); + } + Console.WriteLine("Retoken success."); + } + + public override bool Connect() + { + return AsyncHelper.RunSync(ConnectAsync); + } + + public override async Task ConnectAsync() + { + try + { + + _oauth2 = new OAuth2Client( + new Uri(Constants.TokenEndpoint), + Msg.ClientId, + Msg.ClientSecret + ); + var tokenResponse = await _oauth2.RequestResourceOwnerPasswordAsync + ( + Msg.UserId, + Msg.Password, + Msg.SigninAdditionalValues + ); + if (tokenResponse != null) + { + _refreshToken = tokenResponse.RefreshToken; + await CallService(Msg, tokenResponse.AccessToken); + } + + await + _httpClient2.PostAsync( + "dmon/group/" + _dataGroup.Uid + "/start", null); + Connected = true; + _timer = new Timer(ChangeToken, null, 3600*1000*4, 3600*1000*4); + Console.WriteLine("SignalR Connected success"); + return true; + + } + catch (Exception e) + { + _oauth2 = null; + Console.WriteLine("SignalR Connected failed"); + return false; + } + } + + private async Task CallService(SignalRSigninMsg msg, string token) + { + + var guid = Guid.NewGuid().ToString(); + + var baseAddress = Constants.AspNetWebApiSampleApi; + + _httpClient = new HttpClient + { + BaseAddress = new Uri(baseAddress) + }; + + _httpClient.SetBearerToken(token); + + //var response = await _httpClient.GetStringAsync("device/spec"); + + //List deviceSpecs = JsonConvert.DeserializeObject>(response); + //deviceSpecs = deviceSpecs.OrderBy(p => p.Id).ToList(); + + + var response = await _httpClient.GetStringAsync("boxgroup"); + + List boxGroups = JsonConvert.DeserializeObject>(response); + + foreach (var boxGroup in boxGroups) + { + var boxes = boxGroup.BoxRegs; + foreach (var box in boxes) + { + var sessionId = box.Box.CurrentSessionId; + var baseUrl = box.Box.CommServer.ApiBaseUrl; + var signalrUrl = box.Box.CommServer.SignalRUrl; + var boxUid = box.Box.Uid; + var boxNo = box.Box.BoxNo; + var connectionState = box.Box.ConnectionState; + + + if (boxNo != MachineId) continue; + + _httpClient2 = new HttpClient + { + BaseAddress = new Uri(baseUrl) + }; + _httpClient2.SetBearerToken(token); + _httpClient2.DefaultRequestHeaders.Add("X-FBox-ClientId", guid); + + response = await _httpClient2.GetStringAsync("box/" + box.Box.Uid + "/dmon/def/grouped"); + + + List dataGroups = JsonConvert.DeserializeObject>(response); + foreach (var dataGroup in dataGroups) + { + if (dataGroup.Name == LocalSequence) + { + _dataGroup = dataGroup; + break; + } + } + + _boxSessionId = sessionId; + _boxNo = boxNo; + _connectionState = connectionState; + + _hubConnection = new HubConnection(signalrUrl); + _hubConnection.Headers.Add("Authorization", "Bearer " + token); + _hubConnection.Headers.Add("X-FBox-ClientId", guid); + _hubConnection.Headers.Add("X-FBox-Session", sessionId.ToString()); + + IHubProxy dataHubProxy = _hubConnection.CreateHubProxy("clientHub"); + dataHubProxy.On>("dMonUpdateValue", + (boxSessionId, values) => + { + +//#if DEBUG + //Console.WriteLine($"Box session {boxSessionId} return at {DateTime.Now}"); +//#endif + + _timeStamp = DateTime.Now; + + foreach (var value in values) + { + if (value.Status != 0) + { + lock (_data) + { + var dMonEntry = + _dataGroup.DMonEntries.FirstOrDefault( + p => p.Uid == value.Id); + if (dMonEntry != null) + { + if (_data.ContainsKey(dMonEntry.Desc)) + { + _data.Remove(dMonEntry.Desc); + } + } + + } + return; + } + lock (_data) + { + if (_dataGroup.DMonEntries.Any(p => p.Uid == value.Id)) + { + if (_data == null) + { + _data = new Dictionary(); + } + + var dMonEntry = _dataGroup.DMonEntries.FirstOrDefault( + p => p.Uid == value.Id); + + if (value.Value.HasValue && dMonEntry != null) + { + if (_data.ContainsKey(dMonEntry.Desc)) + { + _data[dMonEntry.Desc] = value.Value.Value; + } + else + { + _data.Add(dMonEntry.Desc, value.Value.Value); + } + } + } + } + } + }); + + dataHubProxy.On("boxConnectionStateChanged", + async (newConnectionToken, getBoxUid, oldStatus, newStatus) => + { + //#if DEBUG + //Console.WriteLine( + //$"Box uid {getBoxUid} change state at {DateTime.Now} new connectionToken {newConnectionToken} newStatus {newStatus}"); + //#endif + sessionId = newConnectionToken; + _boxSessionId = sessionId; + + _connectionState = newStatus; + + _httpClient2.DefaultRequestHeaders.Remove("X-FBox-Session"); + _httpClient2.DefaultRequestHeaders.Add("X-FBox-Session", + sessionId.ToString()); + _hubConnection.Headers["X-FBox-Session"] = sessionId.ToString(); + + if (_hubConnection.State == ConnectionState.Disconnected) + { + await _hubConnection.Start(); + } + + if (newStatus == 1) + { + if (Connected) + { + await + _httpClient2.PostAsync( + "dmon/group/" + _dataGroup.Uid + "/start", null); + } + } + + else + { + lock (_data) + { + _data.Clear(); + } + Connected = false; + } + + }); + + _hubConnection.Error += async ex => + { + Console.WriteLine(@"SignalR error: {0}", ex.Message); + await ConnectRecovery(_hubConnection); + }; + + _hubConnection.Closed += async () => + { + await ConnectRecovery(_hubConnection); + }; + + ServicePointManager.DefaultConnectionLimit = 10; + + if (_dataGroup == null) return; + + var groupUid = _dataGroup.Uid; + var groupName = _dataGroup.Name; + + if (groupName != "(Default)" && groupName != "默认组" && _connectionState == 1) + { + _groupUid = groupUid; + } + if (groupName != "(Default)" && groupName != "默认组" && _connectionState == 1) + { + _boxUid = boxUid; + } + + _dataType = new Dictionary(); + + foreach (var dMonEntry in _dataGroup.DMonEntries) + { + Type type; + switch (dMonEntry.DataType) + { + //位 + case 0: + { + type = typeof (bool); + break; + } + //16位无符号 + case 1: + { + type = typeof (ushort); + break; + } + //16位有符号 + case 2: + { + type = typeof (short); + break; + } + //32位无符号 + case 11: + { + type = typeof (uint); + break; + } + //32位有符号 + case 12: + { + type = typeof (int); + break; + } + //16位BCD + case 3: + { + type = typeof (short); + break; + } + //32位BCD + case 13: + { + type = typeof (int); + break; + } + //浮点数 + case 16: + { + type = typeof (float); + break; + } + //16位16进制 + case 4: + { + type = typeof (short); + break; + } + //32位16进制 + case 14: + { + type = typeof (int); + break; + } + //16位2进制 + case 5: + { + type = typeof (short); + break; + } + //32位2进制 + case 15: + { + type = typeof (int); + break; + } + default: + { + type = typeof (short); + break; + } + } + + if (!_dataType.ContainsKey(dMonEntry.Desc)) + { + _dataType.Add(dMonEntry.Desc, type); + } + else + { + _dataType[dMonEntry.Desc] = type; + } + } + + + await _hubConnection.Start(); + await dataHubProxy.Invoke("updateClientId", guid); + } + } + } + + private async Task ConnectRecovery(HubConnection hubConnection) + { + + + try + { + if (hubConnection.State != ConnectionState.Connected) + { + try + { + hubConnection.Stop(); + } + catch + { + // ignored + } + + await hubConnection.Start(); + if (Connected) + { + await + _httpClient2.PostAsync( + "dmon/group/" + _dataGroup.Uid + "/start", null); + } + } + + } + catch + { + lock (_data) + { + _data.Clear(); + } + Connected = false; + } + + + } + + + public override bool Disconnect() + { + return AsyncHelper.RunSync(DisconnectAsync); + } + + public async Task DisconnectAsync() + { + try + { + + await + _httpClient2.PostAsync( + "dmon/group/" + _groupUid + "/stop", + null); + _connected = false; + _timer.Dispose(); + _timer = null; + Console.WriteLine("SignalR Disconnect success"); + return true; + + } + catch + { + Console.WriteLine("SignalR Disconnect failed"); + return false; + } + } + + public override bool SendMsgWithoutReturn(byte[] message) + { + throw new NotImplementedException(); + } + + public override Task SendMsgWithoutReturnAsync(byte[] message) + { + throw new NotImplementedException(); + } + + public override byte[] SendMsg(byte[] message) + { + if (_httpClient == null) + { + Connected = false; + return null; + } + + if (_hubConnection.State == ConnectionState.Disconnected) + { + _hubConnection.Start(); + } + + var formater = new AddressFormaterFBox(); + var translator = new AddressTranslatorFBox(); + + byte[] ans; + + if (_connectionState != 1) + { + Connected = false; + Console.WriteLine($"Return Value Rejected with connectionToken {ConnectionToken}"); + return null; + } + + if (_timeStamp == DateTime.MinValue) + { + return Encoding.ASCII.GetBytes("NoData"); + } + + if (DateTime.Now - _timeStamp > TimeSpan.FromMinutes(1)) + { + Connected = false; + return null; + } + + Dictionary machineDataValue; + lock (_data) + { + machineDataValue = _data.ToDictionary(pair => pair.Key, pair => pair.Value); + } + var machineDataType = _dataType; + if (machineDataType == null || machineDataType.Count == 0) + { + Connected = false; + Console.WriteLine($"Return Value Rejected with connectionToken {ConnectionToken}"); + return null; + } + + if (machineDataValue == null || machineDataValue.Count == 0) + { + return Encoding.ASCII.GetBytes("NoData"); + } + + int pos = 0; + int area = BigEndianValueHelper.Instance.GetInt(message, ref pos); + int address = BigEndianValueHelper.Instance.GetInt(message, ref pos); + //short count = BigEndianValueHelper.Instance.GetShort(message, ref pos); + object[] dataAns = new object[1]; + try + { + dataAns[0] = + Convert.ChangeType( + machineDataValue[formater.FormatAddress(translator.GetAreaName(area), address)], + machineDataType[formater.FormatAddress(translator.GetAreaName(area), address)]); + } + catch (Exception e) + { + return Encoding.ASCII.GetBytes("NoData"); + //dataAns[0] = + //Convert.ChangeType( + //0, + //machineDataType[formater.FormatAddress(translator.GetAreaName(area), address)]); + } + finally + { + ans = BigEndianValueHelper.Instance.ObjectArrayToByteArray(dataAns); + } + + return ans; + } + + public override Task SendMsgAsync(byte[] message) + { + return Task.Factory.StartNew(() => SendMsg(message)); + } + } +} diff --git a/Modbus.Net/ModBus.Net/FBox/FBoxProtocalLinker.cs b/Modbus.Net/ModBus.Net/FBox/FBoxProtocalLinker.cs new file mode 100644 index 0000000..c486dbf --- /dev/null +++ b/Modbus.Net/ModBus.Net/FBox/FBoxProtocalLinker.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ModBus.Net.FBox +{ + public class FBoxProtocalLinker : ProtocalLinker + { + protected FBoxProtocalLinker(string machineId, string localSequence, SignalRSigninMsg msg) + { + _baseConnector = new FBoxConnector(machineId, localSequence, msg); + } + + public override bool CheckRight(byte[] content) + { + if (content != null && content.Length == 6 && Encoding.ASCII.GetString(content) == "NoData") + { + return false; + } + return base.CheckRight(content); + } + } +} diff --git a/Modbus.Net/ModBus.Net/FBox/FBoxSignalRProtocalLinker.cs b/Modbus.Net/ModBus.Net/FBox/FBoxSignalRProtocalLinker.cs index 9b041c1..ff29eb4 100644 --- a/Modbus.Net/ModBus.Net/FBox/FBoxSignalRProtocalLinker.cs +++ b/Modbus.Net/ModBus.Net/FBox/FBoxSignalRProtocalLinker.cs @@ -6,15 +6,10 @@ using System.Threading.Tasks; namespace ModBus.Net.FBox { - public class FBoxSignalRProtocalLinker : SignalRProtocalLinker + public class FBoxSignalRProtocalLinker : FBoxProtocalLinker { public FBoxSignalRProtocalLinker(string machineId, string localSequence, SignalRSigninMsg msg) : base(machineId, localSequence, msg) { } - - public override bool CheckRight(byte[] content) - { - return true; - } } } diff --git a/Modbus.Net/ModBus.Net/FBox/SignalRConnector.cs b/Modbus.Net/ModBus.Net/FBox/SignalRConnector.cs deleted file mode 100644 index 1f45b6c..0000000 --- a/Modbus.Net/ModBus.Net/FBox/SignalRConnector.cs +++ /dev/null @@ -1,747 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNet.SignalR.Client; -using Newtonsoft.Json; -using Thinktecture.IdentityModel.Client; - -namespace ModBus.Net.FBox -{ - public struct SignalRSigninMsg - { - public string ClientId { get; set; } - public string ClientSecret { get; set; } - public string UserId { get; set; } - public string Password { get; set; } - public string SigninAdditionalValues { get; set; } - public SignalRServer SignalRServer { get; set; } - } - - public class SignalRConnector : BaseConnector - { - private static Dictionary _oauth2; - private static Dictionary _refreshToken; - - private static Dictionary _httpClient; - private static Dictionary _httpClient2; - private static Dictionary _hubConnections; - private static Dictionary _boxUidMsg; - private static Dictionary _boxUidSessionId; - private static Dictionary> _boxUidDataGroups; - private static Dictionary _connectionTokenState; - private static Dictionary _groupNameUid; - private static Dictionary _groupNameBoxUid; - private static Dictionary> _machineData; - private static Dictionary> _machineDataType; - private static Dictionary _boxUidBoxNo; - private static HashSet _connectedDataGroupUid; - - public override string ConnectionToken { get; } - - private Timer _timer; - - private string MachineId => ConnectionToken.Split(',')[0]; - - private string LocalSequence => ConnectionToken.Split(',')[1]; - - private static readonly AsyncLock _lock = new AsyncLock(); - - private bool _connected; - public override bool IsConnected => _connected; - private SignalRSigninMsg Msg { get; set;} - - private Constants _constants; - private Constants Constants => _constants ?? (_constants = new Constants()); - - public SignalRConnector(string machineId, string localSequence, SignalRSigninMsg msg) - { - Constants.SignalRServer = msg.SignalRServer; - System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; - ConnectionToken = machineId + "," + localSequence; - if (_oauth2 == null) - { - _httpClient = new Dictionary(); - _oauth2 = new Dictionary(); - _refreshToken = new Dictionary(); - _boxUidMsg = new Dictionary(); - _hubConnections = new Dictionary(); - _httpClient2 = new Dictionary(); - _machineData = new Dictionary>(); - _machineDataType = new Dictionary>(); - _boxUidSessionId = new Dictionary(); - _connectionTokenState = new Dictionary(); - _groupNameUid = new Dictionary(); - _groupNameBoxUid = new Dictionary(); - _boxUidDataGroups = new Dictionary>(); - _boxUidBoxNo = new Dictionary(); - _connectedDataGroupUid = new HashSet(); - _timer = new Timer(ChangeToken, null, 3600 * 1000 * 4, 3600 * 1000 * 4); - } - Msg = msg; - } - - private async void ChangeToken(object sender) - { - try - { - using (await _lock.LockAsync()) - { - var tokenResponse = await _oauth2[Msg].RequestRefreshTokenAsync(_refreshToken[Msg]); - _refreshToken[Msg] = tokenResponse.RefreshToken; - _httpClient[Msg].SetBearerToken(tokenResponse.AccessToken); - - foreach (var boxUidMsg in _boxUidMsg) - { - if (boxUidMsg.Value.Equals(Msg)) - { - if (_httpClient2.ContainsKey(boxUidMsg.Key) && _hubConnections.ContainsKey(boxUidMsg.Key)) - _httpClient2[boxUidMsg.Key].SetBearerToken(tokenResponse.AccessToken); - _hubConnections[boxUidMsg.Key].Stop(); - _hubConnections[boxUidMsg.Key].Headers["Authorization"] = "Bearer " + - tokenResponse.AccessToken; - await _hubConnections[boxUidMsg.Key].Start(); - var localDataGroups = _boxUidDataGroups[boxUidMsg.Key]; - foreach (var localDataGroup in localDataGroups) - { - if (_connectedDataGroupUid.Contains(localDataGroup.Uid)) - { - await - _httpClient2[boxUidMsg.Key].PostAsync( - "dmon/group/" + localDataGroup.Uid + "/start", null); - } - } - } - } - } - } - catch (Exception e) - { - Console.WriteLine("Retoken failed." + e.Message); - } - Console.WriteLine("Retoken success."); - } - - public override bool Connect() - { - return AsyncHelper.RunSync(ConnectAsync); - } - - public override async Task ConnectAsync() - { - try - { - using (await _lock.LockAsync()) - { - if (!_oauth2.ContainsKey(Msg)) - { - _oauth2.Add(Msg, new OAuth2Client( - new Uri(Constants.TokenEndpoint), - Msg.ClientId, - Msg.ClientSecret - )); - var tokenResponse = await _oauth2[Msg].RequestResourceOwnerPasswordAsync - ( - Msg.UserId, - Msg.Password, - Msg.SigninAdditionalValues - ); - if (tokenResponse != null) - { - _refreshToken.Add(Msg, tokenResponse.RefreshToken); - AsyncHelper.RunSync(()=> CallService(Msg, tokenResponse.AccessToken)); - } - } - - - if (_groupNameBoxUid.ContainsKey(ConnectionToken) && _hubConnections.ContainsKey(_groupNameBoxUid[ConnectionToken]) && - _httpClient2.ContainsKey(_groupNameBoxUid[ConnectionToken]) && - _groupNameUid.ContainsKey(ConnectionToken)) - { - await - _httpClient2[_groupNameBoxUid[ConnectionToken]].PostAsync( - "dmon/group/" + _groupNameUid[ConnectionToken] + "/start", - null); - _connectedDataGroupUid.Add(_groupNameUid[ConnectionToken]); - _connected = true; - Console.WriteLine("SignalR Connected success"); - return true; - } - else - { - _connected = false; - Console.WriteLine("SignalR Connected failed"); - return false; - } - } - } - catch (Exception e) - { - if (_oauth2.ContainsKey(Msg)) - { - _oauth2.Remove(Msg); - } - Console.WriteLine("SignalR Connected failed"); - return false; - } - } - - private async Task CallService(SignalRSigninMsg msg, string token) - { - - var guid = Guid.NewGuid().ToString(); - - var baseAddress = Constants.AspNetWebApiSampleApi; - - if (!_httpClient.ContainsKey(msg)) - { - _httpClient.Add(msg, new HttpClient - { - BaseAddress = new Uri(baseAddress) - }); - } - - _httpClient[msg].SetBearerToken(token); - - //var response = await _httpClient.GetStringAsync("device/spec"); - - //List deviceSpecs = JsonConvert.DeserializeObject>(response); - //deviceSpecs = deviceSpecs.OrderBy(p => p.Id).ToList(); - - - var response = await _httpClient[msg].GetStringAsync("boxgroup"); - - List boxGroups = JsonConvert.DeserializeObject>(response); - - foreach (var boxGroup in boxGroups) - { - var boxes = boxGroup.BoxRegs; - foreach (var box in boxes) - { - var sessionId = box.Box.CurrentSessionId; - var baseUrl = box.Box.CommServer.ApiBaseUrl; - var signalrUrl = box.Box.CommServer.SignalRUrl; - var boxUid = box.Box.Uid; - var boxNo = box.Box.BoxNo; - - //var currentStat = box.Box.ConnectionState; - - var client2 = new HttpClient - { - BaseAddress = new Uri(baseUrl) - }; - client2.SetBearerToken(token); - client2.DefaultRequestHeaders.Add("X-FBox-ClientId", guid); - - response = await client2.GetStringAsync("box/" + box.Box.Uid + "/dmon/def/grouped"); - - if (_boxUidDataGroups.ContainsKey(boxUid)) - { - break; - } - - List dataGroups = JsonConvert.DeserializeObject>(response); - _boxUidDataGroups.Add(boxUid, dataGroups); - lock (_boxUidSessionId) - { - _boxUidSessionId.Add(boxUid, sessionId); - } - _boxUidBoxNo.Add(boxUid, boxNo); - _boxUidMsg.Add(boxUid, Msg); - - var hubConnection = new HubConnection(signalrUrl); - _hubConnections.Add(boxUid, hubConnection); - hubConnection.Headers.Add("Authorization", "Bearer " + token); - hubConnection.Headers.Add("X-FBox-ClientId", guid); - hubConnection.Headers.Add("X-FBox-Session", sessionId.ToString()); - - IHubProxy dataHubProxy = hubConnection.CreateHubProxy("clientHub"); - dataHubProxy.On>("dMonUpdateValue", - (boxSessionId, values) => - { - lock (_boxUidSessionId) - { - if (_boxUidSessionId.ContainsValue(boxSessionId)) - { - Console.WriteLine($"Box session {boxSessionId} return at {DateTime.Now}"); - var localBoxUid = - _boxUidSessionId.FirstOrDefault(p => p.Value == boxSessionId).Key; - var localBoxNo = _boxUidBoxNo[localBoxUid]; - - foreach (var value in values) - { - if (value.Status != 0) - { - lock (_machineData) - { - if (_boxUidDataGroups.ContainsKey(localBoxUid)) - { - foreach (var dataGroupInner in _boxUidDataGroups[localBoxUid]) - { - var dMonEntry = - dataGroupInner.DMonEntries.FirstOrDefault( - p => p.Uid == value.Id); - if (dMonEntry != null && - _machineData.ContainsKey(localBoxNo + "," + - dataGroupInner.Name)) - { - if (_machineData[localBoxNo + "," + dataGroupInner.Name] - .ContainsKey(dMonEntry.Desc)) - { - _machineData[localBoxNo + "," + dataGroupInner.Name] - .Remove(dMonEntry.Desc); - } - } - } - } - } - return; - } - lock (_machineData) - { - if (_boxUidDataGroups.ContainsKey(localBoxUid)) - { - foreach (var dataGroupInner in _boxUidDataGroups[localBoxUid]) - { - if (dataGroupInner.DMonEntries.Any(p => p.Uid == value.Id)) - { - if ( - !_machineData.ContainsKey(localBoxNo + "," + - dataGroupInner.Name)) - { - _machineData.Add(localBoxNo + "," + dataGroupInner.Name, - new Dictionary()); - } - if (_machineData[localBoxNo + "," + dataGroupInner.Name] == - null) - { - _machineData[localBoxNo + "," + dataGroupInner.Name] = - new Dictionary(); - } - - var dMonEntry = - dataGroupInner.DMonEntries.FirstOrDefault( - p => p.Uid == value.Id); - - if (value.Value.HasValue && dMonEntry != null) - { - if ( - _machineData[localBoxNo + "," + dataGroupInner.Name] - .ContainsKey( - dMonEntry.Desc)) - { - _machineData[localBoxNo + "," + dataGroupInner.Name] - [dMonEntry.Desc] = - value.Value.Value; - } - else - { - _machineData[localBoxNo + "," + dataGroupInner.Name] - .Add(dMonEntry.Desc, - value.Value.Value); - } - } - break; - } - } - } - } - } - } - } - }); - - dataHubProxy.On("boxConnectionStateChanged", - async (newConnectionToken, getBoxUid, oldStatus, newStatus) => - { - using (await _lock.LockAsync()) - { - if (_httpClient2.ContainsKey(getBoxUid)) - { - Console.WriteLine( - $"Box uid {getBoxUid} change state at {DateTime.Now} new connectionToken {newConnectionToken} newStatus {newStatus}"); - sessionId = newConnectionToken; - lock (_boxUidSessionId) - { - _boxUidSessionId[getBoxUid] = sessionId; - } - - var localBoxNo = _boxUidBoxNo[getBoxUid]; - var localDataGroups = _boxUidDataGroups[getBoxUid]; - lock (_connectionTokenState) - { - foreach (var localDataGroup in localDataGroups) - { - if ( - !_connectionTokenState.ContainsKey(localBoxNo + "," + - localDataGroup.Name)) - { - _connectionTokenState.Add(localBoxNo + "," + localDataGroup.Name, - newStatus); - } - else - { - _connectionTokenState[localBoxNo + "," + localDataGroup.Name] = - newStatus; - } - } - } - _httpClient2[getBoxUid].DefaultRequestHeaders.Remove("X-FBox-Session"); - _httpClient2[getBoxUid].DefaultRequestHeaders.Add("X-FBox-Session", - sessionId.ToString()); - _hubConnections[getBoxUid].Headers["X-FBox-Session"] = sessionId.ToString(); - - if (_hubConnections[getBoxUid].State == ConnectionState.Disconnected) - { - await _hubConnections[getBoxUid].Start(); - } - - if (newStatus == 1) - { - foreach (var localDataGroup in localDataGroups) - { - if (_connectedDataGroupUid.Contains(localDataGroup.Uid)) - { - await - _httpClient2[getBoxUid].PostAsync( - "dmon/group/" + localDataGroup.Uid + "/start", null); - } - } - } - } - } - }); - - hubConnection.Error += async ex => - { - Console.WriteLine(@"SignalR error: {0}", ex.Message); - await ConnectRecovery(hubConnection); - }; - - hubConnection.Closed += async () => - { - await ConnectRecovery(hubConnection); - }; - - ServicePointManager.DefaultConnectionLimit = 10; - - foreach (var dataGroup in dataGroups) - { - if (dataGroup == null) return; - - var groupUid = dataGroup.Uid; - var groupName = dataGroup.Name; - - if (groupName != "(Default)" && groupName != "默认组" && - !_connectionTokenState.ContainsKey(boxNo + "," + groupName)) - { - _connectionTokenState.Add(boxNo + "," + groupName, 1); - } - if (groupName != "(Default)" && groupName != "默认组" && - !_groupNameUid.ContainsKey(boxNo + "," + groupName)) - { - _groupNameUid.Add(boxNo + "," + groupName, groupUid); - } - if (groupName != "(Default)" && groupName != "默认组" && - !_groupNameBoxUid.ContainsKey(boxNo + "," + groupName)) - { - _groupNameBoxUid.Add(boxNo + "," + groupName, boxUid); - } - if (groupName != "(Default)" && groupName != "默认组" && !_httpClient2.ContainsKey(boxUid)) - { - _httpClient2.Add(boxUid, client2); - } - - if (!_machineDataType.ContainsKey(boxNo + "," + groupName)) - { - _machineDataType.Add(boxNo + "," + groupName, new Dictionary()); - } - foreach (var dMonEntry in dataGroup.DMonEntries) - { - Type type; - switch (dMonEntry.DataType) - { - //位 - case 0: - { - type = typeof (bool); - break; - } - //16位无符号 - case 1: - { - type = typeof (ushort); - break; - } - //16位有符号 - case 2: - { - type = typeof (short); - break; - } - //32位无符号 - case 11: - { - type = typeof (uint); - break; - } - //32位有符号 - case 12: - { - type = typeof (int); - break; - } - //16位BCD - case 3: - { - type = typeof (short); - break; - } - //32位BCD - case 13: - { - type = typeof (int); - break; - } - //浮点数 - case 16: - { - type = typeof (float); - break; - } - //16位16进制 - case 4: - { - type = typeof (short); - break; - } - //32位16进制 - case 14: - { - type = typeof (int); - break; - } - //16位2进制 - case 5: - { - type = typeof (short); - break; - } - //32位2进制 - case 15: - { - type = typeof (int); - break; - } - default: - { - type = typeof (short); - break; - } - } - - if (!_machineDataType[boxNo + "," + groupName].ContainsKey(dMonEntry.Desc)) - { - _machineDataType[boxNo + "," + groupName].Add(dMonEntry.Desc, type); - } - else - { - _machineDataType[boxNo + "," + groupName][dMonEntry.Desc] = type; - } - } - } - - await hubConnection.Start(); - await dataHubProxy.Invoke("updateClientId", guid); - } - - } - } - - private async Task ConnectRecovery(HubConnection hubConnection) - { - using (await _lock.LockAsync()) - { - string getBoxUid; - lock (_boxUidSessionId) - { - getBoxUid = - _boxUidSessionId.FirstOrDefault( - p => p.Value == int.Parse(hubConnection.Headers["X-FBox-Session"])).Key; - } - try - { - if (hubConnection.State != ConnectionState.Connected) - { - try - { - hubConnection.Stop(); - } - catch - { - // ignored - } - - await hubConnection.Start(); - var localDataGroups = _boxUidDataGroups[getBoxUid]; - foreach (var localDataGroup in localDataGroups) - { - if (_connectedDataGroupUid.Contains(localDataGroup.Uid)) - { - await - _httpClient2[getBoxUid].PostAsync( - "dmon/group/" + localDataGroup.Uid + "/start", null); - } - } - } - } - catch - { - if (_boxUidBoxNo.ContainsKey(getBoxUid)) - { - var localBoxNo = _boxUidBoxNo[getBoxUid]; - lock (_machineData) - { - foreach (var machineDataUnit in _machineData) - { - if (machineDataUnit.Key.Contains(localBoxNo)) - { - _machineData.Remove(machineDataUnit.Key); - } - } - } - } - var localDataGroups = _boxUidDataGroups[getBoxUid]; - foreach (var localDataGroup in localDataGroups) - { - _connectedDataGroupUid.RemoveWhere(p => p == localDataGroup.Uid); - } - _connected = false; - } - } - } - - public override bool Disconnect() - { - return AsyncHelper.RunSync(DisconnectAsync); - } - - public async Task DisconnectAsync() - { - try - { - using (await _lock.LockAsync()) - { - if (_groupNameBoxUid.ContainsKey(ConnectionToken) && _hubConnections.ContainsKey(_groupNameBoxUid[ConnectionToken]) && - _httpClient2.ContainsKey(_groupNameBoxUid[ConnectionToken]) && - _groupNameUid.ContainsKey(ConnectionToken)) - { - await - _httpClient2[_groupNameBoxUid[ConnectionToken]].PostAsync( - "dmon/group/" + _groupNameUid[ConnectionToken] + "/stop", - null); - _connectedDataGroupUid.RemoveWhere(p => p == _groupNameUid[ConnectionToken]); - _connected = false; - Console.WriteLine("SignalR Disconnect success"); - return true; - } - else - { - Console.WriteLine("SignalR Disconnect failed"); - return false; - } - } - } - catch - { - Console.WriteLine("SignalR Disconnect failed"); - return false; - } - } - - public override bool SendMsgWithoutReturn(byte[] message) - { - throw new NotImplementedException(); - } - - public override Task SendMsgWithoutReturnAsync(byte[] message) - { - throw new NotImplementedException(); - } - - public override byte[] SendMsg(byte[] message) - { - if (!_httpClient.ContainsKey(Msg)) - { - _connected = false; - return null; - } - - var formater = new AddressFormaterFBox(); - var translator = new AddressTranslatorFBox(); - - byte[] ans; - - lock (_connectionTokenState) - { - if (_connectionTokenState.ContainsKey(ConnectionToken) && _connectionTokenState[ConnectionToken] != 1) - { - _connected = false; - Console.WriteLine($"Return Value Rejected with connectionToken {ConnectionToken}"); - return null; - } - } - - lock (_machineData) - { - if (!_machineData.ContainsKey(ConnectionToken) || !_machineDataType.ContainsKey(ConnectionToken)) - { - _connected = false; - Console.WriteLine($"Return Value Rejected with connectionToken {ConnectionToken}"); - return null; - } - var machineDataValue = _machineData[ConnectionToken]; - var machineDataType = _machineDataType[ConnectionToken]; - if (machineDataValue != null && machineDataType.Count == 0) - { - _connected = false; - Console.WriteLine($"Return Value Rejected with connectionToken {ConnectionToken}"); - return null; - } - int pos = 0; - int area = BigEndianValueHelper.Instance.GetInt(message, ref pos); - int address = BigEndianValueHelper.Instance.GetInt(message, ref pos); - //short count = BigEndianValueHelper.Instance.GetShort(message, ref pos); - object[] dataAns = new object[1]; - try - { - dataAns[0] = - Convert.ChangeType( - machineDataValue[formater.FormatAddress(translator.GetAreaName(area), address)], - machineDataType[formater.FormatAddress(translator.GetAreaName(area), address)]); - } - catch (Exception) - { - dataAns[0] = - Convert.ChangeType( - 0, - machineDataType[formater.FormatAddress(translator.GetAreaName(area), address)]); - } - finally - { - ans = BigEndianValueHelper.Instance.ObjectArrayToByteArray(dataAns); - } - } - - return ans; - } - - public override Task SendMsgAsync(byte[] message) - { - return Task.Factory.StartNew(() => SendMsg(message)); - } - } -} diff --git a/Modbus.Net/ModBus.Net/FBox/SignalRProtocalLinker.cs b/Modbus.Net/ModBus.Net/FBox/SignalRProtocalLinker.cs deleted file mode 100644 index 888bb9b..0000000 --- a/Modbus.Net/ModBus.Net/FBox/SignalRProtocalLinker.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ModBus.Net.FBox -{ - public class SignalRProtocalLinker : ProtocalLinker - { - protected SignalRProtocalLinker(string machineId, string localSequence, SignalRSigninMsg msg) - { - _baseConnector = new SignalRConnector(machineId, localSequence, msg); - } - } -} diff --git a/Modbus.Net/ModBus.Net/ModBus.Net.csproj b/Modbus.Net/ModBus.Net/ModBus.Net.csproj index a48910a..ffb5bb6 100644 --- a/Modbus.Net/ModBus.Net/ModBus.Net.csproj +++ b/Modbus.Net/ModBus.Net/ModBus.Net.csproj @@ -47,6 +47,30 @@ ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll True + + False + ..\packages_local\Opc.Ua.Client.dll + + + False + ..\packages_local\Opc.Ua.Configuration.dll + + + False + ..\packages_local\Opc.Ua.Core.dll + + + False + ..\packages_local\OpcComRcw.dll + + + False + ..\packages_local\OpcNetApi.dll + + + False + ..\packages_local\OpcNetApi.Com.dll + @@ -97,14 +121,23 @@ + + + + + + + + + - - + + @@ -131,6 +164,12 @@ + + + {4f43b6f0-0c32-4c34-978e-9b8b5b0b6e80} + h-opc + + + \ No newline at end of file diff --git a/Modbus.Net/h-opc/packages.config b/Modbus.Net/h-opc/packages.config new file mode 100644 index 0000000..34147bc --- /dev/null +++ b/Modbus.Net/h-opc/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 12d244f..ff33d84 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ Caution: I really want to implement the COM communication system, but nowaday Us Caution2: In the current version, you can't get bit or set bit in this library. Please get a byte, change the bit value in the byte, and set to PLC. I will fix this bug in future. +Reference: "h-opc" is linked by [https://github.com/hylasoft-usa/h-opc](https://github.com/hylasoft-usa/h-opc) + Table of Content: * [Features](#features) * [Usage](#usage) @@ -17,6 +19,7 @@ Table of Content: * A open platform that you can easy to extend a industrial communication protocal. * Modbus Tcp protocal. * Siemens Tcp protocal (acturally it is the same as Profinet) +* OPC DA protocal. * All communications can be asyncronized. * A task manager that you can easily manage multiple connections. * .net framework 4.6 and Visual Studio 2015 support.