Пример #1
0
        // Static Methods
        private static bool TryFindPIPoint(PIConnection connection, DataSet metadata, string pointTag, out PIPoint point)
        {
            DataRow[] rows = metadata.Tables["ActiveMeasurements"].Select($"PointTag = '{pointTag}'");

            if (rows.Length <= 0)
            {
                point = null;
                return false;
            }

            return TryFindPIPoint(connection, pointTag, rows[0]["AlternateTag"].ToString(), out point);
        }
Пример #2
0
        public void Run(string server, string pointsQuery)
        {
            var connection = new PIConnection(server);


            _mainTask = Task.Run(() =>
            {
                WaitForServerToBeAvailable(connection);

                var pointsProvier = new PIPointsProvider(pointsQuery, connection.GetPiServer());

                _dataReader = new DataReader(pointsProvier, _queue, _cancellationTokenSource.Token);
                _dataWriter = new DataWriter(_queue, connection.GetPiServer());
                _dataWriter.Run();

                _dataReader.RunBackfill();
                _logger.Info("Starting the normal operations process");
                _dataReader.Run(General.Default.NormalDataCollectionFrequencySeconds);
            }, _cancellationTokenSource.Token);
        }
Пример #3
0
        private void WaitForServerToBeAvailable(PIConnection connection)
        {
            var isConnected = false;

            while (!isConnected)
            {
                isConnected = connection.Connect();

                if (!isConnected)
                {
                    _logger.InfoFormat("Could not connect to the server, waiting 5s to try to reconnect.");
                    Thread.Sleep(TimeSpan.FromSeconds(5));
                }

                if (_cancellationTokenSource.Token.IsCancellationRequested)
                {
                    _logger.InfoFormat("Cancellation requested, exiting WaitForServerToBeAvailable");
                    return;
                }
            }
        }
Пример #4
0
 /// <summary>
 /// Releases the unmanaged resources used by the <see cref="PIRTInputAdapter"/> object and optionally releases the managed resources.
 /// </summary>
 /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
 protected override void Dispose(bool disposing)
 {
     if (!m_disposed)
     {
         try
         {
             if (disposing)
             {
                 if ((object)m_connection != null)
                 {
                     m_connection.Disconnected -= m_connection_Disconnected;
                     m_connection.Dispose();
                     m_connection = null;
                 }
             }
         }
         finally
         {
             m_disposed = true;          // Prevent duplicate dispose.
             base.Dispose(disposing);    // Call base class Dispose().
         }
     }
 }
Пример #5
0
        private static void Main(string[] args)
        {
            TextWriter writer = Console.Out;

            try
            {
                var options = new CommandLineOptions();
                if (Parser.Default.ParseArguments(args, options))
                {
                    if (args.Length <= 1)
                    {
                        Console.Write(options.GetUsage());
                    }



                    if (options.Run != null && ValidateRunOptions(options.Run))
                    {
                        _logger.Info("Option Run starting, will run the data replay continuously as a command line application.");

                        var replayer = new Replayer();
                        replayer.RunFromCommandLine(options.Run[0], options.Run[1]);
                    }

                    if (options.deleteHistory != null && ValidateDeleteHistoryOptions(options.deleteHistory))
                    {
                        _logger.Info("Delete History Option Selected, will deleted the specified data.");

                        _logger.Info("This operation cannot be reversed, are you sure you want to delete the data you specified? Press Y to continue...");

                        var keyInfo = Console.ReadKey();
                        if (keyInfo.KeyChar != 'Y')
                        {
                            _logger.Info("Operation canceled");
                        }

                        // getting the tags
                        var piConnection = new PIConnection(options.deleteHistory[0]);

                        piConnection.Connect();

                        var pointsProvider = new PIPointsProvider(options.deleteHistory[3], piConnection.GetPiServer());

                        foreach (var piPoint in pointsProvider.Points)
                        {
                            var st = AFTime.Parse(options.deleteHistory[1]);
                            var et = AFTime.Parse(options.deleteHistory[2]);
                            _logger.InfoFormat("Deleting history for tag: {0} between {1:G} and {2:G}", piPoint.Name, st.LocalTime, et.LocalTime);

                            PIHelpers.DeleteValues(piPoint, st, et, options.ForceUpdateValuesMethod);
                        }
                    }
                }

                else
                {
                    options.GetUsage();
                }
            }



            catch (Exception ex)
            {
                Console.SetOut(writer);
                Console.WriteLine("Error: " + ex);
            }
        }
