Ejemplo n.º 1
0
        public void GetTrackSectorByMousePosition(int x, int y, out int track, out int sectorIndex)
        {
            track = x >= 0 ? x / CellWidth : -1;
            if (track > MaxTrack)
            {
                track = MaxTrack;
            }
            sectorIndex = -1;
            if (track < 0 || Image == null || track >= Image.Tracks.Cnt || y < headerHeight)
            {
                return;
            }
            TrackFormat tf = Image?.Tracks[track];

            if (tf == null || tf.Layout.Cnt == 0)
            {
                return;
            }
            int position = y - headerHeight;

            for (int i = 0; i < tf.Layout.Cnt; i++)
            {
                if (position >= tf.Layout.Data[i].MapPoint1 && position < tf.Layout.Data[i].MapPoint2)
                {
                    sectorIndex = i;
                    return;
                }
            }
            return;
        }
Ejemplo n.º 2
0
        public unsafe void AssignLayout(TrackFormat layout, int track, int syncSectorNumber = int.MinValue, int firstIndex = 0)
        {
            int minSectorIndex  = 0;
            int minSectorNumber = int.MaxValue;

            for (int i = firstIndex; i < layout.Layout.Cnt; i++)
            {
                if (layout.Layout.Data[i].SectorNumber < minSectorNumber)
                {
                    minSectorNumber = layout.Layout.Data[i].SectorNumber;
                    minSectorIndex  = i;
                }
            }
            int len = Math.Max(0, layout.Layout.Cnt - firstIndex);

            Layout.EnsureCapacity(len);
            Layout.Cnt = len;
            for (int i = 0, j = minSectorIndex; i < len; i++)
            {
                Layout.Data[i] = layout.Layout.Data[j];
                if (syncSectorNumber != int.MinValue && Layout.Data[i].SectorNumber == syncSectorNumber)
                {
                    SyncByHeader(track, syncSectorNumber);
                }
                j++;
                if (j >= layout.Layout.Cnt)
                {
                    j = firstIndex;
                }
            }
            FormatName  = GetFormatName();
            SpinTime    = GetSpinTime();
            LayoutTrack = track;
        }
Ejemplo n.º 3
0
        public object Clone()
        {
            TrackFormat r = (TrackFormat)MemberwiseClone();

            r.Layout = new MList <SectorInfo>(Layout, true, false);
            r.Timer  = (Timer)Timer.Clone();
            return(r);
        }
Ejemplo n.º 4
0
 public void WriteNoHeader(IntPtr memoryHandle, TrackFormat trackF, int sectorIndex)
 {
     trackF.Layout.Data[sectorIndex].WriteData(memoryHandle);
     trackF.Layout.Data[sectorIndex].ProcessResult = SectorProcessResult.NoHeader;
     Modified = true;
     // %%% Здесь должен быть вызов Map и функции SectorsChanged(sectorNum, sectorCount);
     trackF.Layout.Data[sectorIndex].MapCellValue = MapCell.NoHeader;    // это наверное надо перенести в Map.
     trackF.MapModified = true;
 }
Ejemplo n.º 5
0
        public void UnmarkTrack(int track, MapCell mask)
        {
            TrackFormat tf = Image.Tracks.Data[track];

            for (int i = 0; i < tf.Layout.Cnt; i++)
            {
                tf.Layout.Data[i].MapCellValue &= ~mask;
            }
            tf.MapModified = true;
        }
Ejemplo n.º 6
0
 public void Assign(TrackFormat source)
 {
     Layout.CopyArray(source.Layout);
     Timer.Assign(source.Timer);
     LayoutTrack     = source.LayoutTrack;
     LongSectorIndex = source.LongSectorIndex;
     syncSectorIndex = source.syncSectorIndex;
     syncTrack       = source.syncTrack;
     SpinTime        = source.SpinTime;
     FormatName      = source.FormatName;
 }
Ejemplo n.º 7
0
 public bool ContainsOtherSectors(TrackFormat trackFormat, int cylinder)
 {
     for (int i = 0; i < Layout.Cnt; i++)
     {
         int index = trackFormat.FindSectorIndex(Layout.Data[i].SectorNumber);
         if ((index < 0) ||
             (cylinder >= 0 && Layout.Data[i].Cylinder != cylinder))
         {
             return(true);
         }
     }
     return(false);
 }
Ejemplo n.º 8
0
 public void MarkSectorRange(int firstTrack, int lastTrack, SectorProcessResult processResult, MapCell mapCell)
 {
     for (int i = firstTrack; i < lastTrack; i++)
     {
         TrackFormat tf = Tracks[i];
         for (int j = 0; j < tf.Layout.Cnt; j++)
         {
             tf.Layout.Data[j].ProcessResult = processResult;
             tf.Layout.Data[j].MapCellValue  = mapCell;
         }
         tf.MapModified = true;
     }
     Modified = true;
 }
Ejemplo n.º 9
0
 public bool ContainsSectorsFrom(TrackFormat trackFormat, int cylinder)
 {
     for (int i = 0; i < Layout.Cnt; i++)
     {
         int index = trackFormat.FindSectorIndex(Layout.Data[i].SectorNumber);
         if (index >= 0 &&
             Layout.Data[i].SizeCode == trackFormat.Layout.Data[index].SizeCode &&
             (cylinder < 0 || Layout.Data[i].Cylinder == cylinder))
         {
             return(true);
         }
     }
     return(false);
 }
Ejemplo n.º 10
0
 public void WriteGoodSector(IntPtr memoryHandle, TrackFormat trackF, int sectorIndex)
 {
     trackF.Layout.Data[sectorIndex].WriteData(memoryHandle);
     trackF.Layout.Data[sectorIndex].ProcessResult = SectorProcessResult.Good;
     Modified = true;
     // %%% Здесь должен быть вызов Map и функции SectorsChanged(sectorNum, sectorCount);
     if (DiskImage.AllBytes(trackF.Layout.Data[sectorIndex].Data, 0, trackF.Layout.Data[sectorIndex].SizeBytes, 0))
     {
         trackF.Layout.Data[sectorIndex].MapCellValue = MapCell.Zero;
     }
     else
     {
         trackF.Layout.Data[sectorIndex].MapCellValue = MapCell.Good;    // это наверное надо перенести в Map.
     }
     trackF.MapModified = true;
 }
Ejemplo n.º 11
0
        /// <summary>
        /// Синхронизация сектора с другим объектом TrackFormat.
        /// </summary>
        /// <param name="trackFormat"></param>
        public void Sync(TrackFormat trackFormat)
        {
            if (trackFormat == null || trackFormat.Layout.Cnt == 0)
            {
                return;
            }
            int sectorNum    = trackFormat.Layout.Data[trackFormat.syncSectorIndex].SectorNumber;
            int newSyncIndex = FindSectorIndex(sectorNum);

            if (newSyncIndex < 0)
            {
                return;
            }
            Timer.Assign(trackFormat.Timer);
            syncSectorIndex = newSyncIndex;
            syncTrack       = trackFormat.syncTrack;
        }
