示例#1
0
        /// <summary>
        /// Цикл работы сервера (метод вызывается в отдельном потоке)
        /// </summary>
        private void Execute()
        {
            try
            {
                // запись информации о работе приложения
                workState = WorkStateNames.Normal;
                WriteInfo();

                // выполнение действий модулей
                RaiseOnServerStart();

                // инициализация адаптеров таблиц текущего среза и событий
                curSrezAdapter = new SrezAdapter();
                curSrezCopyAdapter = new SrezAdapter();
                eventAdapter = new EventAdapter();
                eventCopyAdapter = new EventAdapter();
                curSrezAdapter.FileName = ServerUtils.BuildCurFileName(Settings.ArcDir);
                curSrezCopyAdapter.FileName = ServerUtils.BuildCurFileName(Settings.ArcCopyDir);
                eventAdapter.Directory = Settings.ArcDir + "Events" + Path.DirectorySeparatorChar;
                eventCopyAdapter.Directory = Settings.ArcCopyDir + "Events" + Path.DirectorySeparatorChar;

                // инициализация кэша таблиц минутных и часовых срезов
                minSrezTableCache = new SortedList<DateTime, SrezTableCache>();
                hrSrezTableCache = new SortedList<DateTime, SrezTableCache>();

                // инициализация описания создаваемых срезов
                int cnlCnt = inCnls.Count;
                srezDescr = new SrezTable.SrezDescr(cnlCnt);
                for (int i = 0; i < cnlCnt; i++)
                    srezDescr.CnlNums[i] = inCnls.Values[i].CnlNum;
                srezDescr.CalcCS();

                // загрузка исходного текущего среза из файла
                SrezTableLight.Srez curSrezSrc = null;
                SrezTableLight tblCurSrezScr = new SrezTableLight();

                try
                {
                    if (File.Exists(curSrezAdapter.FileName))
                    {
                        curSrezAdapter.Fill(tblCurSrezScr);
                        if (tblCurSrezScr.SrezList.Count > 0)
                            curSrezSrc = tblCurSrezScr.SrezList.Values[0];
                    }

                    if (curSrezSrc == null)
                        AppLog.WriteAction(Localization.UseRussian ? "Текущий срез не загружен" :
                            "Current data are not loaded", Log.ActTypes.Action);
                    else
                        AppLog.WriteAction(Localization.UseRussian ? "Текущий срез загружен" :
                            "Current data are loaded", Log.ActTypes.Action);
                }
                catch (Exception ex)
                {
                    AppLog.WriteAction((Localization.UseRussian ? "Ошибка при загрузке текущего среза: " :
                        "Error loading current data: ") + ex.Message, Log.ActTypes.Exception);
                }

                // инициализация текущего среза, предназначенного для формироваться данных сервера
                curSrez = new SrezTable.Srez(DateTime.MinValue, srezDescr, curSrezSrc);

                // инициализация данных для усреднения и времени активности каналов
                minAvgData = new AvgData[cnlCnt];
                hrAvgData = new AvgData[cnlCnt];
                activeDTs = new DateTime[cnlCnt];
                DateTime nowDT = DateTime.Now;

                for (int i = 0; i < cnlCnt; i++)
                {
                    minAvgData[i] = new AvgData() { Sum = 0.0, Cnt = 0 };
                    hrAvgData[i] = new AvgData() { Sum = 0.0, Cnt = 0 };
                    activeDTs[i] = nowDT;
                }

                // цикл работы сервера
                nowDT = DateTime.MaxValue;
                DateTime today = nowDT.Date;
                DateTime prevDT;
                DateTime writeCurSrezDT = DateTime.MinValue;
                DateTime writeMinSrezDT = DateTime.MinValue;
                DateTime writeHrSrezDT = DateTime.MinValue;
                DateTime calcMinDT = DateTime.MinValue;
                DateTime calcHrDT = DateTime.MinValue;
                DateTime clearCacheDT = nowDT;

                bool writeCur = Settings.WriteCur || Settings.WriteCurCopy;
                bool writeCurOnMod = Settings.WriteCurPer <= 0;
                bool writeMin = (Settings.WriteMin || Settings.WriteMinCopy) && Settings.WriteMinPer > 0;
                bool writeHr = (Settings.WriteHr || Settings.WriteHrCopy) && Settings.WriteHrPer > 0;

                curSrezMod = false;
                serverIsReady = true;

                while (!terminated)
                {
                    prevDT = nowDT;
                    nowDT = DateTime.Now;
                    today = nowDT.Date;

                    // расчёт времени записи срезов и вычисления значений дорасчётных каналов
                    // при переводе времени назад или при первом проходе цикла
                    if (prevDT > nowDT)
                    {
                        writeCurSrezDT = nowDT;
                        writeMinSrezDT = CalcNextTime(nowDT, Settings.WriteMinPer);
                        writeHrSrezDT = CalcNextTime(nowDT, Settings.WriteHrPer);
                        calcMinDT = drmCnls.Count > 0 ? CalcNextTime(nowDT, 60) : DateTime.MaxValue;
                        calcHrDT = drhCnls.Count > 0 ? CalcNextTime(nowDT, 3600) : DateTime.MaxValue;
                    }

                    // удаление устаревших файлов срезов и событий при изменении даты или при первом проходе цикла
                    if (prevDT.Date != today)
                    {
                        ClearArchive(Settings.ArcDir + "Min", "m*.dat", today.AddDays(-Settings.StoreMinPer));
                        ClearArchive(Settings.ArcDir + "Hour", "h*.dat", today.AddDays(-Settings.StoreHrPer));
                        ClearArchive(Settings.ArcDir + "Events", "e*.dat", today.AddDays(-Settings.StoreEvPer));
                        ClearArchive(Settings.ArcCopyDir + "Min", "m*.dat", today.AddDays(-Settings.StoreMinPer));
                        ClearArchive(Settings.ArcCopyDir + "Hour", "h*.dat", today.AddDays(-Settings.StoreHrPer));
                        ClearArchive(Settings.ArcCopyDir + "Events", "e*.dat", today.AddDays(-Settings.StoreEvPer));
                    }

                    lock (curSrez)
                    {
                        // установка недостоверности неактивных каналов
                        SetUnreliable();

                        // вычисление дорасчётных каналов и выполнение действий модулей
                        CalcDRCnls(drCnls, curSrez, true);
                        RaiseOnCurDataCalculated(drCnlNums, curSrez);

                        // вычисление минутных каналов и выполнение действий модулей
                        if (calcMinDT <= nowDT)
                        {
                            CalcDRCnls(drmCnls, curSrez, true);
                            RaiseOnCurDataCalculated(drmCnlNums, curSrez);
                            calcMinDT = CalcNextTime(nowDT, 60);
                            curSrezMod = true;
                        }

                        // вычисление часовых каналов и выполнение действий модулей
                        if (calcHrDT <= nowDT)
                        {
                            CalcDRCnls(drhCnls, curSrez, true);
                            RaiseOnCurDataCalculated(drhCnlNums, curSrez);
                            calcHrDT = CalcNextTime(nowDT, 3600);
                            curSrezMod = true;
                        }

                        // запись текущего среза
                        if ((writeCurSrezDT <= nowDT || writeCurOnMod && curSrezMod) && writeCur)
                        {
                            if (writeCurOnMod)
                            {
                                WriteSrez(SrezTypes.Cur, nowDT);
                                curSrezMod = false;
                                writeCurSrezDT = DateTime.MaxValue;
                            }
                            else
                            {
                                WriteSrez(SrezTypes.Cur, writeCurSrezDT);
                                writeCurSrezDT = CalcNextTime(nowDT, Settings.WriteCurPer);
                            }
                        }

                        // запись минутного среза
                        if (writeMinSrezDT <= nowDT && writeMin)
                        {
                            WriteSrez(SrezTypes.Min, writeMinSrezDT);
                            writeMinSrezDT = CalcNextTime(nowDT, Settings.WriteMinPer);
                        }

                        // запись часового среза
                        if (writeHrSrezDT <= nowDT && writeHr)
                        {
                            WriteSrez(SrezTypes.Hour, writeHrSrezDT);
                            writeHrSrezDT = CalcNextTime(nowDT, Settings.WriteHrPer);
                        }
                    }

                    // очистка устаревших данных кэша
                    if (nowDT - clearCacheDT > CacheClearSpan || nowDT < clearCacheDT /*время переведено назад*/)
                    {
                        clearCacheDT = nowDT;
                        ClearSrezTableCache(minSrezTableCache, MinCacheStorePer, MinCacheCapacity);
                        ClearSrezTableCache(hrSrezTableCache, HourCacheStorePer, HourCacheCapacity);
                    }

                    // запись информации о работе приложения
                    WriteInfo();

                    // задержка для экономиии ресурсов процессора
                    Thread.Sleep(100);
                }
            }
            finally
            {
                // выполнение действий модулей
                RaiseOnServerStop();

                // запись информации о работе приложения
                workState = WorkStateNames.Stopped;
                WriteInfo();
            }
        }
