Ejemplo n.º 1
0
        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);
        }
        public IPsnDataFragmentInformation Build()
        {
            var br         = new AdvancedBinaryReader(_stream, false);
            var pageOffset = br.ReadUInt32();             // Номер страницы

            // 6 байт даты, если она была известна к началу фрагмента:
            var day   = br.ReadByte();
            var month = br.ReadByte();
            var year  = 2000 + br.ReadByte();

            var hour   = br.ReadByte();
            var minute = br.ReadByte();
            var second = br.ReadByte();

            DateTime?time;

            try {
                time = new DateTime(year, month, day, hour, minute, second);
            }
            catch {
                time = null;
            }

            return(new PsnDataFragmentInformationSimple {
                StartOffset = (int)pageOffset, StartTime = time
            });
        }
Ejemplo n.º 3
0
        public static List <PsnBinLogAdvancedLocationInfo> ApplyAdvancedFragmentationFixed(string fileName, IList <IPsnPagesLocationInfo> psnLogFragmentInfos)
        {
            var resultLocations = new List <PsnBinLogAdvancedLocationInfo>();
            var extractor       = PsnPageExtractorFactory.Extractor;

            using (var br = new AdvancedBinaryReader(File.OpenRead(fileName), false)) {
                // Сперва выбираем фрагменты с хорошими первыми страницами:
                foreach (var locationInfo in psnLogFragmentInfos)
                {
                    try {
                        br.BaseStream.Seek(extractor.PsnPageSize * locationInfo.PagesInterval.Begin, SeekOrigin.Begin);
                        var firstPageHeaderBytes = br.ReadBytes(extractor.PsnPageHeaderLength);

                        br.BaseStream.Seek(extractor.PsnPageSize * locationInfo.PagesInterval.End, SeekOrigin.Begin);
                        var lastPageHeaderBytes = br.ReadBytes(extractor.PsnPageHeaderLength);


                        var firstHeader = extractor.GetHeaderFromRealDevice(firstPageHeaderBytes);
                        var lastHeader  = extractor.GetHeaderFromRealDevice(lastPageHeaderBytes);

                        if (firstHeader.PageInfo == PsnPageInfo.NormalPage && lastHeader.PageInfo == PsnPageInfo.NormalPage)
                        {
                            if (locationInfo.TimesInterval.Begin.HasValue && firstHeader.CreatedAt.HasValue)
                            {
                                //if (locationInfo.TimesInterval.Begin.Value.EqualToEvenSecond(firstHeader.CreatedAt.Value)) {
                                if (lastHeader.CreatedAt.HasValue)
                                {
                                    if (lastHeader.CreatedAt.Value > firstHeader.CreatedAt.Value)
                                    {
                                        resultLocations.Add(
                                            new PsnBinLogAdvancedLocationInfo(
                                                fileName,
                                                new PsnPageNumberAndTime(locationInfo.PagesInterval.Begin, firstHeader.CreatedAt.Value),
                                                new PsnPageNumberAndTime(locationInfo.PagesInterval.End, lastHeader.CreatedAt.Value)));
                                    }
                                }
                            }
                        }
                    }
                    catch {
                        // TODO: remove empty catch;
                    }
                }
                // Сортировка фрагментов по дате и указание последней записи
                if (resultLocations.Count > 1)
                {
                    var orderedLocations = resultLocations.OrderBy(loc => loc.FirstPageInfo.Time.Value).ToList();
                    var lastLocation     = orderedLocations.Last();
                    orderedLocations.RemoveAt(orderedLocations.Count - 1);
                    orderedLocations.Add(new PsnBinLogAdvancedLocationInfo(fileName, lastLocation.FirstPageInfo, lastLocation.LastPageInfo)
                    {
                        IsLastPsnLogOnDevice = true
                    });
                    resultLocations = orderedLocations;
                }

                return(resultLocations);
            }
        }
Ejemplo n.º 4
0
        public void ReadFromStream(Stream stream)
        {
            var br = new AdvancedBinaryReader(stream, false);

            Type         = br.ReadByte();
            ControlValue = br.ReadInt16();
            MaxValue     = br.ReadInt16();
            MinValue     = br.ReadInt16();
        }
Ejemplo n.º 5
0
        public IRpdDumpRule Build()
        {
            var rule = new RpdDumpRuleSimple();
            var br   = new AdvancedBinaryReader(_stream, false);

            rule.Type         = br.ReadByte();
            rule.ControlValue = br.ReadInt16();
            rule.MaxValue     = br.ReadInt16();
            rule.MinValue     = br.ReadInt16();
            return(rule);
        }