Ejemplo n.º 12
0
 private void ChartArea_MouseDown(object sender, MouseEventArgs e)
 {
     GetTrackSectorByMousePosition(e.X, e.Y, out track, out sectorIndex);
     if (e.Button == MouseButtons.Right)
     {
         ClearHighlight(MapCell.Highlighted | MapCell.Hover);
         TrackFormat tf             = Image.Tracks.Data[track];
         bool        sectorSelected = sectorIndex >= 0 && sectorIndex < tf.Layout.Cnt && track >= 0 && track < MainForm.MaxTrack;
         if (sectorSelected)
         {
             tf.Layout.Data[sectorIndex].MapCellValue |= MapCell.Hover;
             tf.MapModified = true;
             int diskSector = tf.Layout.Data[sectorIndex].SectorNumber;
             contextMenuTopItem.Text = $"Track: {track} Sector: {diskSector}";
         }
         else
         {
             contextMenuTopItem.Text = $"Track: {track}";
         }
         markAsUnprocessed.Enabled  = sectorSelected;
         markAsGood.Enabled         = sectorSelected;
         viewSectorContents.Enabled = sectorSelected && (tf[sectorIndex].ProcessResult == SectorProcessResult.Good || tf[sectorIndex].ProcessResult == SectorProcessResult.Bad);
         Repaint();
         mapMouseLeaveIgnore = true;
         contextMenu.Show(ChartArea, new Point(e.X, e.Y));
         return;
     }
     if (e.Button != MouseButtons.Left)
     {
         return;
     }
     ClearHighlight();
     if (CanEditReadBounds)
     {
         selecting = true;
     }
     ChartArea_MouseMove(sender, e);
 }
Ejemplo n.º 13
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="result">0 - head определен. 1 - Заголовки не найдены. 2 - Заголовок найден, но он не TR-DOS</param>
        /// <param name="track"></param>
        /// <param name="trackFormat"></param>
        /// <returns></returns>
        private int ScanHeadParameter(ref UpperSideHead result, int track, TrackFormat trackFormat)
        {
            tagFD_READ_ID_PARAMS pars = new tagFD_READ_ID_PARAMS()
            {
                flags = Driver.FD_OPTION_MFM,
                head  = (byte)(track & 1)
            };
            tagFD_CMD_RESULT cmdResult = new tagFD_CMD_RESULT();

            if (!Driver.ReadId(DriverHandle, pars, out cmdResult))
            {
                Log.Trace?.Out($"Функция ReadId вернула false. Cylinder: {cmdResult.cyl} | Sector: {cmdResult.sector} | Size: {cmdResult.size} | Head: {cmdResult.head} | LastError: {Marshal.GetLastWin32Error()}");
                return(1);
            }
            //if (cmdResult.sector < 1 || cmdResult.sector > 16 || cmdResult.size != 1)
            //{
            //    Log.Trace?.Out($"Формат не TR-DOS. Cylinder: {cmdResult.cyl} | Sector: {cmdResult.sector} | Size: {cmdResult.size} | Head: {cmdResult.head}");
            //    return 2;
            //}
            trackFormat.SyncByHeader(track, cmdResult.sector);
            Log.Trace?.Out($"Cylinder: {cmdResult.cyl} | Sector: {cmdResult.sector} | Size: {cmdResult.size} | Head: {cmdResult.head}");
            result = (UpperSideHead)cmdResult.head;
            return(0);
        }
Ejemplo n.º 14
0
        public unsafe int ReadRandomSectors(TimeSpan timeout, int stopOnNthFail = 0)
        {
            int goodSectors = Params.Image.GoodSectors;
            int imageTracks = Params.Image.SizeTracks;

            try
            {
                bool          useTimeout  = timeout > TimeSpan.Zero;
                DateTime      timeoutTime = DateTime.Now.Add(timeout);
                Timer         sectorTimer = new Timer();
                Random        random      = new Random();
                MList <Point> sectorArray = new MList <Point>(Params.Image.SizeSectors);
                for (int track = Params.FirstTrack; track < Params.LastTrack; track++)
                {
                    if (Params.Side == DiskSide.Side0 && track % 2 != 0)
                    {
                        continue;
                    }
                    if (Params.Side == DiskSide.Side1 && track % 2 != 1)
                    {
                        continue;
                    }
                    for (int sector = 0; sector < Params.Image[track].Layout.Cnt; sector++)
                    {
                        if (Params.Image[track][sector].ProcessResult != SectorProcessResult.Good)
                        {
                            sectorArray.Add(new Point(track, sector));
                        }
                    }
                }
                int prevCylinder = -1;
                int failCounter  = 0;
                while (sectorArray.Cnt > 0 && ((useTimeout && DateTime.Now < timeoutTime) || !useTimeout) && (stopOnNthFail == 0 || (failCounter < stopOnNthFail)))
                {
                    int         index       = random.Next(sectorArray.Cnt);
                    int         track       = sectorArray[index].X;
                    int         sectorIndex = sectorArray[index].Y;
                    SectorInfo  sector      = Params.Image[track][sectorIndex];
                    TrackFormat tf          = Params.Image[track];
                    int         error       = 23;
                    Params.Map.MarkSectorAsProcessing(track, sectorIndex);
                    bool badWritten = sector.ProcessResult == SectorProcessResult.Bad;
                    for (int attempt = 0; attempt < Params.SectorReadAttempts; attempt++)
                    {
                        if (Aborted)
                        {
                            goto abort;
                        }
                        int cylinder = track / 2;
                        if (cylinder == prevCylinder)
                        {
                            int tempCylinder = cylinder + (random.Next(2) == 0 ? -1 : 1);
                            tempCylinder = Math.Max(0, tempCylinder);
                            tempCylinder = Math.Min(tempCylinder, Params.LastTrack / 2);
                            Driver.Seek(DriverHandle, tempCylinder * 2);
                            if (Aborted)
                            {
                                goto abort;
                            }
                            Thread.Sleep(random.Next((int)TrackFormat.SpinTimeStandard)); // Ждем случайное время чтобы приехать на нужный цилиндр в случайной точке.
                        }
                        prevCylinder = cylinder;
                        Driver.Seek(DriverHandle, track);
                        if (Aborted)
                        {
                            goto abort;
                        }
                        WinApi.RtlZeroMemory(memoryHandle, (UIntPtr)sector.SizeBytes);
                        sectorTimer.Start();
                        error = Driver.ReadSectorF(DriverHandle, memoryHandle, sector.Cylinder, sector.SectorNumber, sector.SizeCode, track & 1, sector.Head, 0x0a, 0xff);
                        sectorTimer.Stop();
                        if (error == 0)
                        {
                            Params.Image.WriteGoodSector(memoryHandle, tf, sectorIndex);
                            sectorArray.RemoveAt(index);
                            failCounter = 0;
                            timeoutTime = DateTime.Now.Add(timeout);
                            break;
                        }
                        // Ошибка 27 может быть как в случае отсутствия заголовка, так и в случае когда заголовок имеет ошибку CRC.
                        // Тут сложный вопрос что с этим делать: писать сектор как CrcError или как NoHeader. Пишется как NoHeader.
                        // (проверить была ошибка CRC в заголовке или заголовок вообще не был найден можно сравнив sectorTimer.ElapsedMs с временем вращения tf.SpinTime)
                        bool noHeader = error == 21 || error == 1112 || error == 27;
                        Make30HeadPositionings(error, track);
                        if (error == 23)
                        {
                            Params.Image.WriteBadSector(memoryHandle, tf, sectorIndex);
                            badWritten = true;
                        }
                        else if (noHeader && !badWritten)
                        {
                            Params.Image.WriteNoHeader(memoryHandle, tf, sectorIndex);
                        }
                    }
                    failCounter++;
                }
                return(Params.Image.GoodSectors - goodSectors);

abort:
                Log.Info?.Out("Чтение прервано.");
            }
            finally
            {
                Params.Map?.ClearHighlight(MapCell.Processing);
            }
            return(Params.Image.GoodSectors - goodSectors);
        }
