private static (ICollection <IPlcItem> ValidItems, ICollection <(IPlcItem FailedItem, string ErrorMessage)>) VerifyPlcItemResults(ICollection <ReadPlcItemWrapper> mapping, ICollection <AGL4.DATA_RW40> allAgLinkItems, bool transferData) { var validItems = new List <IPlcItem>(mapping.Count); var failedItems = new List <(IPlcItem FailedItem, string ErrorMessage)>(0); //! Assume that no errors occur to save memory. // Iterate each plc item and get the data for all AGLink items that where needed to handle it. foreach (var(plcItem, start, amount) in mapping) { // Get all ag link items of this plc item. var agLinkItems = allAgLinkItems.Skip(start).Take(amount).ToArray(); // Check if any of those have failed. var itemResult = agLinkItems .Select(agLinkItem => agLinkItem.Result) .FirstOrDefault(resultCode => resultCode != 0) ; var result = AgLinkPlc.ConvertToAgLinkResult(itemResult); if (result != AgLinkResult.Success) { failedItems.Add((plcItem, AgLinkPlc.ErrorMapping.GetErrorMessageForCode(itemResult))); } else { validItems.Add(plcItem); if (transferData) { var data = agLinkItems.SelectMany(agLinkItem => agLinkItem.B).ToArray(); AgLinkPlc.TransferValue(plcItem, data); } } } return(validItems, failedItems); }
private static (ICollection <ReadPlcItemWrapper> Mapping, AGL4.DATA_RW40[] AllAgLinkItems) CreateMappingAndAgLinkItems(ICollection <IPlcItem> plcItems, PlcItemUsageType usageType) { var mapping = plcItems .Select(plcItem => new ReadPlcItemWrapper(plcItem)) .ToArray() ; // Create all needed AGLink items. //! Directly storing the AGLink items in the ReadPlcItemWrapper instance won't work, as AGL4.DATA_RW40 is a struct that would consequently be copied on assignment. //! Therefore the ReadPlcItemWrapper only contains the start position and the amount of items in the returned AGLink items array. var previousAmount = 0; var allAgLinkItems = mapping .SelectMany ( readPlcItemWrapper => { var agLinkItems = AgLinkPlc.CreateAgLinkItems(readPlcItemWrapper.PlcItem, usageType).ToArray(); readPlcItemWrapper.Start = (previousAmount += agLinkItems.Length) - 1; readPlcItemWrapper.Amount = agLinkItems.Length; return(agLinkItems); } ) .ToArray() ; return(mapping, allAgLinkItems); }
private async Task PerformWriteAsync(ICollection <IPlcItem> plcItems, CancellationToken cancellationToken) { const PlcItemUsageType usageType = PlcItemUsageType.Write; var underlyingPlc = AgLinkPlc.VerifyConnectivity(this, plcItems, usageType); // Create the mapping. var(mapping, allAgLinkItems) = AgLinkPlc.CreateMappingAndAgLinkItems(plcItems, usageType); // Write to the plc. var writeResult = await Task.Run(() => underlyingPlc.WriteMixEx(allAgLinkItems, allAgLinkItems.Length), cancellationToken); // Verify the total result. //! Ignore the total result and inspect the result of each item individually. var result = AgLinkPlc.ConvertToAgLinkResult(writeResult); //if (result != AgLinkResult.Success) //{ // var errorMessage = AgLinkPlc.ErrorMapping.GetErrorMessageForCode(writeResult); // var items = plcItems.Select(item => (item, "General writing error.")).ToArray(); // throw new WritePlcException(new IPlcItem[0], items, $"Could not write any items to {this:LOG}. AGLink returned error code '{result}' ({errorMessage})."); //} // Verify the result of all items. var(validItems, failedItems) = AgLinkPlc.VerifyPlcItemResults(mapping, allAgLinkItems, false); if (failedItems.Any()) { throw new WritePlcException(validItems, failedItems, $"Some of the items couldn't be written. See the '{nameof(ReadOrWritePlcException.FailedItems)}' property for further information."); } }
private async Task PerformReadAsync(ICollection <IPlcItem> plcItems, CancellationToken cancellationToken) { const PlcItemUsageType usageType = PlcItemUsageType.Read; var underlyingPlc = AgLinkPlc.VerifyConnectivity(this, plcItems, usageType); // Create the mapping. var(mapping, allAgLinkItems) = AgLinkPlc.CreateMappingAndAgLinkItems(plcItems, usageType); // Read from the plc. //! The return value may be zero even if some or all of the items failed. To get the real result the 'Result' property of the AGLink item (AGL4.DATA_RW40.Result) must be checked. var readResult = await Task.Run(() => underlyingPlc.ReadMixEx(allAgLinkItems, allAgLinkItems.Length), cancellationToken); // Verify the total result. //! Ignore the total result and inspect the result of each item individually. var result = AgLinkPlc.ConvertToAgLinkResult(readResult); //if (result != AgLinkResult.Success) //{ // var errorMessage = AgLinkPlc.ErrorMapping.GetErrorMessageForCode(readResult); // var items = plcItems.Select(item => (item, "General reading error.")).ToArray(); // throw new ReadPlcException(new IPlcItem[0], items, $"Could not read any items from {this:LOG}. AGLink returned error code '{result}' ({errorMessage})."); //} // Verify the result of all items and transfer the value. var(validItems, failedItems) = AgLinkPlc.VerifyPlcItemResults(mapping, allAgLinkItems, true); if (failedItems.Any()) { throw new ReadPlcException(validItems, failedItems, $"Some of the items couldn't be read. See the '{nameof(ReadOrWritePlcException.FailedItems)}' property for further information."); } }
private static IAGLink4 VerifyConnectivity(AgLinkPlc plc, ICollection <IPlcItem> plcItems, PlcItemUsageType usageType) { var underlyingPlc = plc.UnderlyingPlc; if (underlyingPlc is null) { var itemDescriptions = Plc.GetPlcItemDescription(plcItems); throw new NotConnectedPlcException($"Cannot {usageType.ToString().ToLower()} the plc items ({itemDescriptions}) because {plc:LOG} is not connected. All items will be put on hold."); } return(underlyingPlc); }