示例#2
0
        private string workState; // состояние работы

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Конструктор
        /// </summary>
        public MainLogic()
        {
            AppDirs = new AppDirs();
            AppLog = new Log(Log.Formats.Full);
            AppLog.Encoding = Encoding.UTF8;
            Settings = new Settings();

            infoFileName = "";
            thread = null;
            terminated = false;
            serverIsReady = false;
            startDT = DateTime.MinValue;
            workState = "";
            comm = new Comm(this);
            calculator = new Calculator(this);
            inCnls = new SortedList<int, InCnl>();
            drCnls = null;
            drmCnls = null;
            drhCnls = null;
            drCnlNums = null;
            drmCnlNums = null;
            drhCnlNums = null;
            avgCnlInds = null;
            ctrlCnls = new SortedList<int, CtrlCnl>();
            users = new SortedList<string, User>();
            formulas = new List<string>();
            curSrez = null;
            curSrezMod = false;
            srezDescr = null;
            minAvgData = null;
            hrAvgData = null;
            activeDTs = null;
            curSrezAdapter = null;
            curSrezCopyAdapter = null;
            eventAdapter = null;
            eventCopyAdapter = null;
            minSrezTableCache = null;
            hrSrezTableCache = null;
            modules = new List<ModLogic>();
        }