Ejemplo n.º 15
0
        private void ChartArea_MouseMove(object sender, MouseEventArgs e)
        {
            if (Image == null)
            {
                return;
            }
            int track;
            int sectorIndex;

            GetTrackSectorByMousePosition(e.X, e.Y, out track, out sectorIndex);
            TrackFormat tf = (track >= 0 && track < Image.Tracks.Cnt) ? Image.Tracks[track] : null;

            if (selecting)
            {
                int minTrack = Math.Min(track, this.track);
                minTrack = Math.Max(0, minTrack);
                int maxTrack = Math.Max(track, this.track);
                maxTrack = Math.Min(maxTrack, MainForm.MaxTrack);
                if (maxTrack == minTrack)
                {
                    maxTrack++;
                }
                if (maxTrack > MainForm.MaxTrack)
                {
                    maxTrack--;
                    minTrack--;
                    if (minTrack < 0)
                    {
                        minTrack = 0;
                    }
                }
                Select(minTrack, maxTrack);
                ReadBoundsChanged?.Invoke(this, null);
            }
            TrackLV.Text = track.ToString();
            if (sectorIndex >= 0)
            {
                int diskSector = tf.Layout.Data[sectorIndex].SectorNumber;
                SectorLV.Text     = diskSector.ToString();
                StatusLV.Text     = tf.Layout.Data[sectorIndex].ProcessResult.ToString();
                SectorSizeLV.Text = tf.Layout.Data[sectorIndex].SizeBytes.ToString();
                CylLV.Text        = tf.Layout.Data[sectorIndex].Cylinder.ToString();
                HeadLV.Text       = tf.Layout.Data[sectorIndex].Head.ToString();
                if (!selecting)
                {
                    ClearHighlight(MapCell.Highlighted | MapCell.Hover);
                    tf.Layout.Data[sectorIndex].MapCellValue |= MapCell.Hover;
                    tf.MapModified = true;
                }
            }
            else
            {
                if (track >= 0 && track < Image.Tracks.Cnt)
                {
                    if (Image[track].FormatName == TrackFormatName.Unscanned)
                    {
                        StatusLV.Text = TrackFormatName.Unscanned.ToString();
                    }
                    else if (Image[track].Scanning)
                    {
                        StatusLV.Text = "Scanning";
                    }
                    else
                    {
                        StatusLV.Text = "";
                    }
                    ClearSectorInfo(false, false);
                }
                else
                {
                    ClearSectorInfo(false, true);
                }
                ClearHighlight(MapCell.Hover);
            }
            Repaint();
        }
Ejemplo n.º 16
0
        private bool PaintMap()
        {
            bool paintMap = false;

            for (int i = 0; i < Image.Tracks.Cnt; i++)
            {
                if (Image.Tracks.Data[i].MapModified)
                {
                    paintMap = true;
                    break;
                }
            }
            bool paintHeader = FirstTrack != firstTrackOld || LastTrack != lastTrackOld;

            if (!paintMap && !paintHeader)
            {
                return(false);
            }
            IntPtr DC       = ChartArea.bDC;
            IntPtr penNull  = WinApi.CreatePen(WinApi.PS_NULL, 1, (uint)ColorTranslator.ToWin32(Color.White));
            IntPtr oldBrush = WinApi.SelectObject(DC, WinApi.GetStockObject(WinApi.StockObjects.DC_BRUSH));
            IntPtr oldPen   = WinApi.SelectObject(DC, penNull);
            IntPtr penBlack = WinApi.CreatePen(WinApi.PS_SOLID, 1, (uint)ColorTranslator.ToWin32(Color.Black));

            if (paintMap)
            {
                int top = headerHeight + upperBoundHeight;
                for (int track = 0; track < Image.Tracks.Cnt; track++)
                {
                    TrackFormat tf = Image.Tracks.Data[track];
                    if (!tf.MapModified)
                    {
                        continue;
                    }
                    tf.MapModified = false;
                    if (tf.Scanning)
                    {
                        WinApi.SetDCBrushColor(DC, GetCellColor(MapCell.Scanning));
                        WinApi.Rectangle(DC, CellWidth * track, top, CellWidth * (track + 1) + 1, top + TrackHeight + 1);
                        continue;
                    }
                    if (tf.FormatName == TrackFormatName.Unscanned)
                    {
                        WinApi.SetDCBrushColor(DC, GetCellColor(MapCell.Unprocessed));
                        WinApi.Rectangle(DC, CellWidth * track, top, CellWidth * (track + 1) + 1, top + TrackHeight + 1);
                        continue;
                    }
                    double prevSectorEnd  = 0;
                    double cumulativeTime = 0;
                    double spinTime       = tf.SpinTime;
                    if (spinTime == 0)
                    {
                        spinTime = TrackFormat.SpinTimeStandard;
                    }
                    bool gapPainted = true;
                    int  prevColor  = 0;
                    for (int j = 0; j < tf.Layout.Cnt; j++)
                    {
                        double sectorStart = j == 0 ? 0 : cumulativeTime + tf.Layout.Data[j].TimeMs - TrackFormat.NormalSectorHeaderSize / tf.BytesPerMs;
                        cumulativeTime += j == 0 ? 59 / tf.BytesPerMs : tf.Layout.Data[j].TimeMs;
                        double sectorEnd        = sectorStart + (tf.Layout.Data[j].SizeBytes + TrackFormat.NormalSectorHeaderSize) / tf.BytesPerMs;
                        double prevSectorEndRem = prevSectorEnd;
                        prevSectorEnd = sectorEnd;
                        MapCell cell = tf.Layout.Data[j].MapCellValue;
                        if (j != 0)
                        {
                            int gapPoint1 = (int)Math.Round(prevSectorEndRem / spinTime * TrackHeight);
                            int gapPoint2 = (int)Math.Round(sectorStart / spinTime * TrackHeight);
                            gapPainted = gapPoint2 > gapPoint1;
                            if (gapPainted)
                            {
                                WinApi.SetDCBrushColor(DC, ColorTranslator.ToWin32(Color.WhiteSmoke));
                                WinApi.Rectangle(DC, CellWidth * track, top + gapPoint1, CellWidth * (track + 1) + 1, top + gapPoint2 + 1);
                            }
                        }
                        int point1 = (int)Math.Round(sectorStart / spinTime * TrackHeight);
                        int point2 = (int)Math.Round(sectorEnd / spinTime * TrackHeight);
                        tf.Layout.Data[j].MapPoint1 = point1;
                        tf.Layout.Data[j].MapPoint2 = point2;
                        int color = GetCellColor(cell);
                        if (!gapPainted && color == prevColor)
                        {
                            color += 0x00202020;
                        }
                        prevColor = color;
                        WinApi.SetDCBrushColor(DC, color);
                        if ((cell & MapCell.Hover) != 0)
                        {
                            IntPtr penX = WinApi.SelectObject(DC, penBlack);
                            WinApi.Rectangle(DC, CellWidth * track, top + point1, CellWidth * (track + 1), top + point2);
                            WinApi.SelectObject(DC, penX);
                        }
                        else
                        {
                            WinApi.Rectangle(DC, CellWidth * track, top + point1, CellWidth * (track + 1) + 1, top + point2 + 1);
                        }
                    }
                    int gapPoint1x = (int)Math.Round(prevSectorEnd / spinTime * TrackHeight);
                    WinApi.SetDCBrushColor(DC, ColorTranslator.ToWin32(Color.WhiteSmoke));
                    WinApi.Rectangle(DC, CellWidth * track, top + gapPoint1x, CellWidth * (track + 1) + 1, top + TrackHeight + 1);
                }
            }
            if (paintHeader)
            {
                firstTrackOld = FirstTrack;
                lastTrackOld  = LastTrack;
                WinApi.SetDCBrushColor(DC, ColorTranslator.ToWin32(backColor));
                WinApi.Rectangle(DC, 0, stripHeight, MaxTrack * CellWidth + 1, headerHeight + 1);
                if (FirstTrack > 0)
                {
                    WinApi.Rectangle(DC, 0, 0, FirstTrack * CellWidth + 1, stripHeight + 1);
                }
                if (LastTrack < MaxTrack)
                {
                    WinApi.Rectangle(DC, LastTrack * CellWidth, 0, MaxTrack * CellWidth + 1, stripHeight + 1);
                }
                WinApi.SetDCBrushColor(DC, ColorTranslator.ToWin32(Color.Black));
                WinApi.Rectangle(DC, FirstTrack * CellWidth, 0, LastTrack * CellWidth + 1, stripHeight + 1);
                WinApi.Rectangle(DC, 160 * CellWidth, stripHeight + 1, 172 * CellWidth + 1, headerHeight);

                // Upper and bottom lines painting.
                WinApi.Rectangle(DC, 0, headerHeight, MaxTrack * CellWidth + 1, headerHeight + upperBoundHeight);
                WinApi.Rectangle(DC, 0, headerHeight + upperBoundHeight + TrackHeight, MaxTrack * CellWidth + 1, headerHeight + upperBoundHeight + TrackHeight + bottomBoundHeight);
            }
            WinApi.SelectObject(DC, oldPen);
            WinApi.SelectObject(DC, oldBrush);
            WinApi.DeleteObject(penNull);
            WinApi.DeleteObject(penBlack);
            return(true);
        }