Пример #6
0
        private static void Main(string[] args)
        {
            PIConnection piConnection;
            var          _logger = LogManager.GetLogger(typeof(Program));


            try
            {
                var options = new CommandLineOptions();


                if (Parser.Default.ParseArguments(args, options))
                {
                    ValidateSettings(options);

                    var readerSettings = new DataReaderSettings();

                    if (options.Server.Length == 1)
                    {
                        piConnection = new PIConnection(options.Server[0]);
                    }
                    else
                    {
                        piConnection = new PIConnection(options.Server[0], options.Server[1]);
                    }

                    if (options.testTagSearch != null && options.testTagSearch.Length > 0)
                    {
                        _logger.Info("Search test started...");

                        piConnection.Connect();

                        var search = new TagsLoader(piConnection.GetPiServer());
                        foreach (var s in options.testTagSearch)
                        {
                            var tags = search.Search(s).ToList();
                            _logger.WarnFormat("Found {0} tags with query {1}", tags.Count, s);

                            if (options.testTagSearchPrintAllTags)
                            {
                                tags.ForEach(t => _logger.InfoFormat("Tag: {0}, PointClass: {1}", t.Name, t.PointClass));
                            }
                        }
                    }

                    if (options.TagQueries != null && options.TagQueries.Length > 0)
                    {
                        _logger.Info("Data reader starting...");


                        piConnection.Connect();

                        if (options.EventsPerDay > 0 && options.TagsCount > 0)
                        {
                            // var type = options.UseParallel? DataReaderSettings.ReadingType.Parallel: DataReaderSettings.ReadingType.Bulk;
                            var type = DataReaderSettings.ReadingType.Bulk;
                            readerSettings.AutoTune(type, options.EventsPerDay, options.TagsCount, options.EventsPerRead);
                        }


                        // starts the data writer


                        // settings data filters to filter out the data if option is specified
                        var filtersFactory = new FiltersFactory();
                        if (options.RemoveDuplicates)
                        {
                            filtersFactory.AddFilter(new DuplicateValuesFilter());
                        }


                        if (options.FilterDigitalStates)
                        {
                            filtersFactory.AddFilter(new SystemStatesFilter());
                        }


                        _logger.Info("Creating worker objects...");
                        var dataWriter = new DataWriter(options.OutfileName, options.EventsPerFile, options.WritersCount, filtersFactory);

                        var dataReader = new DataReaderBulk(readerSettings, dataWriter, options.EnableWrite);

                        //dataReader = options.UseParallel
                        //    ? (IDataReader) new DataReaderParallel(readerSettings, dataWriter)
                        //    : new DataReaderBulk(readerSettings, dataWriter);

                        var orchestrator = new Orchestrator(options.StartTime, options.EndTime,
                                                            readerSettings.TimeIntervalPerDataRequest, dataReader);

                        var tagsLoader = new TagsLoader(piConnection.GetPiServer(), options.TagQueries,
                                                        readerSettings.TagGroupSize, orchestrator);

                        var statistics = new Statistics();

                        // starts the orchestrator
                        _logger.Info("Starting workers...");
                        var tagsLoaderTask = tagsLoader.Run();
                        var writerTask     = dataWriter.Run();

                        // var processorTask = dataProcessor.Run(); -- not using this after determining this was not bringing much performance gain.
                        var orchestratorTask = orchestrator.Run();
                        var dataReaderTask   = dataReader.Run();
                        var statsTask        = statistics.Run();


                        // starts the data reader
                        Task.WaitAll(orchestratorTask, writerTask, dataReaderTask, tagsLoaderTask);

                        statistics.Stop();

                        Task.WaitAll(statsTask);

                        _logger.Info("All tasks completed successfully");
                    }


                    // DEBUG
                    //  Console.ReadKey();

                    // exit ok
                    Environment.Exit(0);
                }
                else
                {
                    // exit with error
                    Environment.Exit(1);
                }
            }


            catch (Exception ex)
            {
                _logger.Error(ex);
            }
        }