示例#3
0
文件: SrezAdapter.cs 项目: iyus/scada
        /// <summary>
        /// Заполнить объект dest из файла срезов FileName
        /// </summary>
        protected void FillObj(object dest)
        {
            Stream stream = null;
            BinaryReader reader = null;
            DateTime fillTime = DateTime.Now;

            SrezTableLight srezTableLight = dest as SrezTableLight;
            DataTable dataTable = dest as DataTable;
            Trend trend = dest as Trend;

            SrezTable srezTable = srezTableLight as SrezTable;
            SrezTableLight.Srez lastStoredSrez = null;

            try
            {
                if (srezTableLight == null && dataTable == null && trend == null)
                    throw new Exception("Destination object is invalid.");

                // подготовка объекта для хранения данных
                if (srezTableLight != null)
                {
                    srezTableLight.Clear();
                    srezTableLight.TableName = tableName;

                    if (srezTable != null)
                        srezTable.BeginLoadData();
                }
                else if (dataTable != null)
                {
                    // формирование структуры таблицы
                    dataTable.BeginLoadData();
                    dataTable.DefaultView.Sort = "";

                    if (dataTable.Columns.Count == 0)
                    {
                        dataTable.Columns.Add("DateTime", typeof(DateTime));
                        dataTable.Columns.Add("CnlNum", typeof(int));
                        dataTable.Columns.Add("Val", typeof(double));
                        dataTable.Columns.Add("Stat", typeof(int));
                        dataTable.DefaultView.AllowNew = false;
                        dataTable.DefaultView.AllowEdit = false;
                        dataTable.DefaultView.AllowDelete = false;
                    }
                    else
                    {
                        dataTable.Rows.Clear();
                    }
                }
                else // trend != null
                {
                    trend.Clear();
                    trend.TableName = tableName;
                }

                // заполнение объекта данными
                stream = ioStream == null ?
                    new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) :
                    ioStream;
                reader = new BinaryReader(stream);

                DateTime date = Arithmetic.ExtractDate(tableName); // определение даты срезов
                SrezTable.SrezDescr srezDescr = null;              // описание среза
                int[] cnlNums = null; // ссылка на номера входных каналов из описания среза
                while (stream.Position < stream.Length)
                {
                    // считывание списка номеров каналов и КС
                    int cnlNumCnt = reader.ReadUInt16();
                    if (cnlNumCnt > 0)
                    {
                        // загрузка номеров каналов в буфер для увеличения скорости работы
                        int cnlNumSize = cnlNumCnt * 2;
                        byte[] buf = new byte[cnlNumSize];
                        int readSize = reader.Read(buf, 0, cnlNumSize);

                        // создание описания среза и заполнение номеров каналов из буфера
                        // с проверкой их уникальности и упорядоченности
                        if (readSize == cnlNumSize)
                        {
                            int prevCnlNum = -1;
                            srezDescr = new SrezTable.SrezDescr(cnlNumCnt);
                            cnlNums = srezDescr.CnlNums;
                            for (int i = 0; i < cnlNumCnt; i++)
                            {
                                int cnlNum = BitConverter.ToUInt16(buf, i * 2);
                                if (prevCnlNum >= cnlNum)
                                    throw new Exception("Table is incorrect.");
                                cnlNums[i] = prevCnlNum = cnlNum;
                            }
                            srezDescr.CalcCS();
                        }
                    }
                    else if (srezDescr == null)
                    {
                        throw new Exception("Table is incorrect.");
                    }

                    // считывание и проверка КС
                    ushort cs = reader.ReadUInt16();
                    bool csOk = cnlNumCnt > 0 ? srezDescr.CS == cs : cs == 1;

                    // считывание данных среза
                    int cnlCnt = cnlNums.Length;   // количество каналов в срезе
                    int srezDataSize = cnlCnt * 9; // размер данных среза
                    if (csOk)
                    {
                        long srezPos = stream.Position;
                        double time = reader.ReadDouble();
                        int hour, min, sec;
                        Arithmetic.DecodeTime(time, out hour, out min, out sec);
                        DateTime srezDT = new DateTime(date.Year, date.Month, date.Day, hour, min, sec);

                        // инициализация нового среза
                        SrezTableLight.Srez srez;
                        if (srezTable != null)
                        {
                            srez = new SrezTable.Srez(srezDT, srezDescr)
                            {
                                State = DataRowState.Unchanged,
                                Position = srezPos
                            };
                        }
                        else if (srezTableLight != null)
                        {
                            srez = new SrezTableLight.Srez(srezDT, cnlCnt);
                            cnlNums.CopyTo(srez.CnlNums, 0);
                        }
                        else // srezTableLight == null
                        {
                            srez = null;
                        }

                        // считывание данных входных каналов
                        int bufInd = 0;
                        double val;
                        byte stat;
                        if (trend != null)
                        {
                            // выбор данных требуемого канала для тренда
                            int index = Array.BinarySearch<int>(cnlNums, trend.CnlNum);
                            if (index >= 0)
                            {
                                stream.Seek(index * 9, SeekOrigin.Current);
                                byte[] buf = new byte[9];
                                int readSize = reader.Read(buf, 0, 9);
                                if (readSize == 9)
                                {
                                    ExtractCnlData(buf, ref bufInd, out val, out stat);
                                    Trend.Point point = new Trend.Point(srezDT, val, stat);
                                    trend.Points.Add(point);
                                    stream.Seek(srezDataSize - (index + 1) * 9, SeekOrigin.Current);
                                }
                            }
                            else
                            {
                                stream.Seek(srezDataSize, SeekOrigin.Current);
                            }
                        }
                        else
                        {
                            // загрузка данных среза в буфер для увеличения скорости работы
                            byte[] buf = new byte[srezDataSize];
                            int readSize = reader.Read(buf, 0, srezDataSize);

                            // заполение таблицы срезов из буфера
                            if (srezTableLight != null)
                            {
                                for (int i = 0; i < cnlCnt; i++)
                                {
                                    ExtractCnlData(buf, ref bufInd, out val, out stat);

                                    srez.CnlNums[i] = cnlNums[i];
                                    srez.CnlData[i].Val = val;
                                    srez.CnlData[i].Stat = stat;

                                    if (bufInd >= readSize)
                                        break;
                                }

                                srezTableLight.AddSrez(srez);
                                lastStoredSrez = srez;
                            }
                            else // dataTable != null
                            {
                                for (int i = 0; i < cnlCnt; i++)
                                {
                                    ExtractCnlData(buf, ref bufInd, out val, out stat);

                                    DataRow row = dataTable.NewRow();
                                    row["DateTime"] = srezDT;
                                    row["CnlNum"] = cnlNums[i];
                                    row["Val"] = val;
                                    row["Stat"] = stat;
                                    dataTable.Rows.Add(row);

                                    if (bufInd >= readSize)
                                        break;
                                }
                            }
                        }
                    }
                    else
                    {
                        // пропустить срез, считая его размер так, как при повторяющемся списке номеров каналов
                        stream.Seek(srezDataSize + 8, SeekOrigin.Current);
                    }
                }
            }
            catch (EndOfStreamException)
            {
                // нормальная ситуация окончания файла
            }
            catch
            {
                fillTime = DateTime.MinValue;
                throw;
            }
            finally
            {
                if (fileMode)
                {
                    if (reader != null)
                        reader.Close();
                    if (stream != null)
                        stream.Close();
                }

                if (srezTableLight != null)
                {
                    srezTableLight.LastFillTime = fillTime;
                    if (srezTable != null)
                    {
                        srezTable.LastStoredSrez = (SrezTable.Srez)lastStoredSrez;
                        srezTable.EndLoadData();
                    }
                }
                else if (dataTable != null)
                {
                    dataTable.EndLoadData();
                    dataTable.AcceptChanges();
                    dataTable.DefaultView.Sort = "DateTime, CnlNum";
                }
                else if (trend != null)
                {
                    trend.LastFillTime = fillTime;
                    trend.Sort();
                }
            }
        }