Ejemplo n.º 17
0
 public bool DoesSatisfyFormat(TrackFormat trackFormat, int cylinder)
 {
     return(ContainsSectorsFrom(trackFormat, cylinder) && !ContainsOtherSectors(trackFormat, cylinder));
 }
Ejemplo n.º 18
0
        public void LoadFormatFromXml(string fileName)
        {
            int track = 0;
            MList <SectorInfo> layout = new MList <SectorInfo>(50);
            MList <SectorInfo> temp   = new MList <SectorInfo>(50);

            using (XmlTextReader xml = new XmlTextReader(fileName))
            {
                while (xml.Read())
                {
                    if (xml.NodeType == XmlNodeType.EndElement)
                    {
                        break;
                    }
                    if (xml.NodeType != XmlNodeType.Element)
                    {
                        continue;
                    }
                    if (xml.Name == "DiskFormat")
                    {
                        string name = xml.GetAttribute("Name");
                        if (string.IsNullOrEmpty(Name) && !string.IsNullOrEmpty(name))
                        {
                            Name = name;
                        }
                        while (xml.Read())
                        {
                            if (xml.NodeType == XmlNodeType.EndElement)
                            {
                                break;
                            }
                            if (xml.NodeType != XmlNodeType.Element)
                            {
                                continue;
                            }
                            switch (xml.Name)
                            {
                            case "Track":
                                TrackFormat tf = Tracks[track];
                                tf.Layout.EnsureCapacity(Int32.Parse(xml.GetAttribute("SectorCount")));
                                layout.Cnt = 0;
                                if (!xml.IsEmptyElement)
                                {
                                    while (xml.Read())
                                    {
                                        if (xml.NodeType == XmlNodeType.EndElement)
                                        {
                                            break;
                                        }
                                        if (xml.NodeType != XmlNodeType.Element)
                                        {
                                            continue;
                                        }
                                        switch (xml.Name)
                                        {
                                        case "Sector":
                                            SectorInfo s = new SectorInfo()
                                            {
                                                Cylinder     = Int32.Parse(xml.GetAttribute("Cylinder")),
                                                Head         = Int32.Parse(xml.GetAttribute("Head")),
                                                SectorNumber = Int32.Parse(xml.GetAttribute("Number")),
                                                SizeCode     = Int32.Parse(xml.GetAttribute("Size")),
                                                TimeMs       = Double.Parse(xml.GetAttribute("Time"), NumberStyles.Any, CultureInfo.InvariantCulture)
                                            };
                                            layout.Add(s);
                                            break;
                                        }
                                    }
                                }
                                if (tf.Layout.Cnt > 0)
                                {
                                    tf.Layout.CopyTo(temp);
                                    layout.CopyTo(tf.Layout);
                                    for (int i = 0; i < temp.Cnt; i++)
                                    {
                                        int index = tf.FindSectorIndex(temp[i].SectorNumber);
                                        if (index < 0)
                                        {
                                            Log.Info?.Out($"Сектор не найден. Трек: {track} | Сектор: {temp[i].SectorNumber}");
                                            continue;
                                        }
                                        tf.Layout.Data[index].Data           = temp[i].Data;
                                        tf.Layout.Data[index].ProcessResult  = temp[i].ProcessResult;
                                        tf.Layout.Data[index].MapCellValue   = temp[i].MapCellValue;
                                        tf.Layout.Data[index].TimeCalculated = false;
                                    }
                                }
                                else
                                {
                                    layout.CopyTo(tf.Layout);
                                    for (int i = 0; i < layout.Cnt; i++)
                                    {
                                        tf.Layout.Data[i].MapCellValue   = MapCell.Unprocessed;
                                        tf.Layout.Data[i].TimeCalculated = false;
                                    }
                                }
                                tf.FormatName  = tf.GetFormatName();
                                tf.SpinTime    = tf.GetSpinTime();
                                tf.MapModified = true;
                                track++;
                                break;
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 19
0
        public unsafe byte[] ToFdi(string text)
        {
            int trackCount  = SizeTracks;
            int sizeSectors = SizeSectors;
            int cylCount    = (int)Math.Ceiling(trackCount / 2.0);
            int textLength  = text != null ? text.Length : 0;
            int dataSize    = SizeBytes + textLength + 1 + 7 * cylCount * 2 + sizeSectors * 7 + 14;

            byte[] data = new byte[dataSize];
            data[0] = (byte)'F';
            data[1] = (byte)'D';
            data[2] = (byte)'I';
            data[4] = (byte)cylCount;
            data[6] = 2;
            //data[8] = 0;  // Смещение текста (комментария), 2 байта. Пишется ниже.
            //data[10] = 0; // Смещение данных, 2 байта. Пишется ниже.
            //data[12] = 0; // Длина дополнительной информации в заголовке, 2 байта. В этой версии - 0.
            //data[14] = 0; // Дополнительная информация ("Резерв для дальнейшей модернизации"). В текущей версии формата отсутствует.
            int index       = 14;
            int trackOffset = 0;

            for (int track = 0; track < cylCount * 2; track++)
            {
                TrackFormat tf = Tracks[track];
                fixed(byte *numRef = &data[index])
                {
                    *((int *)numRef) = trackOffset;
                }

                //data[index + 4] = 0;  // 2 байта, всегда содержит 0 (резерв для модернизации формата).
                data[index + 6] = tf != null ? (byte)tf.Layout.Cnt : (byte)0;
                index          += 7;
                int sectorOffset = 0;
                if (tf != null)
                {
                    for (int sector = 0; sector < tf.Layout.Cnt; sector++)
                    {
                        data[index]     = (byte)(track / 2);
                        data[index + 1] = (byte)tf.Layout.Data[sector].Head;
                        data[index + 2] = (byte)tf.Layout.Data[sector].SectorNumber;
                        data[index + 3] = (byte)tf.Layout.Data[sector].SizeCode;
                        data[index + 4] = (byte)(tf.Layout.Data[sector].ProcessResult == SectorProcessResult.Good ? 1 << tf.Layout.Data[sector].SizeCode : 0);
                        fixed(byte *numRef = &data[index + 5])
                        {
                            *((ushort *)numRef) = (ushort)sectorOffset;
                        }

                        sectorOffset += tf.Layout.Data[sector].SizeBytes;
                        index        += 7;
                    }
                    trackOffset += sectorOffset;
                }
            }
            int textOffset = index;

            if (textLength > 0)
            {
                Encoding.ASCII.GetBytes(text, 0, text.Length, data, textOffset);
            }
            int dataOffset = textOffset + textLength + 1;

            fixed(byte *numRef = &data[8])
            {
                *((ushort *)numRef)       = (ushort)textOffset;
                *((ushort *)(numRef + 2)) = (ushort)dataOffset;
            }

            int currentOffset = 0;

            for (int track = 0; track < trackCount; track++)
            {
                TrackFormat tf = Tracks[track];
                if (tf == null)
                {
                    continue;
                }
                for (int sector = 0; sector < tf.Layout.Cnt; sector++)
                {
                    if (tf.Layout.Data[sector].Data == null)
                    {
                        continue;
                    }
                    Array.Copy(tf.Layout.Data[sector].Data, 0, data, currentOffset + dataOffset, tf.Layout.Data[sector].SizeBytes);
                    currentOffset += tf.Layout.Data[sector].SizeBytes;
                }
            }
            return(data);
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Чтение вперед или назад. Возвращает количество успешно прочитанных секторов.
        /// </summary>
        /// <returns>Возвращает количество успешно прочитанных секторов.</returns>
        public int Read(ScanMode scanMode, bool forward)
        {
            int goodSectors = Params.Image.GoodSectors;

            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            GCLatencyMode oldGCLatencyMode = GCSettings.LatencyMode;

            try
            {
                GCSettings.LatencyMode = GCLatencyMode.LowLatency;
                int firstTrack   = Params.FirstTrack;
                int prevCylinder = -1;
                int lastTrack    = Params.LastTrack;
                trackTimer.Restart();
                int track = forward ? firstTrack : lastTrack - 1;
                for (int p = firstTrack; p < lastTrack; p++, track = forward ? track + 1 : track - 1)
                {
                    if (Aborted)
                    {
                        goto abort;
                    }
                    if (Params.Side == DiskSide.Side0 && (track % 2 != 0))
                    {
                        continue;
                    }
                    if (Params.Side == DiskSide.Side1 && (track % 2 != 1))
                    {
                        continue;
                    }
                    TrackFormat trackF = Params.Image[track];
                    bool        scan   = ((scanMode == ScanMode.Once) ||
                                          (scanMode == ScanMode.UnscannedOnly && trackF.FormatName == TrackFormatName.Unscanned) ||
                                          scanMode == ScanMode.EachTrackRead) &&
                                         (trackF.MaxGap() > 128 + TrackFormat.MinSectorHeaderSize || trackF.ContainsCalculatedTime());
                    if (!scan && trackF.NotGoodSectors == 0)
                    {
                        continue;
                    }
                    int cylinder = track / 2;
                    if (cylinder != prevCylinder)
                    {
                        Driver.Seek(DriverHandle, track);
                        if (Aborted)
                        {
                            goto abort;
                        }
                        prevCylinder = cylinder;
                    }
                    ReadTrack(track, Params, scanMode);
                }
                return(Params.Image.GoodSectors - goodSectors);

abort:
                Log.Info?.Out("Чтение прервано.");
            }
            finally
            {
                GCSettings.LatencyMode = oldGCLatencyMode;
                Params.Map?.ClearHighlight(MapCell.Processing);
            }
            return(Params.Image.GoodSectors - goodSectors);
        }
Ejemplo n.º 21
0
        /// <summary>
        /// 0 - Нет ошибок.
        /// 1 - Размер файла слишком мал.
        /// 5 - Размер файла слишком мал и содержит не все данные содержимого секторов.
        /// 6 - Нет сигнатуры FDI.
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="map"></param>
        /// <returns></returns>
        public unsafe int LoadFdi(string fileName, byte[] data, out string text)
        {
            Clear();
            text = null;
            if (data.Length < 14)
            {
                return(1);
            }
            if (data[0] != 'F' || data[1] != 'D' || data[2] != 'I')
            {
                return(6);
            }
            int cylCount;
            int textOffset;
            int dataOffset;

            fixed(byte *d = &data[0])
            {
                cylCount   = *(ushort *)(d + 4);
                textOffset = *(ushort *)(d + 8);
                dataOffset = *(ushort *)(d + 10);
            }

            int minFileSize = 7 * cylCount * 2 + 14;

            if (data.Length < minFileSize || data.Length < textOffset + 1)
            {
                return(1);
            }

            int tt = textOffset;

            for (; tt < data.Length; tt++)
            {
                if (data[tt] == 0)
                {
                    break;
                }
            }
            int textLen = tt - textOffset;

            text = textLen > 0 ? Encoding.ASCII.GetString(data, textOffset, tt - textOffset) : null;

            int index = 14;

            for (int track = 0; track < cylCount * 2; track++)
            {
                int trackOffset;
                fixed(byte *d = &data[index])
                {
                    trackOffset = *((int *)d);
                }

                int         sectorsOnTrack = data[index + 6];
                TrackFormat tf             = Tracks.Data[track];
                tf.Layout.EnsureCapacity(sectorsOnTrack);
                tf.Layout.Cnt  = sectorsOnTrack;
                tf.SpinTime    = TrackFormat.SpinTimeStandard;
                tf.MapModified = true;
                index         += 7;
                double totalTimeMs = 0;
                for (int sector = 0; sector < sectorsOnTrack; sector++)
                {
                    tf.Layout.Data[sector].Cylinder     = data[index];
                    tf.Layout.Data[sector].Head         = data[index + 1];
                    tf.Layout.Data[sector].SectorNumber = data[index + 2];
                    tf.Layout.Data[sector].SizeCode     = data[index + 3];
                    int code = data[index + 4] & 63;
                    tf.Layout.Data[sector].ProcessResult = code == 0 ? SectorProcessResult.Bad : SectorProcessResult.Good;
                    int sectorOffset;
                    fixed(byte *d = &data[index + 5])
                    {
                        sectorOffset = *((ushort *)d);
                    }

                    int sizeBytes = tf.Layout.Data[sector].SizeBytes;
                    if (data.Length < dataOffset + trackOffset + sectorOffset + sizeBytes)
                    {
                        return(5);
                    }
                    if (tf.Layout.Data[sector].Data == null || tf.Layout.Data[sector].Data.Length < tf.Layout.Data[sector].SizeBytes)
                    {
                        tf.Layout.Data[sector].Data = new byte[tf.Layout.Data[sector].SizeBytes];
                    }
                    tf.Layout.Data[sector].MapCellValue = tf.Layout.Data[sector].ProcessResult == SectorProcessResult.Good ? MapCell.Good : MapCell.CrcError;
                    Array.Copy(data, dataOffset + trackOffset + sectorOffset, tf.Layout.Data[sector].Data, 0, sizeBytes);
                    if (tf.Layout.Data[sector].ProcessResult == SectorProcessResult.Good &&
                        DiskImage.AllBytes(tf.Layout.Data[sector].Data, 0, tf.Layout.Data[sector].SizeBytes, 0))
                    {
                        tf.Layout.Data[sector].MapCellValue = MapCell.Zero;
                    }
                    index += 7;
                    tf.Layout.Data[sector].TimeCalculated = true;
                    if (sector != 0)
                    {
                        tf.Layout.Data[sector].TimeMs = (tf.Layout.Data[sector - 1].SizeBytes + TrackFormat.NormalSectorHeaderSize + 1) / TrackFormat.BytesPerMsStandard;
                        totalTimeMs += tf.Layout.Data[sector].TimeMs;
                    }
                }
                tf.FormatName = tf.GetFormatName();
                if (sectorsOnTrack > 0)
                {
                    tf.Layout.Data[0].TimeMs = Math.Max(0, TrackFormat.SpinTimeStandard - totalTimeMs);
                }
            }
            FileName = fileName;
            Name     = Path.GetFileNameWithoutExtension(fileName);
            Modified = false;
            return(0);
        }
Ejemplo n.º 22
0
        public int LoadTrd(string fileName, byte[] data, bool modifiedTrd)
        {
            Clear();
            const int sectorSize  = 256;
            int       sizeSectors = data.Length / sectorSize;

            if (sizeSectors * sectorSize != data.Length)
            {
                return(1);
            }
            int sizeTracks = sizeSectors / 16;

            FileName = fileName;
            Name     = Path.GetFileNameWithoutExtension(fileName);
            for (int track = 0; track < sizeTracks; track++)
            {
                TrackFormat tf = Tracks[track];
                tf.Layout.Cnt = 16;
                for (int sector = 0; sector < 16; sector++)
                {
                    tf.Layout.Data[sector].Cylinder     = track / 2;
                    tf.Layout.Data[sector].Head         = track & 1;
                    tf.Layout.Data[sector].SectorNumber = sector + 1;
                    tf.Layout.Data[sector].SizeCode     = 1;
                    tf.Layout.Data[sector].TimeMs       = 12.5;
                    tf.FormatName = TrackFormatName.TrDosSequential;
                    tf.Layout.Cnt = 16;
                    tf.SpinTime   = TrackFormat.SpinTimeStandard;
                    int adr = track * 16 * 256 + sector * 256;
                    if (tf.Layout.Data[sector].Data == null || tf.Layout.Data[sector].Data.Length < 256)
                    {
                        tf.Layout.Data[sector].Data = new byte[256];
                    }
                    Array.Copy(data, adr, tf.Layout.Data[sector].Data, 0, 256);
                    tf.Layout.Data[sector].ProcessResult = SectorProcessResult.Good;
                    tf.Layout.Data[sector].MapCellValue  = MapCell.Good;
                    if (modifiedTrd)
                    {
                        if (DiskImage.AllBytes(tf.Layout.Data[sector].Data, 0, 256, (byte)'B'))
                        {
                            tf.Layout.Data[sector].ProcessResult = SectorProcessResult.Bad;
                            tf.Layout.Data[sector].MapCellValue  = MapCell.CrcError;
                        }
                        else if (DiskImage.AllBytes(tf.Layout.Data[sector].Data, 0, 256, (byte)'N'))
                        {
                            tf.Layout.Data[sector].ProcessResult = SectorProcessResult.Unprocessed;
                            tf.Layout.Data[sector].MapCellValue  = MapCell.Unprocessed;
                        }
                    }
                    if (tf.Layout.Data[sector].MapCellValue == MapCell.Good &&
                        DiskImage.AllBytes(tf.Layout.Data[sector].Data, 0, 256, 0))
                    {
                        tf.Layout.Data[sector].MapCellValue = MapCell.Zero;
                    }
                    tf.Layout.Data[sector].TimeCalculated = true;
                }
                tf.MapModified = true;
            }
            Modified = false;
            return(0);
        }
Ejemplo n.º 23
0
        public unsafe void ReadTrack(int track, DiskReaderParams2 pars, ScanMode scanMode)
        {
            // Массив sectors:
            // D0 - Признак обработанного сектора при чтении трека в одной попытке. Обнуляется перед каждой попыткой чтения трека.
            // D1 - Используется в блоке чтения заголовков. Отмечаются сектора заголовки которых были найдены. Вне этого блока не используется.
            // D2 - Запрет чтения сектора из-за того что его заголовок был прочитан SectorReadAttempts раз и не был найден. Параметр сохраняется между попытками чтения трека.

            TrackFormat trackF = pars.Image.Tracks[track];

            const int sectorArrayLen = 50;
            int *     sectors        = stackalloc int[sectorArrayLen];

            for (int i = 0; i < sectorArrayLen; i++)
            {
                sectors[i] = 0;
            }
            bool trackScanned = false;

            for (int attempt = 0; attempt < pars.SectorReadAttempts; attempt++)
            {
                if (Aborted)
                {
                    return;
                }

                // Сканирование трека.

                if (
                    ((scanMode == ScanMode.Once && !trackScanned) ||
                     (scanMode == ScanMode.UnscannedOnly && trackF.FormatName == TrackFormatName.Unscanned) ||
                     scanMode == ScanMode.EachTrackRead)

                    && (trackF.MaxGap() > 128 + TrackFormat.MinSectorHeaderSize || trackF.ContainsCalculatedTime())
                    )
                {
                    // workTrackFormat и longestTrackFormat используются чтобы не плодить объекты.
                    // Объект scanFormatBuffer используется функциями ScanFormat и CombineFormats, поэтому его брать нельзя.

                    trackF.Scanning    = true;
                    trackF.MapModified = true;
                    if (ScanFormat(workTrackFormat, track, true))
                    {
                        for (int i = 0; i < workTrackFormat.Layout.Cnt; i++)
                        {
                            workTrackFormat.Layout.Data[i].MapCellValue = MapCell.Unprocessed;
                        }
                        if (CombineFormats(track, trackF, workTrackFormat, longestTrackFormat))
                        {
                            trackF.Assign(longestTrackFormat);
                            trackF.MapModified = true;
                        }
                    }
                    trackF.Scanning    = false;
                    trackF.MapModified = true;
                    trackScanned       = true;
                    if (Aborted)
                    {
                        return;
                    }
                }

                if (trackF.Layout.Cnt > sectorArrayLen)
                {
                    Log.Error?.Out($"Число секторов превышает размер рабочего массива: {trackF.Layout.Cnt}");
                    throw new Exception();
                }
                for (int i = 0; i < trackF.Layout.Cnt; i++)
                {
                    sectors[i] &= ~1;
                }
                bool wasError = false;
                trackTimer.Restart();
                int        skip             = 0;
                int        processedSectors = 0;
                int        sectorCounter    = 0;
                SectorInfo diskSector;
                while (processedSectors < trackF.Layout.Cnt)
                {
                    diskSector = trackF.Layout.Data[sectorCounter];
                    int sectorIndex = sectorCounter;
                    sectorCounter++;
                    skip++;
                    if ((sectors[sectorIndex] & 1) != 0)
                    {
                        continue;
                    }
                    sectors[sectorIndex] |= 1;
                    processedSectors++;
                    if ((sectors[sectorIndex] & 4) != 0)
                    {
                        continue;
                    }
                    if (trackF.Layout.Data[sectorIndex].ProcessResult == SectorProcessResult.Good)
                    {
                        continue;
                    }
                    skip = 0;
                    pars.Map.MarkSectorAsProcessing(track, sectorIndex);
                    WinApi.RtlZeroMemory(memoryHandle, (UIntPtr)diskSector.SizeBytes);
                    int    error            = Driver.ReadSectorF(DriverHandle, memoryHandle, diskSector.Cylinder, diskSector.SectorNumber, diskSector.SizeCode, track & 1, diskSector.Head, 0x0a, 0xff);
                    double curTimeSinceSync = trackF.Timer.ElapsedMs;
                    bool   badWritten       = diskSector.ProcessResult == SectorProcessResult.Bad;
                    if (error == 0)
                    {
                        pars.Image.WriteGoodSector(memoryHandle, trackF, sectorIndex);
                    }
                    else
                    {
                        wasError = true;
                        // Если надо проверить CRC-Error заголовка: (error == 27 && curTimeSinceSync > trackF.SpinTime)
                        bool noHeader = error == 21 || error == 1112 || error == 27;
                        if (noHeader)
                        {
                            if (!badWritten)
                            {
                                pars.Image.WriteNoHeader(memoryHandle, trackF, sectorIndex);
                            }
                            Make30HeadPositionings(error, track);
                        }
                        else if (error == 23)
                        {
                            pars.Image.WriteBadSector(memoryHandle, trackF, sectorIndex);
                            badWritten = true;
                        }
                        else
                        {
                            Log.Info?.Out($"Необработанная ошибка при чтении сектора: {error}");
                        }
                    }
                    if (Aborted)
                    {
                        return;
                    }
                }
                Log.Trace?.Out($"Время чтения трека: {GP.ToString(trackTimer.ElapsedMs, 2)}");
                trackTimer.Restart();
                if (!wasError)
                {
                    break;
                }
            }
        }
Ejemplo n.º 24
0
        /// <summary>
        /// Сканирование трека. Сканировать может в двух режимах: по времени оборота диска и по зацикливанию потока секторов.
        /// При сканировании по времени оборота диска скорость диска должна быть в районе 300 об/мин, т.е. замедлять диск не надо, иначе будут ошибки.
        /// Если byLooping == true, то конец трека определяется по зацикливанию потока секторов, но сектора сканируются не менее 150 мс и не более 1000 мс.
        /// </summary>
        /// <param name="track"></param>
        /// <returns></returns>
        public unsafe bool ScanFormat(TrackFormat result, int track, bool byLooping)
        {
            int ilayoutCnt = 0;

            scanFormatBuffer.Layout.Cnt = 0;
            SectorInfo[]         layout = scanFormatBuffer.Layout.Data;
            tagFD_READ_ID_PARAMS pars   = new tagFD_READ_ID_PARAMS()
            {
                flags = Driver.FD_OPTION_MFM,
                head  = (byte)(track & 1)
            };
            tagFD_CMD_RESULT cmdResult = new tagFD_CMD_RESULT();

            scanFormatStopwatch.Restart();
            scanFormatTotalTime.Stop();
            int firstIndex = 1;

            for (int i = 0; i < scanFormatBuffer.Layout.Capacity; i++)
            {
                if (Aborted)
                {
                    return(false);
                }
                if (!Driver.ReadId(DriverHandle, pars, out cmdResult))
                {
                    int error = Marshal.GetLastWin32Error();
                    Log.Trace?.Out($"Функция ReadId вернула false. i={i}. LastError={error}");
                    if (Aborted)
                    {
                        return(false);
                    }
                    Make30HeadPositionings(error, track);
                    if (scanFormatBuffer.Layout.Cnt == 0)
                    {
                        goto success;
                    }
                    return(false);
                }
                double timeMs = scanFormatStopwatch.ElapsedMs;
                scanFormatStopwatch.Restart();
                if (!scanFormatTotalTime.IsRunning)
                {
                    scanFormatTotalTime.Restart();
                }
                if (!byLooping && scanFormatTotalTime.ElapsedMs > 209)
                {
                    goto success;
                }
                layout[ilayoutCnt] = new SectorInfo()
                {
                    Cylinder     = cmdResult.cyl,
                    Head         = cmdResult.head,
                    SectorNumber = cmdResult.sector,
                    SizeCode     = cmdResult.size,
                    TimeMs       = timeMs
                };
                ilayoutCnt++;
                scanFormatBuffer.Layout.Cnt = ilayoutCnt;

                // Бывают случаи когда заголовок сектора читается на первом обороте и не читается на втором.
                // Из-за этого алгоритм, в котором повтор сектора определяется сравнением с первым прочитанным заголовком, иногда даёт сбои.
                // Поэтому ищем встечался ли ранее только что прочитанный сектор среди всех прочитанных заголовков, а не только сравниваем с первым.
                // По отношению к найденному сектору замеряем время вращения. Если оно больше 250 мс, значит этот сектор был пропущен на одном из оборотов
                // и такую последовательность брать нельзя. Если время меньше 150, значит на треке есть сектора с одинаковыми параметрами.

                if (byLooping)
                {
                    for (int u = 0; u < ilayoutCnt - 1; u++)
                    {
                        if (layout[u].Cylinder == cmdResult.cyl &&
                            layout[u].Head == cmdResult.head &&
                            layout[u].SectorNumber == cmdResult.sector &&
                            layout[u].SizeCode == cmdResult.size)
                        {
                            double spinTime = 0;
                            for (int p = u + 1; p < ilayoutCnt; p++)
                            {
                                spinTime += layout[p].TimeMs;
                            }
                            if (spinTime > 250 || spinTime < 150)
                            {
                                continue;
                            }
                            firstIndex = u + 1;
                            goto success;
                        }
                    }
                    if (scanFormatTotalTime.ElapsedMs > 1000)
                    {
                        Log.Trace?.Out($"Не удалось найти цикл в последовательности секторов из-за нестабильного чтения. Сканироваие прервано по таймауту.");
                        return(false);
                    }
                }
            }
            return(false);

success:
            result.AssignLayout(scanFormatBuffer, track, cmdResult.sector, firstIndex);
            Log.Trace?.Out($"Время сканирования трека {track}: {GP.ToString(scanFormatTotalTime.ElapsedMs, 2)}");
            return(true);
        }
Ejemplo n.º 25
0
        /// <summary>
        /// Объединение форматов двух результатов сканирования одного трека. У треков main и add будут изменены тайминги при работе этой функции!
        /// </summary>
        /// <param name="track"></param>
        /// <param name="main">Основной трек.</param>
        /// <param name="add">Добавляемый трек.</param>
        /// <param name="result"></param>
        /// <returns>true - объединение успешно, false - объединение не удалось по какой-то причине (невозможность синхронизации, несовместимость треков).</returns>
        public bool CombineFormats(int track, TrackFormat main, TrackFormat add, TrackFormat result)
        {
            if (add.Layout.Cnt == 0)
            {
                result.Assign(main);
                if (result.FormatName == TrackFormatName.Unscanned)
                {
                    result.FormatName = TrackFormatName.NoHeaders;
                }
                return(true);
            }
            if (main.Layout.Cnt == 0 && add.Layout.Cnt > 0)
            {
                result.AssignLayout(add, track);
                return(true);
            }

            int indexM = 0;
            int indexA = 0;

            for (int i = 0; i < main.Layout.Cnt; i++)
            {
                for (int j = 0; j < add.Layout.Cnt; j++)
                {
                    if (main.Layout.Data[i].Parameters == add.Layout.Data[j].Parameters)
                    {
                        indexM = i;
                        indexA = j;
                        goto outside;
                    }
                }
            }
            return(false);

outside:
            int iM = indexM;
            int iA = indexA;
            int iR = 0;

            scanFormatBuffer.Layout.EnsureCapacity(main.Layout.Cnt + add.Layout.Cnt);
            scanFormatBuffer.Layout.Cnt = 0;
            int    totalPassedInMain = 0;
            double timeM             = main.Layout.Data[(iM + 1) % main.Layout.Cnt].TimeMs;
            double timeA             = add.Layout.Data[(iA + 1) % add.Layout.Cnt].TimeMs;

            while (totalPassedInMain < main.Layout.Cnt)
            {
                int iM1 = (iM + 1) % main.Layout.Cnt;
                int iA1 = (iA + 1) % add.Layout.Cnt;
                if (main.Layout.Data[iM1].TimeCalculated)
                {
                    if (main.Layout.Data[iM1].Parameters == add.Layout.Data[iA1].Parameters)
                    {
                        iM = iM1;
                        totalPassedInMain++;
                        iA = iA1;
                        scanFormatBuffer.Layout.Data[iR]                = main.Layout.Data[iM];
                        scanFormatBuffer.Layout.Data[iR].TimeMs         = add.Layout.Data[iA].TimeMs;
                        scanFormatBuffer.Layout.Data[iR].TimeCalculated = false;
                        iR++;
                    }
                    else
                    {
                        return(false);
                        //totalPassedInMain++;
                        //for (int t = 0, r = iM1, tlast = main.Layout.Cnt - totalPassedInMain; t < tlast; t++, totalPassedInMain++, r = r % main.Layout.Cnt)
                        //{
                        //    for (int y = 0; y < add.Layout.Cnt; y++)
                        //    {
                        //        if (main.Layout.Data[r].Parameters == add.Layout.Data[y].Parameters)
                        //        {
                        //            iM = r;
                        //            iA = y;
                        //            goto outOfLoop;
                        //        }
                        //    }
                        //}
                        //outOfLoop:;
                    }
                }
                else if (Math.Abs(timeM - timeA) / timeM < 0.1)
                {
                    iM = iM1;
                    totalPassedInMain++;
                    iA = iA1;
                    if (main.Layout.Data[iM].Parameters != add.Layout.Data[iA].Parameters)
                    {
                        Log.Info?.Out($"Несовпадение параметров секторов при совмещении форматов. Основной сектор: {main[iM]} | Добавляемый сектор: {add[iA]}");
                        return(false);
                    }
                    scanFormatBuffer.Layout.Data[iR] = main.Layout.Data[iM];
                    iR++;
                    timeM = main.Layout.Data[(iM + 1) % main.Layout.Cnt].TimeMs;
                    timeA = add.Layout.Data[(iA + 1) % add.Layout.Cnt].TimeMs;
                }
                else if (timeA < timeM)
                {
                    timeM -= timeA;
                    main.Layout.Data[iM1].TimeMs -= timeA;
                    iA = iA1;
                    scanFormatBuffer.Layout.Data[iR] = add.Layout.Data[iA];

                    // Проверки ниже закомментированы, т.к. стало понятно что заголовки могут быть без данных и быть как следствие с более высокой плотностью.

                    // Проверка выхода конца добавляемого сектора дальше начала следующего сектора в массиве main.
                    if (timeM < (add.Layout.Data[iA].SizeBytes + TrackFormat.MinSectorHeaderSize) / add.BytesPerMs)
                    {
                        return(false);
                    }

                    // Проверка выхода начала добавляемого сектора влево от конца предыдущего сектора в массиве main.
                    if (timeA < (main.Layout.Data[iM].SizeBytes + TrackFormat.MinSectorHeaderSize) / main.BytesPerMs)
                    {
                        return(false);
                    }

                    iR++;
                    timeA = add.Layout.Data[(iA + 1) % add.Layout.Cnt].TimeMs;
                }
                else
                {
                    timeA -= timeM;
                    add.Layout.Data[iA1].TimeMs -= timeM;
                    iM = iM1;
                    totalPassedInMain++;
                    scanFormatBuffer.Layout.Data[iR] = main.Layout.Data[iM];
                    iR++;
                    timeM = main.Layout.Data[(iM + 1) % main.Layout.Cnt].TimeMs;
                }
            }
            scanFormatBuffer.Layout.Cnt = iR;
            result.AssignLayout(scanFormatBuffer, track);
            return(true);
        }