public IRpdMeterSystemInformation Build() { var rpdMeterInfo = new RpdMeterSystemInformationSimple(); var br = new AdvancedBinaryReader(_stream, false); rpdMeterInfo.Address = br.ReadByte(); rpdMeterInfo.Type = br.ReadByte(); rpdMeterInfo.Status = br.ReadByte(); rpdMeterInfo.LinkErrorCounter = br.ReadByte(); rpdMeterInfo.ChannelsMask = br.ReadUInt16(); rpdMeterInfo.ChannelsMaskFromMeter = br.ReadUInt16(); rpdMeterInfo.ChannelsCount = br.ReadByte(); rpdMeterInfo.ChannelsDumpedCount = br.ReadByte(); var channelsDumpRulesCodes = new byte[MaxChannels]; // 0 - unused, 1..47 - valid br.Read(channelsDumpRulesCodes, 0, MaxChannels); rpdMeterInfo.ChannelsDumpRulesCodes = channelsDumpRulesCodes; rpdMeterInfo.HigherReadedFaultNumber = br.ReadByte(); rpdMeterInfo.ReadedFaultsCount = br.ReadByte(); rpdMeterInfo.NumberOfFaultDumpsForMeter = br.ReadByte(); rpdMeterInfo.PageLine = br.ReadUInt32(); rpdMeterInfo.PageLinesCountPerFault = br.ReadUInt32(); rpdMeterInfo.Crc = br.ReadByte(); return(rpdMeterInfo); }
private static PsnPageNumberAndTime GetLastPageNumberWithGoodDate(PsnBinLogLocationInfo locationInfo, Func <byte[], PsnPageHeader> timeReceiveMethod) { using (var br = new AdvancedBinaryReader(File.OpenRead(locationInfo.PsnBinFileName), false)) { var extractor = PsnPageExtractorFactory.Extractor; var buf = new byte[extractor.PsnPageHeaderLength]; for (int i = locationInfo.LastPageIndex; i >= locationInfo.FirstPageIndex; --i) { try { br.BaseStream.Seek(extractor.PsnPageSize * i, SeekOrigin.Begin); br.Read(buf, 0, buf.Length); var header = timeReceiveMethod(buf); //PsnBinPageExtractor.GetHeaderFromRealDevice(buf); br.Close(); return(new PsnPageNumberAndTime(i, header.CreatedAt)); } catch { // в случае ошибки цикл продолжается, т.к. нужная страница не найдена } } } throw new Exception("Cannot find any dated page"); }
public void ReadFromStream(Stream stream) { var br = new AdvancedBinaryReader(stream, false); Address = br.ReadByte(); Type = br.ReadByte(); Status = br.ReadByte(); LinkErrorCounter = br.ReadByte(); ChannelsMask = br.ReadUInt16(); ChannelsMaskFromMeter = br.ReadUInt16(); ChannelsCount = br.ReadByte(); ChannelsDumpedCount = br.ReadByte(); br.Read(ChannelsDumpRulesCodes, 0, 16); HigherReadedFaultNumber = br.ReadByte(); ReadedFaultsCount = br.ReadByte(); NumberOfFaultDumpsForMeter = br.ReadByte(); PageLine = br.ReadUInt32(); PageLinesCountPerFault = br.ReadUInt32(); Crc = br.ReadByte(); }
/// <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> /// Прочитать информацию об аварии из бинарника вида AVR*.bin /// Переопределяет название аварии из бинарника /// Переопределяет время аварии /// Переопределяет FileHash /// Переопределяет BinFileInfo /// </summary> /// <param name="sourceFile">Путь к бинарнику</param> /// <returns>Результат операции</returns> public bool ReadInfoFromBinaryFile(FileInfo sourceFile) { //Log.Global.Info("Попытка чтения информации об аварии из файла: " + sourceFile.FullName); bool result = true; sourceFile.Refresh(); if (sourceFile.Exists) { //Log.Global.Info("Файл лога аварии существует"); using (var reader = new AdvancedBinaryReader(new FileStream(sourceFile.FullName, FileMode.Open, FileAccess.Read), false)) { long pagesCount = reader.BaseStream.Length / 2048; //Log.Global.Info("Количество страниц в файле = " + pagesCount); bool startPageFound = false; //int startPageIndex = 0; bool firstNonstartPageFound = false; for (long i = 0; i < pagesCount; ++i) { reader.BaseStream.Seek(i * 2048, SeekOrigin.Begin); byte firstPageByte = reader.ReadByte(); // считаем первый байт if (firstPageByte == 0x55) // заголовок найден! { //Log.Global.Info("Заголовочная страница найдена, её номер = " + i); startPageFound = true; HeaderPageIndex = i; // запомнить индекс страницы-заголовка аварии (но в реальности страниц может быть много!) // следующие 6 байт - дата (dd|MM|yy|HH|mm|ss) byte day = reader.ReadByte(); byte month = reader.ReadByte(); byte year = reader.ReadByte(); byte hour = reader.ReadByte(); byte minute = reader.ReadByte(); byte second = reader.ReadByte(); try { AccuredAt = new DateTime(2000 + year, month, day, hour, minute, second); // соберем байты в удобный вид } catch { //Log.Global.Info("Не удалось распарсить дату и время аварии из байт: " + year + " " + month + " " + day + " " + hour + " " + minute + " " + second); AccuredAt = DateTime.MinValue; } //Log.Global.Info("Дата аварии = " + AccuredAt.ToString("yyyy.MM.dd HH:mm:ss")); _faultNumberFromHeader = reader.ReadByte(); // прочитаем номер аварии (байт №8) _metersCount = reader.ReadByte(); // прочитаем число измерителей (байт №9) } else if (firstPageByte < 0x55) // Первую незаголовочную страницу нужно прочитать для получения настроек измерителя: { if (startPageFound) { firstNonstartPageFound = true; } //Log.Global.Info("Незаголовочная страница, её индекс=" + i + " RpdMeters.Count=" + RpdMeters.Count); reader.BaseStream.Seek(i * 2048, SeekOrigin.Begin); var pageRaw = new byte[2048]; reader.Read(pageRaw, 0, 2048); //считываем страницу var currentPage = new FaultArchivePage(pageRaw, this); // Считываем настройки всех измерителей: for (int j = 0; j < _metersCount; ++j) { var neededMeter = (RpdMeter)RpdMeters[j]; if (!neededMeter.SettingsReaded) { neededMeter.ReadSettings(currentPage); } } } if (startPageFound && firstNonstartPageFound) { break; } } if (startPageFound && firstNonstartPageFound) { //reader.BaseStream.Seek(startPageIndex * 2048, SeekOrigin.Begin); // После чтения информации по измерителям РПД необходимо вернуться в начало и прочитать текущие данные: var rpdCurrentData = new List <RpdChannelCurrentData>(); int rpdChannelCurrentDataOffset = 9; // В этом цикле считываем текущие данные каналов РПД, заодно на выходе получая позицию текущих данных ПСН for (int i = 0; i < _metersCount; ++i) { rpdChannelCurrentDataOffset += MeterHeaderCurrentDataRecordLength; foreach (RpdChannel ch in RpdMeters[i].Channels) { //Log.Global.Info("Channel=" + ch.Name + ".IsEnabled = " + ch.IsEnabled); if (ch.IsEnabled) { rpdChannelCurrentDataOffset += ChannelCurrentDataRecordLength; //Log.Global.Info("rpdChannelCurrentDataOffset = " + rpdChannelCurrentDataOffset); // Если настройки были прочитаны: // Нельзя выносить на верхний уровень, т.к. тогда не правильно отработает смещение rpdChannelCurrentDataOffset var neededMeter = (RpdMeter)RpdMeters[i]; if (neededMeter.Settings != null && neededMeter.SettingsReaded) { //Log.Global.Info(neededMeter.Name + " настроки были прочитаны"); reader.BaseStream.Seek(HeaderPageIndex * 2048 + rpdChannelCurrentDataOffset, SeekOrigin.Begin); var chT = neededMeter.Settings.Calibrations.Channels[ch.Number - 1]; var b1 = reader.ReadByte(); // По суте первый байт не нужен, но нужно сдвинуть текущее положение в файле на 1 байт var b2 = reader.ReadByte(); var b3 = reader.ReadByte(); //Log.Global.Info("b1 = " + b1); //Log.Global.Info("b2 = " + b2); //Log.Global.Info("b3 = " + b3); double channelCurrentValue = b2 + b3 * 256.0; //Log.Global.Info("ChCurrValue = " + channelCurrentValue); double modifiedCurValue = (channelCurrentValue - chT.Zero) * chT.Kkor * chT.Kper * 1.0; //Log.Global.Info("ResultValue = " + modifiedCurValue); rpdCurrentData.Add(new RpdChannelCurrentData(ch, modifiedCurValue)); } } } } int psnCurrentDataOffset = rpdChannelCurrentDataOffset; // На самом деле № позиции текущих данных ПСН определяется так: сумма числа разрешённых каналов рпд по каждому измерителю: //Log.Global.Info("Смещение текущих данных магистрали ПСН: psnCurrentDataOffset=" + psnCurrentDataOffset); var psnReasonRaw = new byte[FaultReason.PsnGaugesCount * FaultReason.PsnReplyMaxLength]; reader.BaseStream.Seek(HeaderPageIndex * 2048 + psnCurrentDataOffset, SeekOrigin.Begin); reader.Read(psnReasonRaw, 0, psnReasonRaw.Length); // TODO: whre to get PsnChannelSimple //Reason = new FaultReason(rpdCurrentData, PsnPagesParser.GetPsnCurrentData(psnReasonRaw, _deviceConfig)); reader.Close(); } else { reader.Close(); throw new Exception("Ошибка, не удалось найти начальную страницу или первую страницу с данными"); } //reader.Close(); FileHash = DTHasher.GetMD5Hash(sourceFile.FullName, string.Empty); BinFilePath = sourceFile; //this.Name = sourceFile.Name; // Имя исходного файла всегда корявое, UpdateName(); //Log.Global.Info("Информация об аварии {" + Name + "} успешно прочитана"); //Log.Global.Info(BinFilePath.FullName); //Log.Global.Info(Reason.ToString); } } else { result = false; //Log.Global.Info("Файл лога аварии не существует! result = " + result); } return(result); }
public ISystemConfiguration BuildConfiguration() { var sysconf = new SystemConfigurationSimple(); if (File.Exists(_fileName)) { var raw = File.ReadAllBytes(_fileName); if (raw.Length != FileSize) { throw new Exception("SYSCONF.BIN file size must be " + FileSize); } using (var br = new AdvancedBinaryReader(new MemoryStream(raw, false), false)) { //br.Read(sysconf.Raw, 0, sysconf.Raw.Length); br.BaseStream.Seek(0, SeekOrigin.Begin); //-----------------------------------------------------------0 (0) sysconf.DeviceAddress = br.ReadUInt16(); sysconf.NetAddress = (int)br.ReadUInt32(); var locomotiveAndSectionNumbers = br.ReadUInt16(); sysconf.LocomotiveNumber = locomotiveAndSectionNumbers & 0x7FFF; sysconf.SectionNumber = (locomotiveAndSectionNumbers & 0x8000) > 0 ? 2 : 1; //br.BaseStream.Seek(8, SeekOrigin.Begin); sysconf.FirmwareVersion = br.ReadUInt16(); sysconf.LastWrittenPageAddress = (int)br.ReadUInt32(); sysconf.LastReadedBlockAddress = br.ReadUInt16(); sysconf.BadBlocksCount = br.ReadUInt16(); sysconf.LastWrittenPageNumber = br.ReadUInt16(); sysconf.FirstWrittenAfterResetPageNumber = (int)br.ReadUInt32(); sysconf.PsnLogStartPageNumber = (int)br.ReadUInt32(); sysconf.ArrayDumpPsnStartPageNumber = (int)br.ReadUInt32(); sysconf.FatOffsetFromPageZero = (int)br.ReadUInt32(); sysconf.RpdPagesCountTransmittedToPsnLog = (int)br.ReadUInt32(); sysconf.ConfigurationByte = br.ReadByte(); //-----------------------------------------------------------1 (2048) br.BaseStream.Seek(2048, SeekOrigin.Begin); sysconf.FaultsCount = br.ReadByte(); var rpdLogInfos = new IRpdDataInformation[FaultLogTableRecordsMax]; var rpdLogInfoBuilder = new RpdDataInformationBuilderFromStream(br.BaseStream); for (int i = 0; i < FaultLogTableRecordsMax; ++i) { rpdLogInfos[i] = rpdLogInfoBuilder.Build(); } sysconf.FaultDumpsTable = rpdLogInfos; //-----------------------------------------------------------2 (4096) br.BaseStream.Seek(4096, SeekOrigin.Begin); sysconf.MetersCount = br.ReadByte(); var rpdMeters = new IRpdMeterSystemInformation[MetersTableRecordsMax]; var rpdMeterInfoBuilder = new RpdMeterSystemInformationBuilderFromStream(br.BaseStream); for (int i = 0; i < MetersTableRecordsMax; ++i) { rpdMeters[i] = rpdMeterInfoBuilder.Build(); } sysconf.MetersTable = rpdMeters; //4096 + 1217: br.BaseStream.Seek(4096 + 1217, SeekOrigin.Begin); // установим необходимое смещение var psnRegisterStatusMasks = new byte[PsnRegisterStatusMasksMax]; br.Read(psnRegisterStatusMasks, 0, PsnRegisterStatusMasksMax); sysconf.PsnRegisterStatusMasks = psnRegisterStatusMasks; //4096 + 1238: br.BaseStream.Seek(4096 + 1238, SeekOrigin.Begin); // установим необходимое смещение var dumpRules = new IRpdDumpRule[DumpRulesMax]; var rpdDumpRulesBuilder = new RpdDumpRuleBuilderFromStream(br.BaseStream); for (int i = 0; i < DumpRulesMax; ++i) { dumpRules[i] = rpdDumpRulesBuilder.Build(); } sysconf.DumpRules = dumpRules; //------------------------------------------------------------3 (6144) const int offsetPage3 = 6144; const int offsetPowerOnStartPages = offsetPage3 + 2; const int offsetFixedStartPages = offsetPage3 + 500; br.BaseStream.Seek(offsetPage3, SeekOrigin.Begin); sysconf.CurrentPsnLogNumber = br.ReadUInt16(); br.BaseStream.Seek(offsetPowerOnStartPages, SeekOrigin.Begin); var powerOnOffsetInfos = new List <IPsnDataFragmentInformation>(); var psnLogFragmentInfoBuilder = new PsnDataFragmentInformationBuilderFromStream(br.BaseStream); for (int i = 0; i < PsnLogPowerOnStartPagesMaxCount; ++i) { var psnLogFragmentInfo = psnLogFragmentInfoBuilder.Build(); if (psnLogFragmentInfo.StartOffset >= sysconf.PsnLogStartPageNumber) { powerOnOffsetInfos.Add(psnLogFragmentInfo); } } // —писок инвертируетс¤, т.к. перед записью элементы таблицы смещаютс¤ и последний элемент оказываетс¤ в начале таблицы powerOnOffsetInfos.Reverse(); sysconf.PsnLogPowerUpFragmentInfos = powerOnOffsetInfos; br.BaseStream.Seek(offsetFixedStartPages, SeekOrigin.Begin); // „итаем фиксированные смещени¤: var predefinedFragmentInfos = new List <IPsnDataFragmentInformation>(); for (int i = 0; i < PsnPredefinedFragmentStartInfosMaxCount; ++i) { predefinedFragmentInfos.Add(psnLogFragmentInfoBuilder.Build()); } sysconf.PsnLogPredefinedFragmentInfos = predefinedFragmentInfos; br.BaseStream.Close(); } return(sysconf); } throw new Exception("Cannot find binary file, file " + _fileName + " is not exist"); }