/// <summary> /// Экспортировать текущие данные, загрузив их из файла /// </summary> private void ExportCurDataFromFile(Exporter exporter) { // загрузка текущего среза из файла SrezTableLight srezTable = new SrezTableLight(); SrezAdapter srezAdapter = new SrezAdapter(); srezAdapter.FileName = ServerUtils.BuildCurFileName(Settings.ArcDir); try { srezAdapter.Fill(srezTable); } catch (Exception ex) { log.WriteAction(string.Format(Localization.UseRussian ? "Ошибка при загрузке текущего среза из файла {0}: {1}" : "Error loading current data from file {0}: {1}", srezAdapter.FileName, ex.Message)); } // добавление среза в очередь экспорта if (srezTable.SrezList.Count > 0) { SrezTableLight.Srez sourceSrez = srezTable.SrezList.Values[0]; SrezTableLight.Srez srez = new SrezTableLight.Srez(DateTime.Now, sourceSrez.CnlNums, sourceSrez); exporter.EnqueueCurData(srez); log.WriteAction(Localization.UseRussian ? "Текущие данные добавлены в очередь экспорта" : "Current data added to export queue"); } else { log.WriteAction(Localization.UseRussian ? "Отсутствуют текущие данные для экспорта" : "No current data to export"); } }
/// <summary> /// Экспортировать архивные данные, загрузив их из файла /// </summary> private void ExportArcDataFromFile(Exporter exporter, DateTime dateTime) { // загрузка таблицы минутных срезов из файла SrezTableLight srezTable = new SrezTableLight(); SrezAdapter srezAdapter = new SrezAdapter(); srezAdapter.FileName = ServerUtils.BuildMinFileName(Settings.ArcDir, dateTime); try { srezAdapter.Fill(srezTable); } catch (Exception ex) { log.WriteAction(string.Format(Localization.UseRussian ? "Ошибка при загрузке таблицы минутных срезов из файла {0}: {1}" : "Error loading minute data table from file {0}: {1}", srezAdapter.FileName, ex.Message)); } // поиск среза на заданное время SrezTableLight.Srez srez = srezTable.GetSrez(dateTime); // добавление среза в очередь экспорта if (srez == null) { log.WriteAction(Localization.UseRussian ? "Отсутствуют архивные данные для экспорта" : "No archive data to export"); } else { exporter.EnqueueArcData(srez); log.WriteAction(Localization.UseRussian ? "Архивные данные добавлены в очередь экспорта" : "Archive data added to export queue"); } }
/// <summary> /// Начальная обработка дерева XML-документа /// </summary> protected override void StartXmlDocProc() { genDT = DateTime.Now; if (tableView == null) { hourTable = null; } else { AppData.MainData.RefreshData(date, out hourTable); } if (eventOut <= 0) { eventTable = null; } else { AppData.MainData.RefreshEvents(date, out eventTable); } templItemRow = null; templEventRow = null; item = null; eventView = null; }
/// <summary> /// Конструктор /// </summary> public DataCache(ServerComm serverComm, Log log) { if (serverComm == null) { throw new ArgumentNullException("serverComm"); } if (log == null) { throw new ArgumentNullException("log"); } this.serverComm = serverComm; this.log = log; baseLock = new object(); curDataLock = new object(); baseRefrDT = DateTime.MinValue; tblCur = new SrezTableLight(); curDataRefrDT = DateTime.MinValue; BaseTables = new BaseTables(); CnlProps = new InCnlProps[0]; CtrlCnlProps = new CtrlCnlProps[0]; CnlStatProps = new SortedList <int, CnlStatProps>(); HourTableCache = new Cache <DateTime, SrezTableLight>(HourCacheStorePeriod, HourCacheCapacity); EventTableCache = new Cache <DateTime, EventTableLight>(EventCacheStorePeriod, EventCacheCapacity); }
/// <summary> /// Конструктор /// </summary> public DataCache(ServerComm serverComm, Log log) { if (serverComm == null) { throw new ArgumentNullException("serverComm"); } if (log == null) { throw new ArgumentNullException("log"); } this.serverComm = serverComm; this.log = log; baseLock = new object(); curDataLock = new object(); baseRefrDT = DateTime.MinValue; baseAge = DateTime.MinValue; tblCur = new SrezTableLight(); curRefrDT = DateTime.MinValue; BaseTables = new BaseTables(); CnlProps = new InCnlProps[0]; CtrlCnlProps = new CtrlCnlProps[0]; }
public List <MQTTPubTopic> GetValues(List <MQTTPubTopic> MqttPTs) { if (cn) { SrezTableLight stl = new SrezTableLight(); IsCurr = rsrv.ReceiveSrezTable("current.dat", stl); SrezTableLight.Srez srez = stl.SrezList.Values [0]; bool found; SrezTableLight.CnlData cnlData; foreach (MQTTPubTopic MqttPT in MqttPTs) { found = srez.GetCnlData(MqttPT.NumCnl, out cnlData); if (found) { if (MqttPT.PubBehavior == "OnChange") { if (MqttPT.Value != cnlData.Val) { MqttPT.IsPub = true; } } if (MqttPT.PubBehavior == "OnAlways") { MqttPT.IsPub = true; } MqttPT.Value = cnlData.Val; } } } return(MqttPTs); }
/// <summary> /// Get a table of hourly data per day from the cache or from the server /// </summary> /// <remarks>The returned table after loading is not changed by an instance of this class, /// thus, reading its data is thread safe. /// The method always returns a non-null object.</remarks> public SrezTableLight GetHourTable(DateTime date) { try { // getting the table of hourly slices from the cache date = date.Date; var utcNowDT = DateTime.UtcNow; var cacheItem = HourTableCache.GetOrCreateItem(date, utcNowDT); // block access to only one table of hourly slices lock (cacheItem) { var table = cacheItem.Value; // table to get var tableAge = cacheItem.ValueAge; // table file change time bool tableIsNotValid = utcNowDT - cacheItem.ValueRefrDT > DataValidSpan; // the table might be out of date // getting time slice table from server if (table == null || tableIsNotValid) { string tableName = SrezAdapter.BuildHourTableName(date); var newTableAge = serverComm.ReceiveFileAge(ServerComm.Dirs.Hour, tableName); if (newTableAge == DateTime.MinValue) { // the table file does not exist or there is no connection to the server table = null; // do not clog the log //log.WriteError($"Unable to receive modification time of the hourly data table {tableName}"); } else if (newTableAge != tableAge) // table file changed { table = new SrezTableLight(); if (serverComm.ReceiveSrezTable(tableName, table)) { table.FileModTime = newTableAge; table.LastFillTime = utcNowDT; } else { throw new ScadaException("Unable to receive hourly data table."); } } if (table == null) { table = new SrezTableLight(); } // update table in cache HourTableCache.UpdateItem(cacheItem, table, newTableAge, utcNowDT); } return(table); } } catch (Exception ex) { log.WriteException(ex, "Error getting hourly data table for {0} from the cache or from the server", date.ToLocalizedDateString()); return(new SrezTableLight()); } }
/// <summary> /// Предварительно обработать дерево XML-документа /// </summary> protected override void StartXmlDocProc() { genDT = DateTime.Now; itemRowTemplate = null; viewItem = null; reqDateHourTable = null; prevDateHourTable = null; }
public SrezTableLight.Srez GetCurrSrez() { lock (rssrv) { SrezTableLight stl = new SrezTableLight(); bool rec; rec = rssrv.ReceiveSrezTable("current.dat", stl); return(stl.SrezList.Values [0]); } }
/// <summary> /// Окончательно обработать дерево XML-документа /// </summary> protected override void FinalXmlDocProc() { // проверка шаблона if (workbook.Worksheets.Count == 0 || itemRowTemplate == null) { throw new Exception(WebPhrases.IncorrectRepTemplate); } // перевод наименования листа workbook.Worksheets[0].Name = PlgPhrases.HourDataWorksheet; // удаление лишних атрибутов таблицы Table table = itemRowTemplate.ParentTable; table.RemoveTableNodeAttrs(); // скрытие неиспользуемых столбцов HideUnusedColumns(table); // удаление строки-шаблона int itemRowIndex = table.Rows.IndexOf(itemRowTemplate); table.RemoveRow(itemRowIndex); // получение часовых данных reqDateHourTable = dataAccess.DataCache.GetHourTable(date); if (startHour < 0) { prevDateHourTable = dataAccess.DataCache.GetHourTable(date.AddDays(-1)); } // вывод данных в отчёт for (int i = 0, cnt = tableView.Items.Count; i < cnt; i++) { viewItem = tableView.Items[i]; if (!viewItem.Hidden) { cnlProps = viewItem.CnlNum > 0 ? dataAccess.GetCnlProps(viewItem.CnlNum) : null; Row newRow = itemRowTemplate.Clone(); ExcelProc(newRow); table.AppendRow(newRow); } } }
public void SendCurrSrez(List <Cnl> cnls) { bool res = false; DateTime dt = DateTime.Now; foreach (Cnl cnl in cnls) { RSServer RSSrv = GetRSSrvId(cnl.ID); SrezTableLight stl = new SrezTableLight(); SrezTableLight.Srez curSrezSrc = new SrezTableLight.Srez(dt, 1); curSrezSrc.CnlNums [0] = cnl.Num; curSrezSrc.CnlData [0] = new SrezTableLight.CnlData() { Val = cnl.Value, Stat = cnl.State }; res = RSSrv.SendSrez(curSrezSrc, out res); } }
private SrezTableLight prevDateHourTable; // таблица часовых данных за предыдущую дату /// <summary> /// Конструктор /// </summary> public HourDataRepBuilder(DataAccess dataAccess) : base() { if (dataAccess == null) { throw new ArgumentNullException("dataAccess"); } this.dataAccess = dataAccess; dataFormatter = new DataFormatter(); tableView = null; date = DateTime.MinValue; startHour = 0; endHour = 23; genDT = DateTime.MinValue; itemRowTemplate = null; viewItem = null; reqDateHourTable = null; prevDateHourTable = null; }
public override void OnCurDataProcessed(int[] cnlNums, SrezTableLight.Srez curSrez) { // the method executes when new current data have been processed by the server, // the channel numbers are sorted in ascending order // метод выполняется после обработки новых текущих данных сервером, // номера каналов упорядочены по возрастанию const int MyCnlNum = 1; const int MyKpNum = 1; const int MyCmdNum = 1; const double MyCmdVal = 1.0; // send a command if the value of MyCnlNum channel greater than 200 WriteToLog("Process current data by the module " + Name, Log.ActTypes.Action); SrezTableLight.CnlData cnlData; if (curSrez.GetCnlData(MyCnlNum, out cnlData) && cnlData.Val > 200) { WriteToLog("Send command by the module " + Name, Log.ActTypes.Action); Command cmd = new Command(BaseValues.CmdTypes.Standard); cmd.KPNum = MyKpNum; cmd.CmdNum = MyCmdNum; cmd.CmdVal = MyCmdVal; PassCommand(cmd); } }
/// <summary> /// Выполнить действия после обработки новых текущих данных /// </summary> /// <remarks>Номера каналов упорядочены по возрастанию. /// Вычисление дорасчётных каналов текущего среза в момент вызова метода не выполнено</remarks> public virtual void OnCurDataProcessed(int[] cnlNums, SrezTableLight.Srez curSrez) { }
public override TaskStatus Run() { Info("Start Comparator task"); bool success = false; bool IsIndata = false; try { if (indata == "file") { foreach (FileInf fi in SelectFiles()) { SrezTableLight stl = new SrezTableLight(); sa.FileName = fi.Path; sa.Fill(stl); int id = int.Parse(fi.FileName.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries)[1]); stls.AddSrez(id, stl.SrezList.Values[0]); } IsIndata = true; } if (indata == "mem") { foreach (RSServer srv in srvs.GetRSServers()) { stls.AddSrez(srv.Id, srv.GetCurrSrez()); } IsIndata = true; } if (IsIndata) { foreach (Cnl cnl in Cnls) { Argument cArg = new Argument(cnl.ToString(), stls.GetCnlData(cnl.ID, cnl.Num)); CalcArgs.Add(cArg); } CalcArgs.AddRange(xArgs); foreach (Argument arg in CalcArgs) { Info(arg.getArgumentName() + " " + arg.getArgumentValue().ToString()); } Expression expr = new Expression(condition, CalcArgs.ToArray()); double pvExpr = expr.calculate(); if (pvExpr == 0) { success = false; } else if (pvExpr == 1) { success = true; } if (success) { foreach (Argument arg in odts) { arg.addDefinitions(CalcArgs.ToArray()); } } InfoFormat("Condition: {0}", condition); InfoFormat("Result calculate: {0}", expr.calculate()); InfoFormat("Success value: {0}", success); } else { Info("Not set parametr indata"); } CalcArgs.Clear(); stls.ClearSrez(); } catch (ThreadAbortException) { throw; } catch (Exception ex) { ErrorFormat("Ann error calc comparator. Error: {0}", ex.Message); } Info("Task RSComparator finished."); return(new TaskStatus(Status.Success, success)); }
/// <summary> /// Обработать директиву, связанную со значением ячейки /// </summary> protected override void ProcVal(Cell cell, string valName) { string nodeText = null; if (valName == "Title") { nodeText = string.Format(TablePhrases.HourDataTitle, tableView.Title, date.ToLocalizedDateString(), WFrmTable.GetLocalizedHour(startHour) + " - " + WFrmTable.GetLocalizedHour(endHour)); } else if (valName == "Gen") { nodeText = TablePhrases.HourDataGen + genDT.ToLocalizedString(); } else if (valName == "ItemCol") { nodeText = TablePhrases.ItemCol; } else if (valName.StartsWith("H")) { // заголовок таблицы часовых данных if (int.TryParse(valName.Substring(1), out int hour)) { nodeText = WFrmTable.GetLocalizedHour(hour); } } else if (viewItem != null) { if (valName == "Name") { nodeText = viewItem.Caption; } else if (valName.StartsWith("h")) { // часовые данные if (int.TryParse(valName.Substring(1), out int hour)) { if (viewItem.CnlNum > 0 && startHour <= hour && hour <= endHour) { DateTime colDT = date.AddHours(hour); SrezTableLight hourTable = hour >= 0 ? reqDateHourTable : prevDateHourTable; hourTable.SrezList.TryGetValue(colDT, out SrezTableLight.Srez snapshot); if (dataFormatter.HourDataVisible(colDT, genDT, snapshot != null, out string emptyVal)) { // получение данных snapshot.GetCnlData(viewItem.CnlNum, out double val, out int stat); // форматирование данных dataFormatter.FormatCnlVal(val, stat, viewItem.CnlProps, ".", "", out string text, out string textWithUnit, out bool textIsNumber); string color = dataFormatter.GetCnlValColor(val, stat, viewItem.CnlProps, dataAccess.GetCnlStatProps(stat)); // вывод данных nodeText = text; workbook.SetColor(cell.Node, null, color); if (textIsNumber) { cell.SetNumberType(); } } else { nodeText = emptyVal; } } else { nodeText = ""; } } } } if (nodeText != null) { cell.DataNode.InnerText = nodeText; } }
/// <summary> /// Копировать текущие данные и признаки изменения тегов КП, /// затем сбросить признаки изменения /// </summary> public void CopyCurData(SrezTableLight.CnlData[] destCurData, bool[] destCurDataModified) { if (destCurData == null) throw new ArgumentNullException("destCurData"); if (destCurDataModified == null) throw new ArgumentNullException("destCurDataModified"); try { lock (curData) { int tagCnt = curData.Length; Array.Copy(curData, destCurData, tagCnt); Array.Copy(curDataModified, destCurDataModified, tagCnt); Array.Clear(curDataModified, 0, tagCnt); } } catch (Exception ex) { WriteToLog((Localization.UseRussian ? "Ошибка при копировании текущих данных тегов КП: " : "Error copying current data of device tags: ") + ex.Message); } }
/// <summary> /// Потокобезопасно установить текущие данные тега КП и признак их изменения /// </summary> protected void SetCurData(int tagIndex, SrezTableLight.CnlData newData) { lock (curData) { if (0 <= tagIndex && tagIndex < curData.Length) { SrezTableLight.CnlData curTagData = curData[tagIndex]; curDataModified[tagIndex] |= curTagData.Val != newData.Val || curTagData.Stat != newData.Stat; curData[tagIndex] = newData; } } }
/// <summary> /// Получить таблицу часовых данных за сутки из кэша или от сервера /// </summary> /// <remarks>Возвращаемая таблица после загрузки не изменяется экземпляром данного класса, /// таким образом, чтение её данных является потокобезопасным. /// Метод всегда возвращает объект, не равный null</remarks> public SrezTableLight GetHourTable(DateTime date) { try { // получение таблицы часовых срезов из кэша date = date.Date; DateTime utcNowDT = DateTime.UtcNow; Cache <DateTime, SrezTableLight> .CacheItem cacheItem = HourTableCache.GetOrCreateItem(date, utcNowDT); // блокировка доступа только к одной таблице часовых срезов lock (cacheItem) { SrezTableLight table = cacheItem.Value; // таблица, которую необходимо получить DateTime tableAge = cacheItem.ValueAge; // время изменения файла таблицы bool tableIsNotValid = utcNowDT - cacheItem.ValueRefrDT > DataValidSpan; // таблица могла устареть // получение таблицы часовых срезов от сервера if (table == null || tableIsNotValid) { string tableName = SrezAdapter.BuildHourTableName(date); DateTime newTableAge = serverComm.ReceiveFileAge(ServerComm.Dirs.Hour, tableName); if (newTableAge == DateTime.MinValue) // файл таблицы не существует или нет связи с сервером { table = null; // не засорять лог /*log.WriteError(string.Format(Localization.UseRussian ? * "Не удалось принять время изменения таблицы часовых данных {0}" : * "Unable to receive modification time of the hourly data table {0}", tableName));*/ } else if (newTableAge != tableAge) // файл таблицы изменён { table = new SrezTableLight(); if (serverComm.ReceiveSrezTable(tableName, table)) { table.FileModTime = newTableAge; table.LastFillTime = utcNowDT; } else { throw new ScadaException(Localization.UseRussian ? "Не удалось принять таблицу часовых срезов." : "Unable to receive hourly data table."); } } if (table == null) { table = new SrezTableLight(); } // обновление таблицы в кэше HourTableCache.UpdateItem(cacheItem, table, newTableAge, utcNowDT); } return(table); } } catch (Exception ex) { log.WriteException(ex, Localization.UseRussian ? "Ошибка при получении таблицы часовых данных за {0} из кэша или от сервера" : "Error getting hourly data table for {0} from the cache or from the server", date.ToLocalizedDateString()); return(new SrezTableLight()); } }
/// <summary> /// Добавить текущие данные в очередь экспорта /// </summary> public void EnqueueCurData(SrezTableLight.Srez curSrez) { lock (curSrezQueue) { if (curSrezQueue.Count < MaxQueueSize) { curSrezQueue.Enqueue(curSrez); } else { skipCurSrezCnt++; log.WriteAction(string.Format(Localization.UseRussian ? "Невозможно добавить в очередь текущие данные. Максимальный размер очереди {0} превышен" : "Unable to enqueue current data. The maximum size of the queue {0} is exceeded", MaxQueueSize)); } } }
/// <summary> /// Генерировать событие в соответствии со свойствами и данными входного канала /// </summary> private void GenEvent(InCnl inCnl, SrezTableLight.CnlData oldCnlData, SrezTableLight.CnlData newCnlData) { if (inCnl.EvEnabled) { double oldVal = oldCnlData.Val; double newVal = newCnlData.Val; int oldStat = oldCnlData.Stat; int newStat = newCnlData.Stat; bool dataHasChanged = oldStat > BaseValues.CnlStatuses.Undefined && newStat > BaseValues.CnlStatuses.Undefined && (oldVal != newVal || oldStat != newStat); if (// события по изменению inCnl.EvOnChange && dataHasChanged || // события по неопределённому состоянию и выходу из него inCnl.EvOnUndef && (oldStat > BaseValues.CnlStatuses.Undefined && newStat == BaseValues.CnlStatuses.Undefined || oldStat == BaseValues.CnlStatuses.Undefined && newStat > BaseValues.CnlStatuses.Undefined) || // события нормализации, занижения и завышения (newStat == BaseValues.CnlStatuses.Normal || newStat == BaseValues.CnlStatuses.LowCrash || newStat == BaseValues.CnlStatuses.Low || newStat == BaseValues.CnlStatuses.High || newStat == BaseValues.CnlStatuses.HighCrash) && oldStat != newStat) { // создание события EventTableLight.Event ev = new EventTableLight.Event(); ev.DateTime = DateTime.Now; ev.ObjNum = inCnl.ObjNum; ev.KPNum = inCnl.KPNum; ev.ParamID = inCnl.ParamID; ev.CnlNum = inCnl.CnlNum; ev.OldCnlVal = oldCnlData.Val; ev.OldCnlStat = oldStat; ev.NewCnlVal = newCnlData.Val; ev.NewCnlStat = dataHasChanged && oldStat == BaseValues.CnlStatuses.Defined && newStat == BaseValues.CnlStatuses.Defined ? BaseValues.CnlStatuses.Changed : newStat; // запись события и выполнение действий модулей WriteEvent(ev); } } }
/// <summary> /// Вызвать событие OnCurDataCalculated для модулей /// </summary> private void RaiseOnCurDataCalculated(int[] cnlNums, SrezTableLight.Srez curSrez) { lock (modules) { foreach (ModLogic modLogic in modules) { try { modLogic.OnCurDataCalculated(cnlNums, curSrez); } catch (Exception ex) { AppLog.WriteAction(string.Format(Localization.UseRussian ? "Ошибка при выполнении действий " + "после вычисления дорасчётных каналов текущего среза в модуле {0}: {1}" : "Error executing actions on current data calculated in module {0}: {1}", modLogic.Name, ex.Message), Log.ActTypes.Exception); } } } }
/// <summary> /// Выполнить действия после вычисления дорасчётных каналов текущего среза /// </summary> /// <remarks>Номера каналов упорядочены по возрастанию</remarks> public virtual void OnCurDataCalculated(int[] cnlNums, SrezTableLight.Srez curSrez) { }
/// <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(); } }
/// <summary> /// Преобразовать данные тега КП в строку /// </summary> protected override string ConvertTagDataToStr(int signal, SrezTableLight.CnlData tagData) { if (tagData.Stat > 0) { if (signal == 1) return tagData.Val.ToString("N0"); } return base.ConvertTagDataToStr(signal, tagData); }
private Trend trend; // ��������� ���������� �������� ����� #endregion Fields #region Constructors /// <summary> /// ����������� /// </summary> public MainData() { serverComm = null; settFileName = ""; settModTime = DateTime.MinValue; tblCur = new SrezTableLight(); hourTableCache = new SrezTableLight[HourCacheSize]; eventTableCache = new EventTableLight[EventCacheSize]; for (int i = 0; i < HourCacheSize; i++) hourTableCache[i] = null; for (int i = 0; i < EventCacheSize; i++) eventTableCache[i] = null; hourTableIndex = 0; eventTableIndex = 0; trend = null; nfi = new NumberFormatInfo(); defDecSep = Localization.Culture.NumberFormat.NumberDecimalSeparator; defGrSep = Localization.Culture.NumberFormat.NumberGroupSeparator; baseModTime = DateTime.MinValue; baseFillTime = DateTime.MinValue; tblInCnl = new DataTable("InCnl"); tblCtrlCnl = new DataTable("CtrlCnl"); tblObj = new DataTable("Obj"); tblKP = new DataTable("KP"); tblRole = new DataTable("Role"); tblUser = new DataTable("User"); tblInterface = new DataTable("Interface"); tblRight = new DataTable("Right"); tblEvType = new DataTable("EvType"); tblParam = new DataTable("Param"); tblUnit = new DataTable("Unit"); tblCmdVal = new DataTable("CmdVal"); tblFormat = new DataTable("Format"); baseTblArr = new DataTable[13]; baseTblArr[0] = tblInCnl; baseTblArr[1] = tblCtrlCnl; baseTblArr[2] = tblObj; baseTblArr[3] = tblKP; baseTblArr[4] = tblRole; baseTblArr[5] = tblUser; baseTblArr[6] = tblInterface; baseTblArr[7] = tblRight; baseTblArr[8] = tblEvType; baseTblArr[9] = tblParam; baseTblArr[10] = tblUnit; baseTblArr[11] = tblCmdVal; baseTblArr[12] = tblFormat; cnlPropsArr = null; maxCnlCnt = 0; refrLock = new Object(); baseLock = new Object(); cnlPropLock = new Object(); cnlDataLock = new Object(); eventLock = new Object(); }
/// <summary> /// �������� (�����������) ������ ��� ������ ������� �� SCADA-�������� /// ��� ��������� ����� �������� ���������� �� SCADA-�������� /// </summary> private void RefrServerComm() { if (settFileName != "") { DateTime dateTime = GetLastWriteTime(settFileName); if (dateTime > DateTime.MinValue && dateTime != settModTime) { settModTime = dateTime; CommSettings commSettings = new CommSettings(); commSettings.LoadFromFile(settFileName, AppData.Log); if (serverComm == null || !serverComm.CommSettings.Equals(commSettings)) { if (serverComm != null) { serverComm.Close(); tblCur = new SrezTableLight(); for (int i = 0; i < HourCacheSize; i++) hourTableCache[i] = null; for (int i = 0; i < EventCacheSize; i++) eventTableCache[i] = null; hourTableIndex = 0; eventTableIndex = 0; trend = null; baseModTime = DateTime.MinValue; baseFillTime = DateTime.MinValue; } serverComm = new ServerComm(commSettings); } } } }
/// <summary> /// Установить данные тега среза /// </summary> protected void SetTagData(int tagIndex, SrezTableLight.CnlData newData) { if (0 <= tagIndex && tagIndex < TagData.Length) TagData[tagIndex] = newData; }
/// <summary> /// Вызвать событие OnCurDataProcessed для модулей /// </summary> private void RaiseOnCurDataProcessed(int[] cnlNums, SrezTableLight.Srez curSrez) { lock (modules) { foreach (ModLogic modLogic in modules) { try { modLogic.OnCurDataProcessed(cnlNums, curSrez); } catch (Exception ex) { AppLog.WriteAction(string.Format(Localization.UseRussian ? "Ошибка при выполнении действий после обработки новых текущих данных в модуле {0}: {1}" : "Error executing actions on current data processed in module {0}: {1}", modLogic.Name, ex.Message), Log.ActTypes.Exception); } } } }
/// <summary> /// Отправить архивный срез SCADA-Серверу /// </summary> public bool SendArchive(SrezTableLight.Srez arcSrez, out bool result) { Monitor.Enter(tcpLock); bool complete = false; result = false; errMsg = ""; try { if (RestoreConnection()) { commState = CommStates.WaitResponse; tcpClient.ReceiveTimeout = commSettings.ServerTimeout; // отправка команды записи архивного среза int cnlCnt = arcSrez.CnlNums.Length; int cmdLen = cnlCnt * 14 + 13; byte[] buf = new byte[cmdLen]; buf[0] = (byte)(cmdLen % 256); buf[1] = (byte)(cmdLen / 256); buf[2] = 0x04; double arcDT = Arithmetic.EncodeDateTime(arcSrez.DateTime); byte[] bytes = BitConverter.GetBytes(arcDT); Array.Copy(bytes, 0, buf, 3, 8); buf[11] = (byte)(cnlCnt % 256); buf[12] = (byte)(cnlCnt / 256); for (int i = 0; i < cnlCnt; i++) { bytes = BitConverter.GetBytes((UInt32)arcSrez.CnlNums[i]); Array.Copy(bytes, 0, buf, i * 14 + 13, 4); SrezTableLight.CnlData data = arcSrez.CnlData[i]; bytes = BitConverter.GetBytes(data.Val); Array.Copy(bytes, 0, buf, i * 14 + 17, 8); bytes = BitConverter.GetBytes((UInt16)data.Stat); Array.Copy(bytes, 0, buf, i * 14 + 25, 2); } netStream.Write(buf, 0, cmdLen); // приём результата buf = new byte[4]; int bytesRead = netStream.Read(buf, 0, 4); // обработка полученных данных if (bytesRead == buf.Length && CheckDataFormat(buf, 0x04)) { result = buf[3] > 0; commState = result ? CommStates.Authorized : CommStates.NotReady; complete = true; } else { errMsg = Localization.UseRussian ? "Неверный формат ответа SCADA-Сервера на команду отправки архивного среза" : "Incorrect SCADA-Server response to sending archive data command"; WriteAction(errMsg, Log.ActTypes.Exception); commState = CommStates.Error; } } } catch (Exception ex) { errMsg = (Localization.UseRussian ? "Ошибка при отправке архивного среза SCADA-Серверу: " : "Error sending archive data to SCADA-Server: ") + ex.Message; WriteAction(errMsg, Log.ActTypes.Exception); Disconnect(); } finally { RestoreReceiveTimeout(); Monitor.Exit(tcpLock); } return complete; }
/// <summary> /// �������� ������� ���� ������������, �������� � ������� ������, ���� ��� ���������� /// </summary> /// <param name="reqDate">���� ������������� ������� ������</param> /// <param name="hourTable">������� ������� ������</param> public void RefreshData(DateTime reqDate, out SrezTableLight hourTable) { RefreshBase(); Monitor.Enter(refrLock); try { // ���������� �������� ����� DateTime now = DateTime.Now; if ((now - tblCur.LastFillTime).TotalSeconds > CurSrezValidTime) // ������ �������� { DateTime curModTime = serverComm.ReceiveFileAge(ServerComm.Dirs.Cur, "current.dat"); if (curModTime != tblCur.FileModTime) // ���� ����� ������ tblCur.FileModTime = serverComm.ReceiveSrezTable("current.dat", tblCur) ? curModTime : DateTime.MinValue; } // ���������� ������� ������� ������ hourTable = null; if (reqDate > DateTime.MinValue) { string hourTableName = "h" + reqDate.ToString("yyMMdd") + ".dat"; // ����� ������� ������� ������� ������ � ���� int tableIndex = -1; for (int i = 0; i < HourCacheSize; i++) { hourTable = hourTableCache[i]; if (hourTable != null && hourTable.TableName == hourTableName) { tableIndex = i; break; } } if (tableIndex < 0 || (now - hourTable.LastFillTime).TotalSeconds > HourSrezValidTime /*������ ��������*/) { DateTime fileModTime = serverComm.ReceiveFileAge(ServerComm.Dirs.Hour, hourTableName); if (tableIndex < 0) { hourTable = null; // ����������� ����� � ���� ��� ����� ������� ������� ������ tableIndex = hourTableIndex; if (++hourTableIndex == HourCacheSize) hourTableIndex = 0; } if (hourTable == null || fileModTime != hourTable.FileModTime /*���� ������ ������*/) { // �������� ����� ������� ������� ������ hourTable = new SrezTableLight(); hourTableCache[tableIndex] = hourTable; // �������� ������� ������� ������ if (serverComm.ReceiveSrezTable(hourTableName, hourTable)) hourTable.FileModTime = fileModTime; } } } } finally { Monitor.Exit(refrLock); } }
/// <summary> /// Экспортировать срез /// </summary> private void ExportSrez(DbCommand cmd, SrezTableLight.Srez srez) { DataSource.SetCmdParam(cmd, "dateTime", srez.DateTime); foreach (int cnlNum in srez.CnlNums) { SrezTableLight.CnlData cnlData; if (srez.GetCnlData(cnlNum, out cnlData)) { DataSource.SetCmdParam(cmd, "cnlNum", cnlNum); DataSource.SetCmdParam(cmd, "val", cnlData.Val); DataSource.SetCmdParam(cmd, "stat", cnlData.Stat); cmd.ExecuteNonQuery(); } } }
/// <summary> /// Получить таблицу срезов, содержащую данные заданных каналов /// </summary> public SrezTableLight GetSrezTable(DateTime date, SrezTypes srezType, int[] cnlNums) { try { SrezTableLight destSrezTable; int cnlNumsLen = cnlNums == null ? 0 : cnlNums.Length; if (serverIsReady && cnlNumsLen > 0) { // получение кэша таблицы срезов SrezTableCache srezTableCache = GetSrezTableCache(date.Date, srezType); lock (srezTableCache) { // заполнение таблицы срезов в кэше srezTableCache.FillSrezTable(); // создание новой таблицы срезов и копирование в неё данных заданных каналов SrezTable srcSrezTable = srezTableCache.SrezTable; SrezTable.SrezDescr prevSrezDescr = null; int[] cnlNumIndexes = new int[cnlNumsLen]; destSrezTable = new SrezTableLight(); foreach (SrezTable.Srez srcSrez in srcSrezTable.SrezList.Values) { // определение индексов каналов if (!srcSrez.SrezDescr.Equals(prevSrezDescr)) { for (int i = 0; i < cnlNumsLen; i++) cnlNumIndexes[i] = Array.BinarySearch<int>(srcSrez.CnlNums, cnlNums[i]); } // создание и заполнение среза, содержащего заданные каналы SrezTableLight.Srez destSrez = new SrezTableLight.Srez(srcSrez.DateTime, cnlNumsLen); for (int i = 0; i < cnlNumsLen; i++) { destSrez.CnlNums[i] = cnlNums[i]; int cnlNumInd = cnlNumIndexes[i]; destSrez.CnlData[i] = cnlNumInd < 0 ? SrezTableLight.CnlData.Empty : srcSrez.CnlData[cnlNumInd]; } destSrezTable.SrezList.Add(destSrez.DateTime, destSrez); prevSrezDescr = srcSrez.SrezDescr; } } } else { destSrezTable = null; } return destSrezTable; } catch (Exception ex) { AppLog.WriteAction((Localization.UseRussian ? "Ошибка при получении таблицы срезов: " : "Error getting snapshot table: ") + ex.Message, Log.ActTypes.Exception); return null; } }
/// <summary> /// Добавить архивные данные в очередь экспорта /// </summary> public void EnqueueArcData(SrezTableLight.Srez arcSrez) { lock (arcSrezQueue) { if (arcSrezQueue.Count < MaxQueueSize) { arcSrezQueue.Enqueue(arcSrez); } else { skipArcSrezCnt++; log.WriteAction(string.Format(Localization.UseRussian ? "Невозможно добавить в очередь архивные данные. Максимальный размер очереди {0} превышен" : "Unable to enqueue archive data. The maximum size of the queue {0} is exceeded", MaxQueueSize)); } } }
public override void OnArcDataProcessed(int[] cnlNums, SrezTableLight.Srez arcSrez) { // the method executes when new archive data have been processed by the server // метод выполняется после обработки новых архивных данных сервером WriteToLog("Process archive data by the module " + Name, Log.ActTypes.Action); }
/// <summary> /// Преобразовать данные тега КП в строку /// </summary> protected virtual string ConvertTagDataToStr(int signal, SrezTableLight.CnlData tagData) { return tagData.Stat > 0 ? tagData.Val.ToString("N3", Localization.Culture) : "---"; }
public override void OnCurDataCalculated(int[] cnlNums, SrezTableLight.Srez curSrez) { // the method executes after current data calculation (approximately every 100 ms) // метод выполняется после вычисления дорасчётных каналов текущего среза (примерно каждые 100 мс) }
/// <summary> /// Получить часовые данные входных каналов /// </summary> private HourCnlData[] GetHourCnlDataArr(int year, int month, int day, int startHour, int endHour, IList <int> cnlList, bool existing, ref long[] dataAgeArr) { if (startHour > endHour) { throw new ArgumentException("Start hour must be less or equal than end hour."); } DataAccess dataAccess = AppData.DataAccess; DataCache dataCache = dataAccess.DataCache; DateTime date = new DateTime(year, month, day); DateTime startDT = date.AddHours(startHour); DateTime startDate = startDT.Date; DateTime endDT = date.AddHours(endHour); DateTime endDate = endDT.Date; int hourCnt = endHour - startHour + 1; int dayCnt = (int)(endDate - startDate).TotalDays + 1; List <HourCnlData> hourCnlDataList = new List <HourCnlData>(hourCnt); long[] newDataAgeArr = new long[dayCnt]; DateTime nowDT = DateTime.Now; DateTime curDate = startDate; for (int dayInd = 0; dayInd < dayCnt; dayInd++) { SrezTableLight tblHour = dataCache.GetHourTable(curDate); long newDataAge = WebUtils.DateTimeToJs(tblHour.FileModTime); long prevDataAge = dayInd < dataAgeArr.Length ? dataAgeArr[dayInd] : 0; bool modified = prevDataAge <= 0 || prevDataAge < newDataAge; newDataAgeArr[dayInd] = newDataAge; DateTime nextDate = curDate.AddDays(1.0); if (existing) { // получение всех существующих часовых срезов DateTime dayStartDT = curDate > startDate ? curDate : startDT; DateTime dayEndDT = curDate < endDate ? nextDate : endDT; foreach (SrezTableLight.Srez snapshot in tblHour.SrezList.Values) { DateTime snapshotDT = snapshot.DateTime; if (dayStartDT <= snapshotDT && snapshotDT <= dayEndDT) { double hour = (snapshotDT - date).TotalHours; if (modified) { AppendHourCnlData(hourCnlDataList, hour, cnlList, snapshot, snapshotDT, nowDT); } else { AppendEmptyHourCnlData(hourCnlDataList, hour); } } } } else { // заполнение данных по целым часам int dayStartHour = curDate > startDate ? 0 : startDT.Hour; int dayEndHour = curDate < endDate ? 23 : endDT.Hour; for (int dayHour = dayStartHour; dayHour <= dayEndHour; dayHour++) { DateTime snapshotDT = curDate.AddHours(dayHour); SrezTableLight.Srez snapshot; tblHour.SrezList.TryGetValue(snapshotDT, out snapshot); double hour = (snapshotDT - date).TotalHours; if (modified) { AppendHourCnlData(hourCnlDataList, hour, cnlList, snapshot, snapshotDT, nowDT); } else { AppendEmptyHourCnlData(hourCnlDataList, hour); } } } curDate = nextDate; } dataAgeArr = newDataAgeArr; return(hourCnlDataList.ToArray()); }
/// <summary> /// �������� ����������������� �������� ������ �� �������� ��� �������� ����� �� ��������� ����� /// </summary> /// <remarks>��� �������� �������� hourTable ����� null ��� dataDT ����� DateTime.MinValue</remarks> public string GetCnlVal(SrezTableLight hourTable, int cnlNum, DateTime dateTime, bool showUnit, out string color) { // ��������� �������� � ������� ������ double val; int stat; if (dateTime == DateTime.MinValue || hourTable == null) GetCurData(cnlNum, out val, out stat); else GetHourData(hourTable, cnlNum, dateTime, out val, out stat); // �������������� �������� ������ bool isNumber; return FormatCnlVal(val, stat, GetCnlProps(cnlNum), showUnit, true, dateTime, DateTime.Now, out isNumber, out color); }
/// <summary> /// Выполнить действия после обработки новых архивных данных /// </summary> /// <remarks>Номера каналов упорядочены по возрастанию. /// Вычисление дорасчётных каналов архивного среза в момент вызова метода завершено</remarks> public virtual void OnArcDataProcessed(int[] cnlNums, SrezTableLight.Srez arcSrez) { }
/// <summary> /// Вычислить дорасчётные каналы /// </summary> private void CalcDRCnls(List<InCnl> inCnls, SrezTableLight.Srez srez, bool genEvents) { lock (calculator) { try { procSrez = srez; foreach (InCnl inCnl in inCnls) { int cnlInd = srez.GetCnlIndex(inCnl.CnlNum); if (cnlInd >= 0) { // вычисление новых данных входного канала SrezTableLight.CnlData oldCnlData = srez.CnlData[cnlInd]; SrezTableLight.CnlData newCnlData = new SrezTableLight.CnlData(oldCnlData.Val, BaseValues.CnlStatuses.Defined); CalcCnlData(inCnl, oldCnlData, ref newCnlData); // запись новых данных в срез srez.CnlData[cnlInd] = newCnlData; // генерация события if (genEvents) GenEvent(inCnl, oldCnlData, newCnlData); } } } catch (Exception ex) { AppLog.WriteAction((Localization.UseRussian ? "Ошибка при вычислении дорасчётных каналов: " : "Error calculating channels: ") + ex.Message, Log.ActTypes.Exception); } finally { procSrez = null; } } }
/// <summary> /// Обработать новые архивные данные /// </summary> public bool ProcArcData(SrezTableLight.Srez receivedSrez) { try { if (serverIsReady) { bool result = true; int cnlCnt = receivedSrez == null ? 0 : receivedSrez.CnlNums.Length; if (cnlCnt > 0) { // определение времени, на которое записывются архивные данные DateTime paramSrezDT = receivedSrez.DateTime; DateTime paramSrezDate = paramSrezDT.Date; DateTime nearestMinDT = CalcNearestTime(paramSrezDT, Settings.WriteMinPer); DateTime nearestHrDT = CalcNearestTime(paramSrezDT, Settings.WriteHrPer); // получение кэша таблиц срезов SrezTableCache minCache = Settings.WriteMin || Settings.WriteMinCopy ? GetSrezTableCache(paramSrezDate, SrezTypes.Min) : null; SrezTableCache hrCache = nearestHrDT == paramSrezDT && (Settings.WriteHr || Settings.WriteHrCopy) ? GetSrezTableCache(paramSrezDate, SrezTypes.Hour) : null; SrezTableLight.Srez arcSrez = null; // запись минутных данных if (minCache != null) { lock (minCache) { if (Settings.WriteMin && !WriteReceivedSrez(minCache.SrezTable, minCache.SrezAdapter, receivedSrez, nearestMinDT, ref arcSrez)) result = false; if (Settings.WriteMinCopy && !WriteReceivedSrez(minCache.SrezTableCopy, minCache.SrezCopyAdapter, receivedSrez, nearestMinDT, ref arcSrez)) result = false; } } // запись часовых данных if (hrCache != null) { lock (hrCache) { if (Settings.WriteHr && !WriteReceivedSrez(hrCache.SrezTable, hrCache.SrezAdapter, receivedSrez, nearestHrDT, ref arcSrez)) result = false; if (Settings.WriteHrCopy && !WriteReceivedSrez(hrCache.SrezTableCopy, hrCache.SrezCopyAdapter, receivedSrez, nearestHrDT, ref arcSrez)) result = false; } } // выполнение действий модулей RaiseOnArcDataProcessed(receivedSrez.CnlNums, arcSrez); } return result; } else { return false; } } catch (Exception ex) { AppLog.WriteAction((Localization.UseRussian ? "Ошибка при обработке новых архивных данных: " : "Error processing the new archive data: ") + ex.Message, Log.ActTypes.Exception); return false; } }
public override TaskStatus Run () { Info("Start RSSendValues task"); bool IsIndata = false; try { if(indata=="file") { foreach(FileInf fi in SelectFiles()) { SrezTableLight stl = new SrezTableLight (); sa.FileName = fi.Path; sa.Fill(stl); int id = int.Parse (fi.FileName.Split (new char[]{'.'},StringSplitOptions.RemoveEmptyEntries)[1]); stls.AddSrez(id,stl.SrezList.Values[0]); } IsIndata = true; } if (indata == "mem") { foreach(RSServer srv in srvs.GetRSServers()) { stls.AddSrez(srv.Id,srv.GetCurrSrez()); } IsIndata = true; } if(IsIndata) { foreach(Cnl cnl in Cnls) { Argument cArg = new Argument(cnl.ToString(),stls.GetCnlData(cnl.ID,cnl.Num)); CalcArgs.Add(cArg); } CalcArgs.AddRange(xArgs); List<Cnl> cnls = new List<Cnl>(); foreach(Argument arg in SendVals) { PrimitiveElement[] pes = CalcArgs.ToArray(); arg.addDefinitions(pes); Cnl cnl = new Cnl(arg.getArgumentName(),arg.getArgumentValue(),1); cnls.Add(cnl); arg.removeDefinitions(CalcArgs.ToArray()); } srvs.SendCurrSrez(cnls); } else{ Info("No set parametr indata"); } CalcArgs.Clear(); stls.ClearSrez(); } catch (ThreadAbortException) { throw; } catch (Exception ex) { InfoFormat ("An error RSSendValues: {0}", ex.Message); } Info("Task RSSendValues finished"); return new TaskStatus (Status.Success, false); }
/// <summary> /// Обработать новые текущие данные /// </summary> public bool ProcCurData(SrezTableLight.Srez receivedSrez) { lock (curSrez) lock (calculator) { try { if (serverIsReady) { procSrez = curSrez; int cnlCnt = receivedSrez == null ? 0 : receivedSrez.CnlNums.Length; for (int i = 0; i < cnlCnt; i++) { int cnlNum = receivedSrez.CnlNums[i]; int cnlInd = curSrez.GetCnlIndex(cnlNum); InCnl inCnl; if (inCnls.TryGetValue(cnlNum, out inCnl) && cnlInd >= 0) // входной канал существует { if (inCnl.CnlTypeID == BaseValues.CnlTypes.TS || inCnl.CnlTypeID == BaseValues.CnlTypes.TI) { // вычисление новых данных входного канала SrezTableLight.CnlData oldCnlData = curSrez.CnlData[cnlInd]; SrezTableLight.CnlData newCnlData = receivedSrez.CnlData[i]; CalcCnlData(inCnl, oldCnlData, ref newCnlData); // расчёт данных для усреднения if (inCnl.Averaging && newCnlData.Stat > BaseValues.CnlStatuses.Undefined && newCnlData.Stat != BaseValues.CnlStatuses.FormulaError && newCnlData.Stat != BaseValues.CnlStatuses.Unreliable) { minAvgData[cnlInd].Sum += newCnlData.Val; minAvgData[cnlInd].Cnt++; hrAvgData[cnlInd].Sum += newCnlData.Val; hrAvgData[cnlInd].Cnt++; } // запись новых данных в текущий срез curSrez.CnlData[cnlInd] = newCnlData; // генерация события GenEvent(inCnl, oldCnlData, newCnlData); // обновление информации об активности канала activeDTs[cnlInd] = DateTime.Now; } else if (inCnl.CnlTypeID != BaseValues.CnlTypes.TSDR && inCnl.CnlTypeID != BaseValues.CnlTypes.TIDR) { // запись новых данных минутных и часовых каналов, а также // количества переключений в текущий срез без вычислений curSrez.CnlData[cnlInd] = receivedSrez.CnlData[i]; } } } // выполнение действий модулей if (cnlCnt > 0) RaiseOnCurDataProcessed(receivedSrez.CnlNums, curSrez); return true; } else { return false; } } catch (Exception ex) { AppLog.WriteAction((Localization.UseRussian ? "Ошибка при обработке новых текущих данных: " : "Error processing the new current data: ") + ex.Message, Log.ActTypes.Exception); return false; } finally { procSrez = null; curSrezMod = true; } } }
/// <summary> /// Вычислить данные входного канала /// </summary> private void CalcCnlData(InCnl inCnl, SrezTableLight.CnlData oldCnlData, ref SrezTableLight.CnlData newCnlData) { if (inCnl != null) { try { // вычисление новых данных if (inCnl.CalcCnlData != null) inCnl.CalcCnlData(ref newCnlData); // увеличение счётчика количества переключений if (inCnl.CnlTypeID == BaseValues.CnlTypes.SWCNT && newCnlData.Stat > BaseValues.CnlStatuses.Undefined) { bool even = (int)oldCnlData.Val % 2 == 0; // старое значение чётное newCnlData.Val = newCnlData.Val < 0 && even || newCnlData.Val >= 0 && !even ? Math.Truncate(oldCnlData.Val) + 1 : Math.Truncate(oldCnlData.Val); } // корректировка нового статуса, если задана проверка границ значения if (newCnlData.Stat == BaseValues.CnlStatuses.Defined && (inCnl.LimLow < inCnl.LimHigh || inCnl.LimLowCrash < inCnl.LimHighCrash)) { newCnlData.Stat = BaseValues.CnlStatuses.Normal; if (inCnl.LimLow < inCnl.LimHigh) { if (newCnlData.Val < inCnl.LimLow) newCnlData.Stat = BaseValues.CnlStatuses.Low; else if (newCnlData.Val > inCnl.LimHigh) newCnlData.Stat = BaseValues.CnlStatuses.High; } if (inCnl.LimLowCrash < inCnl.LimHighCrash) { if (newCnlData.Val < inCnl.LimLowCrash) newCnlData.Stat = BaseValues.CnlStatuses.LowCrash; else if (newCnlData.Val > inCnl.LimHighCrash) newCnlData.Stat = BaseValues.CnlStatuses.HighCrash; } } } catch { newCnlData.Stat = BaseValues.CnlStatuses.FormulaError; } } }
/// <summary> /// Записать принятый срез в таблицу архивных срезов /// </summary> private bool WriteReceivedSrez(SrezTable srezTable, SrezAdapter srezAdapter, SrezTableLight.Srez receivedSrez, DateTime srezDT, ref SrezTableLight.Srez arcSrez) { string fileName = ""; try { // получение существующего или создание нового архивного среза fileName = srezAdapter.FileName; SrezTableCache.FillSrezTable(srezTable, srezAdapter); SrezTable.Srez srez = srezTable.GetSrez(srezDT); bool addSrez; if (srez == null) { srez = new SrezTable.Srez(srezDT, srezDescr, receivedSrez); addSrez = true; } else { addSrez = false; } if (arcSrez == null) arcSrez = srez; // изменение архивного среза lock (calculator) { try { procSrez = srez; int cntCnt = receivedSrez.CnlNums.Length; for (int i = 0; i < cntCnt; i++) { int cnlNum = receivedSrez.CnlNums[i]; int cnlInd = srez.GetCnlIndex(cnlNum); InCnl inCnl; if (inCnls.TryGetValue(cnlNum, out inCnl) && cnlInd >= 0 && (inCnl.CnlTypeID == BaseValues.CnlTypes.TS || inCnl.CnlTypeID == BaseValues.CnlTypes.TI)) { // вычисление новых данных входного канала SrezTableLight.CnlData oldCnlData = srez.CnlData[cnlInd]; SrezTableLight.CnlData newCnlData = receivedSrez.CnlData[i]; if (newCnlData.Stat == BaseValues.CnlStatuses.Defined) newCnlData.Stat = BaseValues.CnlStatuses.Archival; CalcCnlData(inCnl, oldCnlData, ref newCnlData); // запись новых данных в архивный срез srez.CnlData[cnlInd] = newCnlData; } } } finally { procSrez = null; } } // вычисление дорасчётных каналов CalcDRCnls(drCnls, srez, false); if (addSrez) srezTable.AddSrez(srez); else srezTable.MarkSrezAsModified(srez); // запись изменений таблицы срезов srezAdapter.Update(srezTable); srezTable.FileModTime = File.GetLastWriteTime(fileName); return true; } catch (Exception ex) { string fileNameStr = string.IsNullOrEmpty(fileName) ? "" : Environment.NewLine + (Localization.UseRussian ? "Имя файла: " : "Filename: ") + fileName; AppLog.WriteAction(string.Format(Localization.UseRussian ? "Ошибка при записи принятого среза в таблицу архивных срезов: {0}{1}" : "Error writing received snapshot in the archive data table: {0}{1}", ex.Message, fileNameStr), Log.ActTypes.Exception); return false; } }
/// <summary> /// �������� ������ ������ �������� ����� �� ��������� ������� ������ /// </summary> public void GetHourData(SrezTableLight hourTable, int cnlNum, DateTime dateTime, out double val, out int stat) { Monitor.Enter(cnlDataLock); val = 0.0; stat = 0; try { SrezTableLight.Srez srez; if (hourTable != null && hourTable.SrezList.TryGetValue(dateTime, out srez)) { SrezTableLight.CnlData cnlData; bool found = srez.GetCnlData(cnlNum, out cnlData); if (found) { val = cnlData.Val; stat = cnlData.Stat; } } } catch (Exception ex) { AppData.Log.WriteAction(string.Format(Localization.UseRussian ? "������ ��� ��������� ������ ������ {0} �������� �����: {1}" : "Error getting channel {0} hour data: {1}", cnlNum, ex.Message), Log.ActTypes.Exception); } finally { Monitor.Exit(cnlDataLock); } }