/// <summary> /// Прочитать тренд из бинарника /// </summary> /// <param name="channel">Канал, для которого грузится тренд</param> public ReadChannelTrendResult ReadChannelTrendFromBinaryFile(/*string filePath,*/ RpdChannel channel) { var result = new ReadChannelTrendResult { Result = ((RpdMeter)channel.OwnerMeter).CloneAndLinkWithFault(null) }; // Запишем в результат измеритель (родитель для channel) result.Result.Channels.Clear(); //каналы тоже склонировались!!1 result.Result.Channels.Add(channel.CloneAndLinkWithMeter(result.Result)); //добавим результирующему измерителю канал try { result.Result.Channels[0].Trend.Clear(); //очистим тренд канала, вдруг там что-то есть! //using (AdvancedBinaryReader reader = new AdvancedBinaryReader(new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read), false)) using (var reader = new AdvancedBinaryReader(new FileStream(BinFilePath.FullName, FileMode.Open, FileAccess.Read), false)) { // запомним количество страниц в файле long pagesCount = reader.BaseStream.Length / 2048; // постраничное перемещение i int timePosition = 0; for (long i = 0; i < pagesCount; ++i) { try { var pageRaw = new byte[2048]; //ряд байтов, представляющих собой страницу reader.Read(pageRaw, 0, 2048); //считываем страницу // тут не надо проверять псн! // && pageRaw[0] != 0x80) //если это не заголовок аварии и не данные по ПСН (по идее заголовок - это >= 0x55) fixed if (pageRaw[0] < 0x55) { int meterAddrFromPage = pageRaw[0]; //номер/адрес измерителя хранится в первом байте страницы if (meterAddrFromPage == result.Result.Channels[0].OwnerMeter.Address) //если страница принадлежит нужному измерителю, то: { var currentPage = new FaultArchivePage(pageRaw, this); //сформируем страницу как объект var neededMeter = (RpdMeter)result.Result.Channels[0].OwnerMeter; //если настройки не считаны - считываем: if (!neededMeter.SettingsReaded) { neededMeter.ReadSettings(currentPage); // Настройки измерителя хранятся в первой послезаголовочной странице ( TODO: а если это измеритель № 10 и его настройки не влезли в первую послезаголовочную страницу?) } // В любом случае удаляем информационные строки с настройками по измерителю RemoveMeterSettingLines(currentPage); // Зачем пытаться удалять то, чего возможно и нет? (не лучше ли будет перенести под условие if (!neededMeter.SettingsReaded) // Не лучше, т.к. нужно в люом случае проверять строки на нулевой номер (вдруг в системе куча измерителей? и т.п.) // Можно не удалять, а работать только со строками, номер которых больше нуля (нулевые - это строки настроек измерителей) // Теперь необходимо прочесать строки и найти строки для нашего канала foreach (VariableLengthPageLine currentLine in currentPage.Lines) { if (currentLine.ChannelNumber + 1 == result.Result.Channels[0].Number) //ввбираем строки для нужного канала { foreach (int val in currentLine.Values) { ChannelCalibration chT = neededMeter.Settings.Calibrations.Channels[result.Result.Channels[0].Number - 1]; //формула вычисления значения с учетом настроек измерителя: (см. ТЗ) var point = new DataPointSimple((val - chT.Zero) * chT.Kkor * chT.Kper * 1.0, AccuredAt.AddTicks((long)(timePosition * (10000000.0 / neededMeter.Settings.Time) - neededMeter.TrendsTimeOffset * 10)), true, 0, null); // TODO result.Result.Channels[0].Trend.Add(point); // *10 is microseconds in ticks//timePosition * 25 - neededMeter.TrendsTimeOffset)); timePosition++; } //else пропускаем, такого канала в системе нету :( } } } } } catch { // TODO: remove empty catch } } //sw.Close();//DEBUG reader.Close(); //ридер нужно закрыть } } catch // (Exception ex) { result = null; } return(result); }
/// <summary> /// Создаёт новый экземпляр класса /// </summary> /// <param name="channel">Ассоциируемый канал</param> /// <param name="data">Данные канала</param> public RpdChannelCurrentData(RpdChannel channel, double data) { _channel = channel; Data = data; }