Пример #7
0
        /// <summary>
        /// Closes this <see cref="PIOutputAdapter"/> connections to the PI server.
        /// </summary>
        protected override void AttemptDisconnection()
        {
            foreach (ProcessQueue<AFValue> archiveQueue in m_archiveQueues)
                archiveQueue.Stop();

            m_mapRequestQueue.Stop();
            m_mapRequestQueue.Clear();

            m_mappedPIPoints.Clear();

            lock (m_pendingMappings)
            {
                m_pendingMappings.Clear();
            }

            if ((object)m_connection != null)
            {
                m_connection.Disconnected -= m_connection_Disconnected;
                m_connection.Dispose();
                m_connection = null;
            }
        }
Пример #8
0
        /// <summary>
        /// Connects to the configured PI server.
        /// </summary>
        protected override void AttemptConnection()
        {
            m_processedMappings = 0;
            m_processedMeasurements = 0;
            m_totalProcessingTime = 0;

            m_connection = new PIConnection
            {
                ServerName = this.ServerName,
                UserName = this.UserName,
                Password = this.Password,
                ConnectTimeout = this.ConnectTimeout
            };

            m_connection.Disconnected += m_connection_Disconnected;
            m_connection.Open();

            m_mappedPIPoints.Clear();

            lock (m_pendingMappings)
            {
                m_pendingMappings.Clear();
            }

            m_mapRequestQueue.Clear();
            m_mapRequestQueue.Start();

            foreach (ProcessQueue<AFValue> archiveQueue in m_archiveQueues)
                archiveQueue.Start();

            // Kick off meta-data refresh
            RefreshMetadata();
        }
        /// <summary>
        /// Attempts to connect to this <see cref="PIAdapters.PIPBInputAdapter"/>.
        /// </summary>
        protected override void AttemptConnection()
        {
            // This adapter is only engaged for history, so we don't process any data unless a temporal constraint is defined
            if (this.TemporalConstraintIsDefined())
            {
                // Turn off read timer if it's active
                m_readTimer.Enabled = false;

                m_connection = new PIConnection
                {
                    ServerName = m_serverName,
                    UserName = m_userName,
                    Password = m_password,
                    ConnectTimeout = m_connectTimeout
                };

                m_connection.Open();

                // Start the data reader on its own thread so connection attempt can complete in a timely fashion...
                ThreadPool.QueueUserWorkItem(StartDataReader);
            }
        }
