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; } } }
/// <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); }