Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        private async Task <bool> ExecuteReadWriteAsync(ICollection <IPlcItem> plcItems, PlcItemUsageType usageType, CancellationToken cancellationToken)
        {
            // Allow only items that have a length greater than zero. This is mostly needed for dynamic items.
            plcItems = plcItems.Where(item => item.Value.Length > 0).ToList();
            if (!plcItems.Any())
            {
                return(true);
            }

            var cancellationTokenSource = this.BuildLinkedTokenSource(cancellationToken);

            cancellationToken = cancellationTokenSource.Token;
            try
            {
                while (true)
                {
                    try
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        lock (_connectionStateChangeLock)
                        {
                            // If no active connection is available, then throw an exception.

                            /*!
                             * This means, that reading/writing items while the plc is not connected, will result in the calling function to indefinitely wait,
                             * because no reconnect will be made when the connection was deliberately not established.
                             */
                            if (this.ConnectionState == PlcConnectionState.Disconnected)
                            {
                                var itemDescriptions = Plc.GetPlcItemDescription(plcItems);
                                throw new NotConnectedPlcException($"Cannot {usageType.ToString().ToLower()} the plc items ({itemDescriptions}) because {this:LOG} is not connected. All items will be put on hold.");
                            }
                        }

                        await Task.Run(() => this.PerformReadWriteAsync(plcItems, usageType, cancellationToken), cancellationToken);

                        break;
                    }
                    // This handles task cancellation.
                    catch (OperationCanceledException)
                    {
                        if (_disposeToken.IsCancellationRequested)
                        {
                            if (usageType == PlcItemUsageType.Read)
                            {
                                throw new DisposedReadPlcException(plcItems);
                            }
                            else
                            {
                                throw new DisposedWritePlcException(plcItems);
                            }
                        }
                        return(false);
                    }
                    // Handle not connected exceptions by trying to re-connect and halting the items until a connection was established.
                    catch (NotConnectedPlcException ex)
                    {
                        this.Logger.Error(ex.Message);

                        // Create a cancellation token source for this handle callback that is linked to the external one.
                        var sleepCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                        _waitQueue.Enqueue(sleepCancellationTokenSource);
                        var sleepCancellationToken = sleepCancellationTokenSource.Token;

                        // Check if a reconnection could be useful.
                        lock (_connectionStateChangeLock)
                        {
                            // Don't reconnect if the connection is disconnected to begin with.
                            if (this.ConnectionState != PlcConnectionState.Disconnected)
                            {
                                this.OnInterrupted(executeReconnect: true);
                            }
                        }

                        // Indefinitely wait until the task gets canceled.
                        try
                        {
                            await Task.Delay(Timeout.Infinite, sleepCancellationToken);
                        }
                        catch (OperationCanceledException)
                        {
                            // Throw special dispose exception if the dispose token was canceled.
                            if (_disposeToken.IsCancellationRequested)
                            {
                                if (usageType == PlcItemUsageType.Read)
                                {
                                    throw new DisposedReadPlcException(plcItems);
                                }
                                else
                                {
                                    throw new DisposedWritePlcException(plcItems);
                                }
                            }
                            // Stop execution if the original (external) token was canceled.
                            else if (cancellationToken.IsCancellationRequested)
                            {
                                return(false);
                            }
                            // In all other cases just keep going.
                            else
                            {
                                /* ignore */
                            }
                        }

                        this.Logger.Info($"The previously suspended plc items of {this:LOG} will now be handled again.");
                    }
                    // Throw on read or write exceptions.
                    catch (ReadOrWritePlcException)
                    {
                        throw;
                    }
                }

                return(true);
            }
            finally
            {
                cancellationTokenSource.Dispose();
                cancellationTokenSource = null;
#if DEBUG
                this.LinkedTokenWasCanceled();
#endif
            }
        }