Пример #10
0
        /// <summary>
        /// Gets a connection from the pool or creates a new one if all current connections are being used at peak access.
        /// </summary>
        /// <param name="serverName">Name of the PI server for the adapter's PI connection.</param>
        /// <param name="userName">Name of the PI user ID for the adapter's PI connection.</param>
        /// <param name="password">Password used for the adapter's PI connection.</param>
        /// <param name="connectTimeout">Timeout interval (in milliseconds) for the adapter's connection.</param>
        /// <returns>A <see cref="PIConnection"/> from the pool.</returns>
        /// <exception cref="InvalidOperationException">Failed to get a pooled PI connection.</exception>
        public PIConnection GetPooledConnection(string serverName, string userName = null, string password = null, int connectTimeout = PIConnection.DefaultConnectTimeout)
        {
            PIConnection connection = null;

            // We dynamically allocate pooled PI server connections each having a maximum accessibility count.
            // PI's threading model can handle many connections each archiving a small volume of points, but
            // falls behind under load when archiving a large volume of points from a single connection.
            try
            {
                lock (m_connectionPool)
                {
                    while ((object)connection == null)
                    {
                        // Get next connection from the pool with lowest accessibility count
                        if (m_connectionPool.Count > 0)
                        {
                            PIConnection[] availableConnections = m_connectionPool.Where(c => c.AccessCount < m_accessCountPerConnection).ToArray();

                            if (availableConnections.Length > 0)
                                connection = availableConnections.Aggregate((currentMin, nextItem) => (object)nextItem != null && currentMin.AccessCount < nextItem.AccessCount ? currentMin : nextItem);
                        }

                        if ((object)connection == null)
                        {
                            // Add pooled connections in groups for better distribution
                            for (int i = 0; i < m_minimumPoolSize; i++)
                            {
                                // Create a new connection
                                connection = new PIConnection
                                {
                                    ServerName = serverName,
                                    UserName = userName,
                                    Password = password,
                                    ConnectTimeout = connectTimeout
                                };

                                // Since PI doesn't detect disconnection until an operation is attempted,
                                // we must monitor for disconnections from the pooled connections as well
                                connection.Disconnected += connection_Disconnected;
                                connection.Open();

                                // Add the new connection to the server pool
                                m_connectionPool.Add(connection);
                            }
                        }
                    }

                    // Increment current connection access count
                    connection.AccessCount++;
                }
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException(string.Format("Failed to get a pooled PI connection: {0}", ex.Message), ex);
            }

            return connection;
        }
Пример #11
0
 private static bool TryFindPIPoint(PIConnection connection, string pointTag, string alternateTag, out PIPoint point)
 {
     return PIPoint.TryFindPIPoint(connection.Server, string.IsNullOrWhiteSpace(alternateTag) ? pointTag : alternateTag, out point);
 }
Пример #12
0
        // TODO: Update code to properly handle piped-events in AF-SDK
        //private void PipeOnOnNewValue()
        //{
        //    List<IMeasurement> measurements = new List<IMeasurement>();

        //    m_connection.Execute(server =>
        //    {
        //        PIEventObject eventobject;
        //        PointValue pointvalue;

        //        for (int i = 0; i < m_pipe.Count; i++)
        //        {
        //            eventobject = m_pipe.Take();

        //            // we will publish measurements for every action except deleted (possible dupes on updates)
        //            if (eventobject.Action != EventActionConstants.eaDelete)
        //            {
        //                try
        //                {
        //                    pointvalue = (PointValue)eventobject.EventData;

        //                    double value = Convert.ToDouble(pointvalue.PIValue.Value);
        //                    MeasurementKey key = m_tagKeyMap[pointvalue.PIPoint.Name];

        //                    Measurement measurement = new Measurement();
        //                    measurement.Key = key;
        //                    measurement.Timestamp = pointvalue.PIValue.TimeStamp.LocalDate.ToUniversalTime();
        //                    measurement.Value = value;
        //                    measurement.StateFlags = MeasurementStateFlags.Normal;

        //                    if (measurement.Timestamp > m_lastReceivedTimestamp.Ticks)
        //                        m_lastReceivedTimestamp = measurement.Timestamp;

        //                    measurements.Add(measurement);
        //                }
        //                catch
        //                {
        //                    /* squelch any errors on digital state data that can't be converted to a double */
        //                }
        //            }
        //        }
        //    });

        //    if (measurements.Any())
        //    {
        //        OnNewMeasurements(measurements);
        //        m_processedMeasurements += measurements.Count;
        //    }
        //}

        /// <summary>
        /// Disposes members for garbage collection
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            if (m_tagKeyMap != null)
                m_tagKeyMap.Clear();
            m_tagKeyMap = null;

            if ((object)m_connection != null)
                m_connection.Dispose();

            m_connection = null;
            m_points = null;
            //m_pipe = null;

            m_measurements.Clear();
            m_measurements = null;

            if (m_dataThread != null)
            {
                m_dataThread.Abort();
                m_dataThread = null;
            }

            if (m_publishTimer != null)
            {
                m_publishTimer.Stop();
                m_publishTimer.Elapsed -= m_publishTimer_Tick;
                m_publishTimer.Dispose();
                m_publishTimer = null;
            }
        }