Ejemplo n.º 6
0
        public void ReadFromStream(Stream stream)
        {
            var br = new AdvancedBinaryReader(stream, false);

            Number = br.ReadByte();
            Status = br.ReadByte();
            Day    = br.ReadByte();
            Month  = br.ReadByte();
            Year   = br.ReadByte();
            Hour   = br.ReadByte();
            Minute = br.ReadByte();
            Second = br.ReadByte();

            DescriptionPageAddress = br.ReadInt32();
            LastWrittenPageAddress = br.ReadInt32();

            FaultWasReaded = br.ReadByte();
            BadPageCounter = br.ReadInt16();
        }
Ejemplo n.º 7
0
 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 IRpdDataInformation Build()
        {
            var rpdLogInfo = new RpdDataInformationSimple();

            var br = new AdvancedBinaryReader(_stream, false);

            rpdLogInfo.Number = br.ReadByte();
            rpdLogInfo.Status = br.ReadByte();
            rpdLogInfo.Day    = br.ReadByte();
            rpdLogInfo.Month  = br.ReadByte();
            rpdLogInfo.Year   = br.ReadByte();
            rpdLogInfo.Hour   = br.ReadByte();
            rpdLogInfo.Minute = br.ReadByte();
            rpdLogInfo.Second = br.ReadByte();

            rpdLogInfo.DescriptionPageAddress = br.ReadInt32();
            rpdLogInfo.LastWrittenPageAddress = br.ReadInt32();

            rpdLogInfo.FaultWasReaded = br.ReadByte();
            rpdLogInfo.BadPageCounter = br.ReadInt16();
            return(rpdLogInfo);
        }
Ejemplo n.º 9
0
        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();
        }
Ejemplo n.º 10
0
        /// <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);
        }
Ejemplo n.º 11
0
        /// <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 ICommandConfiguration BuildConfiguration()
        {
            // PERFOMANCE INCREASE POSSIBILITY: need fastest work with stream, closing it, then filling fields and vars
            using (var br = new AdvancedBinaryReader(File.OpenRead(_filename), false)) {
                br.BaseStream.Seek(2048, SeekOrigin.Begin);
                var memoryStatusByte = br.ReadByte();
                var configStatusByte = br.ReadByte();

                var verificationStatusBytes = br.ReadBytes(32);

                var meterChannelConfigVerificationStatuses = new List <IMetersChannelsConfigurationVerificationStatus>();
                for (int i = 0; i < verificationStatusBytes.Length; ++i)
                {
                    var status = verificationStatusBytes[i];
                    ChannelConfigVerificationStatus st;
                    switch (status)
                    {
                    case 0:
                        st = ChannelConfigVerificationStatus.NoMeterFoundInTable;
                        break;

                    case 1:
                        st = ChannelConfigVerificationStatus.VerificationSuccess;
                        break;

                    case 2:
                        st = ChannelConfigVerificationStatus.ErrorDuringConfigurationWriting;
                        break;

                    case 3:
                        st = ChannelConfigVerificationStatus.NoLinkWithMeter;
                        break;

                    case 4:
                        st = ChannelConfigVerificationStatus.VerificationInProgress;
                        break;

                    default:
                        st = ChannelConfigVerificationStatus.Unknown;
                        break;
                    }
                    meterChannelConfigVerificationStatuses.Add(new MetersChannelsConfigurationVerificationStatusSimple(i, st));
                }
                br.ReadByte();
                var second = br.ReadByte();
                var minute = br.ReadByte();
                var hour   = br.ReadByte();
                var day    = br.ReadByte();
                var month  = br.ReadByte();
                var year   = br.ReadByte();

                DateTime?dateTime;
                try {
                    dateTime = new DateTime(2000 + year, month, day, hour, minute, second);
                }
                catch {
                    dateTime = null;
                }

                var psnProtocolType = br.ReadUInt16();

                return(new CommandConfigurationSimple(
                           dateTime,
                           (memoryStatusByte & 0x01) == 0x01,
                           (memoryStatusByte & 0x02) == 0x02,
                           (memoryStatusByte & 0x04) == 0x04,
                           (memoryStatusByte & 0x08) == 0x08,

                           (configStatusByte & 0x01) == 0x01,
                           (configStatusByte & 0x02) == 0x02,
                           (configStatusByte & 0x04) == 0x04,
                           (configStatusByte & 0x08) == 0x08,
                           (configStatusByte & 0x10) == 0x10,
                           (configStatusByte & 0x20) == 0x20,
                           (configStatusByte & 0x40) == 0x40,

                           meterChannelConfigVerificationStatuses,
                           psnProtocolType
                           ));
            }
        }
        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");
        }