Пример #13
0
 /// <summary>
 /// Disconnects from the configured PI server if a connection is open
 /// </summary>
 protected override void AttemptDisconnection()
 {
     if ((object)m_connection != null)
     {
         m_connection.Dispose();
         m_connection = null;
     }
 }
Пример #14
0
        /// <summary>
        /// Connects to the configured PI server.
        /// </summary>
        protected override void AttemptConnection()
        {
            m_processedMeasurements = 0;

            m_connection = new PIConnection
            {
                ServerName = m_serverName,
                UserName = m_userName,
                Password = m_password,
                ConnectTimeout = m_connectTimeout
            };

            m_connection.Open();
        }
Пример #15
0
        /// <summary>
        /// Attempts to disconnect from this <see cref="PIAdapters.PIPBInputAdapter"/>.
        /// </summary>
        protected override void AttemptDisconnection()
        {
            if ((object)m_readTimer != null)
            {
                m_readTimer.Enabled = false;

                lock (m_readTimer)
                {
                    m_dataReader = null;
                }
            }

            if ((object)m_connection != null)
            {
                m_connection.Dispose();
                m_connection = null;
            }
        }
Пример #16
0
        /// <summary>
        /// Connects to the configured PI server.
        /// </summary>
        protected override void AttemptConnection()
        {
            m_connection = new PIConnection
            {
                ServerName = this.ServerName,
                UserName = this.UserName,
                Password = this.Password,
                ConnectTimeout = this.ConnectTimeout
            };

            m_connection.Disconnected += m_connection_Disconnected;
            m_connection.Open();

            m_dataPipe = new PIDataPipe(AFDataPipeType.Snapshot);
            //m_dataPipe.Subscribe(m_dataUpdateObserver);

            if (AutoStart && (object)OutputMeasurements != null && OutputMeasurements.Any())
                SubscribeToPointUpdates(this.OutputMeasurementKeys());
        }
Пример #17
0
        /// <summary>
        /// Disconnects from the configured PI server if a connection is open
        /// </summary>
        protected override void AttemptDisconnection()
        {
            m_eventTimer.Enabled = false;

            if ((object)m_dataPoints != null)
            {
                m_dataPoints.Clear();
                m_dataPoints = null;
            }

            if ((object)m_dataPipe != null)
            {
                m_dataPipe.Dispose();
                m_dataPipe = null;
            }

            if ((object)m_connection != null)
            {
                m_connection.Dispose();
                m_connection = null;
            }
        }
Пример #18
0
        /// <summary>
        /// Releases the unmanaged resources used by the <see cref="PIOutputAdapter"/> object and optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected override void Dispose(bool disposing)
        {
            if (!m_disposed)
            {
                try
                {
                    if (disposing)
                    {
                        if ((object)m_mapRequestQueue != null)
                            m_mapRequestQueue.Dispose();

                        if ((object)m_archiveQueues != null)
                        {
                            foreach (ProcessQueue<AFValue> archiveQueue in m_archiveQueues)
                                archiveQueue.Dispose();
                        }

                        if ((object)m_connection != null)
                        {
                            m_connection.Disconnected -= m_connection_Disconnected;
                            m_connection.Dispose();
                            m_connection = null;
                        }

                        if ((object)m_mappedPIPoints != null)
                            m_mappedPIPoints.Clear();
                    }
                }
                finally
                {
                    m_disposed = true;          // Prevent duplicate dispose.
                    base.Dispose(disposing);    // Call base class Dispose().
                }
            }
        }
Пример #19
0
        /// <summary>
        /// Returns <see cref="PIConnection"/> to the pool.
        /// </summary>
        /// <param name="connection"><see cref="PIConnection"/> to return to the pool.</param>
        /// <exception cref="InvalidOperationException">Provided PIConnection does not belong to this connection pool.</exception>
        public void ReturnPooledConnection(PIConnection connection)
        {
            if ((object)connection == null)
                return;

            lock (m_connectionPool)
            {
                if (!m_connectionPool.Contains(connection))
                    throw new InvalidOperationException("Provided PIConnection does not belong to this connection pool");

                if (connection.AccessCount > 0)
                    connection.AccessCount--;

                if (connection.AccessCount < 1)
                {
                    if (m_connectionPool.Count > m_minimumPoolSize && m_connectionPool.Remove(connection))
                    {
                        connection.Disconnected -= connection_Disconnected;
                        connection.Dispose();
                    }
                }
            }
        }
Пример #20
0
        private static void Main(string[] args)
        {
            PIConnection piConnection;
            var _logger = LogManager.GetLogger(typeof (Program));

            try
            {
                var options = new CommandLineOptions();

                if (Parser.Default.ParseArguments(args, options))
                {

                    ValidateSettings(options);

                    var readerSettings = new DataReaderSettings();

                    if(options.Server.Length==1)
                        piConnection = new PIConnection(options.Server[0]);
                    else
                        piConnection = new PIConnection(options.Server[0], options.Server[1]);

                    if (options.testTagSearch != null && options.testTagSearch.Length > 0)
                    {
                        _logger.Info("Search test started...");

                        piConnection.Connect();

                        var search = new TagsLoader(piConnection.GetPiServer());
                        foreach (var s in options.testTagSearch)
                        {
                            var tags = search.Search(s).ToList();
                            _logger.WarnFormat("Found {0} tags with query {1}", tags.Count, s);

                            if (options.testTagSearchPrintAllTags)
                            {
                                tags.ForEach(t => _logger.InfoFormat("Tag: {0}, PointClass: {1}", t.Name, t.PointClass));
                            }
                        }
                    }

                    if (options.TagQueries != null && options.TagQueries.Length > 0)
                    {
                        _logger.Info("Data reader starting...");

                        piConnection.Connect();

                        if (options.EventsPerDay > 0 && options.TagsCount > 0)
                        {
                            // var type = options.UseParallel? DataReaderSettings.ReadingType.Parallel: DataReaderSettings.ReadingType.Bulk;
                            var type = DataReaderSettings.ReadingType.Bulk;
                            readerSettings.AutoTune(type, options.EventsPerDay, options.TagsCount, options.EventsPerRead);
                        }

                        // starts the data writer

                        // defines rejected states to filter out
                        var rejectedStates = new[]
                                                {
                            "pt created",
                            "snapfix",
                            "shutdown",
                            "no data",
                            "bad",
                            "No Alarm",
                            "High Alarm",
                            "Low Alarm",
                            "Hi Alarm/Ack",
                            "Lo Alarm/Ack",
                            "NoAlrm/UnAck",
                            "Bad Quality",
                            "Rate Alarm",
                            "Rate Alm/Ack",
                            "Dig Alarm",
                            "Dig Alm/Ack",
                            "?204",
                            "?205",
                            "?206",
                            "?207",
                            "?208",
                            "?209",
                            "AccessDenied",
                            "No Sample",
                            "No Result",
                            "Unit Down",
                            "Sample Bad",
                            "Equip Fail",
                            "No Lab Data",
                            "Trace",
                            "GreaterMM",
                            "Bad Lab Data",
                            "Good-Off",
                            "Good-On",
                            "Alarm-Off",
                            "Alarm-On",
                            "Bad_Quality",
                            "BadQ-On",
                            "BadQ-Alrm-Of",
                            "BadQ-Alrm-On",
                            "?228",
                            "?229",
                            "Manual",
                            "Auto",
                            "Casc/Ratio",
                            "DCS failed",
                            "Manual Lock",
                            "CO Bypassed",
                            "?236",
                            "Bad Output",
                            "Scan Off",
                            "Scan On",
                            "Configure",
                            "Failed",
                            "Error",
                            "Execute",
                            "Filtered",
                            "Calc Off",
                            "I/O Timeout",
                            "Set to Bad",
                            "Calc Failed",
                            "Calc Overflw",
                            "Under Range",
                            "Over Range",
                            "Bad Input",
                            "Bad Total",
                            "No_Alarm",
                            "Over UCL",
                            "Under LCL",
                            "Over WL",
                            "Under WL",
                            "Over 1 Sigma",
                            "Under 1Sigma",
                            "Over Center",
                            "Under Center",
                            "Stratified",
                            "Mixture",
                            "Trend Up",
                            "Trend Down",
                            "No Alarm#",
                            "Over UCL#",
                            "Under LCL#",
                            "Over WL#",
                            "Under WL#",
                            "Over 1Sigma#",
                            "Under 1Sigm#",
                            "Over Center#",
                            "Under Centr#",
                            "Stratified#",
                            "Mixture#",
                            "Trend Up#",
                            "Trend Down#",
                            "?283",
                            "?284",
                            "?285",
                            "?286",
                            "?287",
                            "?288",
                            "ActiveBatch",
                            "Bad Data",
                            "Calc Crash",
                            "Calc Timeout",
                            "Bad Narg",
                            "Inp OutRange",
                            "Not Converge",
                            "DST Forward",
                            "DST Back",
                            "Substituted",
                            "Invalid Data",
                            "Scan Timeout",
                            "No_Sample",
                            "Arc Off-line",
                            "ISU Saw No Data",
                            "-err",
                            "Good",
                            "_SUBStituted",
                            "Doubtful",
                            "Wrong Type",
                            "Overflow_st",
                            "Intf Shut",
                            "Out of Serv",
                            "Comm Fail",
                            "Not Connect",
                            "Coercion Failed",
                            "Invalid Float",
                            "Future Data Unsupported"
                        };

                        var filtersFactory=new FiltersFactory();
                        filtersFactory.SetDigitalStatesFilters(rejectedStates);
                        filtersFactory.SetFilters(FiltersFactory.FiltersTypesEnum.DigitalStatesFilter,FiltersFactory.FiltersTypesEnum.DuplicateValuesFilter);

                        _logger.Info("Creating worker objects...");
                        var dataWriter = new DataWriter(options.OutfileName, options.EventsPerFile, options.WritersCount, filtersFactory);

                       var dataReader = new DataReaderBulk(readerSettings, dataWriter, options.EnableWrite);

                        //dataReader = options.UseParallel
                        //    ? (IDataReader) new DataReaderParallel(readerSettings, dataWriter)
                        //    : new DataReaderBulk(readerSettings, dataWriter);

                        var orchestrator = new Orchestrator(options.StartTime, options.EndTime,
                            readerSettings.TimeIntervalPerDataRequest, dataReader);

                        var tagsLoader = new TagsLoader(piConnection.GetPiServer(), options.TagQueries,
                            readerSettings.TagGroupSize, orchestrator);

                        var statistics = new Statistics();

                        // starts the orchestrator
                        _logger.Info("Starting workers...");
                        var tagsLoaderTask = tagsLoader.Run();
                        var writerTask = dataWriter.Run();
                        // var processorTask = dataProcessor.Run();
                        var orchestratorTask = orchestrator.Run();
                        var dataReaderTask = dataReader.Run();
                        var statsTask = statistics.Run();

                        // starts the data reader
                        Task.WaitAll(orchestratorTask, writerTask, dataReaderTask, tagsLoaderTask);

                        statistics.Stop();

                        Task.WaitAll(statsTask);

                        _logger.Info("All tasks completed successfully");
                    }

                    // DEBUG
                    //  Console.ReadKey();

                    // exit ok
                    Environment.Exit(0);
                }
                else
                {
                    // exit with error
                    Environment.Exit(1);
                }
            }

            catch (Exception ex)
            {

                _logger.Error(ex);
            }
        }