private void ReadCatalogue(object sender, EventArgs e) { if (!ReadParameters(false)) { return; } SetProcessing(true); BackgroundWorker worker = new BackgroundWorker(); Log.Info?.Out($"Чтение каталога. DataRate: {Params.DataRate}"); int successfullyRead = 0; DiskReaderParams npars = new DiskReaderParams() { FirstSectorNum = 0, LastSectorNum = 9, DataRate = Params.DataRate, Image = new TrDosImage(9, null), SectorReadAttempts = Params.SectorReadAttempts, Side = DiskSide.Both, CurrentTrackFormat = new TrackFormat(TrackFormatName.TrDosSequential), ReadMode = ReadMode.Standard, TrackLayoutAutodetect = false, UpperSideHeadAutodetect = false, }; diskReader = new DiskReader() { Params = npars }; worker.DoWork += (object sndr, DoWorkEventArgs ee) => { try { if (!diskReader.OpenDriver()) { return; } successfullyRead = diskReader.ReadForward(); diskReader.CloseDriver(); Log.Info?.Out($"Чтение каталога завершено. Успешно прочитанных секторов: {successfullyRead}"); } catch (Exception ex) { Log.Error?.Out($"Исключение при чтении диска: {ex.Message} | StackTrace: {ex.StackTrace}"); } }; worker.RunWorkerCompleted += (object sender1, RunWorkerCompletedEventArgs ee) => { SetProcessing(false); if (MainForm.CatalogueForm == null) { MainForm.CatalogueForm = new CatalogueForm(); } if (successfullyRead > 1) { MainForm.CatalogueForm.ShowForm(diskReader.Params.Image as TrDosImage, false); } }; worker.RunWorkerAsync(); }
public IsDosReader(Control parent, DiskReaderParams dparams) : base(parent, 1024, 5, dparams) { upperSidePanel.Visible = false; readModePanel.Visible = false; map.FileL.Visible = false; map.FileLV.Visible = false; map.ExtenstionLV.Visible = false; readCatalogue.Visible = false; showCatalogue.Visible = false; showCatFromTrack.Visible = false; Image = new IsDosImage(160 * SectorsOnTrack, map) { Name = "" }; map.Image = Image; stats.Image = Image; map.Repaint(); stats.Repaint(); loadImage.Click += LoadImage; mergeImage.Click += MergeImage; newImage.Click += NewImage; saveImage.Click += SaveImage; readForward.Click += ReadForward; readBackward.Click += ReadBackward; readRandomSectors.Click += ReadRandomSectors; }
public object Clone() { DiskReaderParams r = (DiskReaderParams)MemberwiseClone(); r.CurrentTrackFormat = (TrackFormat)CurrentTrackFormat.Clone(); return(r); }
public TrDosReader(Control parent, DiskReaderParams dparams) : base(parent, 256, 16, dparams) { Image = new TrDosImage(160 * SectorsOnTrack, map) { Name = "" }; map.Image = Image; stats.Image = Image; map.Repaint(); stats.Repaint(); saveImage.Click += SaveImage; readCatalogue.Click += ReadCatalogue; showCatalogue.Click += ShowCatalogue; showCatFromTrack.Click += ShowCatFromTrack; loadImage.Click += LoadImage; mergeImage.Click += MergeImage; newImage.Click += NewImage; readForward.Click += ReadForward; readBackward.Click += ReadBackward; readRandomSectors.Click += ReadRandomSectors; }
public unsafe void ReadTrack(int track, DiskReaderParams pars) { // Массив sectors: // D0 - Признак обработанного сектора при чтении трека в одной попытке. Обнуляется перед каждой попыткой чтения трека. // D1 - Используется в блоке чтения заголовков. Отмечаются сектора заголовки которых были найдены. Вне этого блока не используется. // D2 - Запрет чтения сектора из-за того что его заголовок был прочитан SectorReadAttempts раз и не был найден. Параметр сохраняется между попытками чтения трека. int *sectors = stackalloc int[pars.SectorsOnTrack]; for (int i = 0; i < pars.SectorsOnTrack; i++) { sectors[i] = 0; } bool formatScanned = false; bool headScanned = false; bool trackScanned = false; bool wasCorrectHead = false; bool missedHeaders = false; for (int attempt = 0; attempt < pars.SectorReadAttempts; attempt++) { if (Aborted) { return; } for (int i = 0; i < pars.SectorsOnTrack; i++) { sectors[i] &= ~1; } bool wasError = false; double timeAfterSync = 0; trackTimer.Restart(); int skip = 0; int processedSectors = 0; int sectorCounter = 0; SectorInfo diskSector; while (processedSectors < pars.SectorsOnTrack) { bool sync = false; if (pars.ReadMode == ReadMode.Fast && pars.CurrentTrackFormat.IsSync) { bool gcsError; diskSector = pars.CurrentTrackFormat.GetClosestSector(track, 0, skip, out timeAfterSync, out gcsError); sync = true; // Переключение в стандартный режим чтения в случае если функция GetClosestSector отработала с ошибкой. // Такое было у одного из пользователей и причина ошибки непонятна. if (gcsError) { pars.ReadMode = ReadMode.Standard; } } else { diskSector = pars.Image.StandardFormat.Layout.Data[sectorCounter]; sectorCounter++; } int sectorIndex = pars.Image.StandardFormat.FindSectorIndex(diskSector.SectorNumber); int diskSectorNum = track * Params.SectorsOnTrack + sectorIndex; skip++; if ((sectors[sectorIndex] & 1) != 0) { continue; } sectors[sectorIndex] |= 1; processedSectors++; if ((sectors[sectorIndex] & 4) != 0) { continue; } if (diskSectorNum < pars.FirstSectorNum || diskSectorNum >= pars.LastSectorNum) { continue; } if (pars.Image.Sectors[diskSectorNum] == SectorProcessResult.Good) { continue; } bool badWritten = pars.Image.Sectors[diskSectorNum] == SectorProcessResult.Bad; skip = 0; pars.Image.Map?.ClearHighlight(MapCell.Processing); pars.Image.Map?.MarkAsProcessing(diskSectorNum); WinApi.RtlZeroMemory(memoryHandle, (UIntPtr)diskSector.SizeBytes); int error = Driver.ReadSector(DriverHandle, memoryHandle, track, diskSector.SectorNumber, pars.UpperSideHead, diskSector.SizeCode); double curTimeSinceSync = pars.CurrentTrackFormat.Timer.ElapsedMs; if (error == 0) { pars.CurrentTrackFormat.Sync(track, diskSector.SectorNumber); pars.Image.WriteGoodSectors(diskSectorNum, memoryHandle, 1); wasCorrectHead = true; if (Aborted) { return; } // Проверка несовпадения расположения секторов с заданным. Работает только для TR-DOS. if (pars.ReadMode == ReadMode.Fast && pars.TrackLayoutAutodetect && sync && !formatScanned && !missedHeaders && curTimeSinceSync < 2 * pars.CurrentTrackFormat.SpinTime) { double remainderTime = curTimeSinceSync; for (int t = 0; remainderTime > 0 && t < 20; remainderTime -= pars.CurrentTrackFormat.SpinTime, t++) { // 6 - половина времени сектора TR-DOS (около 12 мс). if (Math.Abs(remainderTime - timeAfterSync) <= 6) { goto skip; } } Log.Trace?.Out($"Несовпадение расположения секторов. Calculated Time: {GP.ToString(timeAfterSync, 2)} | Real Time: {GP.ToString(curTimeSinceSync, 2)}"); formatScanned = true; bool scanResult = ScanFormat(workTrackFormat, track, true); if (Aborted) { return; } if (scanResult) { Log.Trace?.Out($"Формат трека {track}: {workTrackFormat.FormatName} | {workTrackFormat.Layout.Cnt} sectors | {workTrackFormat.ToStringAsSectorArray()}"); if (workTrackFormat.FormatName <= TrackFormatName.TrDosGeneric) { pars.CurrentTrackFormat.Assign(workTrackFormat); } } //pars.Image.Map?.ClearHighlight(MapCell.Scanning); //findex = pars.TrackFormat.GetNextSectorIndex(track); skip :; } } else { wasError = true; bool writeBad = true; bool noHeader = error == 21 || error == 1112 || error == 1122 || (error == 27 /* && curTimeSinceSync > pars.CurrentTrackFormat.SpinTime*/); if (noHeader) { Make30HeadPositionings(error, track); // Проверка параметра Head верхней стороны. bool scanWholeTrack = true; int scanHeadResult = 0; if (track % 2 == 1 && !headScanned && !wasCorrectHead && pars.UpperSideHeadAutodetect) { headScanned = true; UpperSideHead head = pars.UpperSideHead; scanHeadResult = ScanHeadParameter(ref head, track, pars.CurrentTrackFormat); if (scanHeadResult == 0) { if (head != pars.UpperSideHead) { Log.Trace?.Out($"Параметр Head верхней стороны для трека {track} определен: {(int)head}"); pars.UpperSideHead = head; writeBad = false; sectors[sectorIndex] = 0; processedSectors--; scanWholeTrack = false; } else { Log.Trace?.Out($"Параметр Head верхней стороны для трека {track} определен и совпадает с предыдущим: {(int)head}"); } } else { Log.Trace?.Out($"Параметр Head верхней стороны для трека {track} определить не удалось."); } } // Чтение неформатных областей. // Если встретился NoHeader, то предполагается что на этом треке может быть еще много случаев NoHeader, // поэтому они проверяются сканированием трека целиком. Это происходит быстрее, чем если пытаться читать их по-отдельности. if (scanWholeTrack && !trackScanned) { int sec0Num = Math.Max(track * pars.SectorsOnTrack, pars.FirstSectorNum); int sec0NtNum = Math.Min((track + 1) * pars.SectorsOnTrack, pars.LastSectorNum); // sectorsToCheck - число секторов которые надо проверить на предмет отсутствия заголовков. // Если подозреваемый сектор только один (т.е. только что прочитанный) и число попыток чтения 1, то sectorsToCheck после цикла будет нулём. bool ignoreCurSector = pars.SectorReadAttempts == 1; writeBad = ignoreCurSector; int sectorsToCheck = ignoreCurSector ? 0 : 1; // Учет только что обработанного сектора. // Далее к sectorsToCheck добавляются только необработанные сектора. for (int sn = sec0Num, si = sn - track * pars.SectorsOnTrack; sn < sec0NtNum; sn++, si++) { if (pars.Image.Sectors[sn] != SectorProcessResult.Good && (sectors[si] & 1) == 0) { sectorsToCheck++; } } if (sectorsToCheck > 0) { trackScanned = true; int foundHeaders = 0; bool scanResult = false; int maxExtraSectors = 0; if (!ignoreCurSector) { sectors[sectorIndex] &= ~1; } int attempts = !ignoreCurSector && sectorsToCheck == 1 ? pars.SectorReadAttempts - 1 : pars.SectorReadAttempts; for (int attemptnh = 0; attemptnh < attempts; attemptnh++) { scanResult = false; if (scanHeadResult == 1 && attemptnh == 0) { workTrackFormat.Layout.Cnt = 0; } else { scanResult = ScanFormat(workTrackFormat, track, true); } if (workTrackFormat.Layout.Cnt == 0) { Log.Info?.Out($"На треке {track} заголовки не найдены."); } else { Log.Trace?.Out($"Формат трека {track}: {workTrackFormat.FormatName} | {workTrackFormat.Layout.Cnt} sectors | {workTrackFormat.ToStringAsSectorArray()}"); } for (int sn = sec0Num, si = sn - track * pars.SectorsOnTrack; sn < sec0NtNum; sn++, si++) { if (pars.Image.Sectors[sn] == SectorProcessResult.Good || (sectors[si] & 1) == 1 || (sectors[si] & 2) != 0) { continue; } int dSector = pars.Image.StandardFormat.Layout.Data[si].SectorNumber; int sindex = workTrackFormat.FindSectorIndex(dSector); int head = pars.UpperSideHead == UpperSideHead.Head1 ? track & 1 : 0; int sizeCode = pars.CurrentTrackFormat.Layout.Data[pars.CurrentTrackFormat.FindSectorIndex(dSector)].SizeCode; if (sindex >= 0 && workTrackFormat.Layout.Data[sindex].SizeCode == sizeCode) { if (workTrackFormat.Layout.Data[sindex].Cylinder == track / 2 && workTrackFormat.Layout.Data[sindex].Head == head) { sectors[si] |= 2; foundHeaders++; } else { Log.Info?.Out($"Не совпадает Cylinder или Head в заголовке сектора {dSector} на треке {track} (цилиндр {track / 2} сторона {track % 2}): {workTrackFormat.Layout.Data[sindex]}"); } } } // Поиск экстра-секторов на треке. int extraSectors = 0; for (int ii = 0; ii < workTrackFormat.Layout.Cnt; ii++) { for (int jj = 0; jj < pars.CurrentTrackFormat.Layout.Cnt; jj++) { if (pars.CurrentTrackFormat.Layout.Data[jj].SectorNumber == workTrackFormat.Layout.Data[ii].SectorNumber && pars.CurrentTrackFormat.Layout.Data[jj].SizeCode == workTrackFormat.Layout.Data[ii].SizeCode) { goto found; } } extraSectors++; found :; } if (extraSectors > maxExtraSectors) { maxExtraSectors = extraSectors; longestTrackFormat.Assign(workTrackFormat); } if (foundHeaders == sectorsToCheck) { break; } } int noHeaderCnt = 0; for (int sn = sec0Num, si = sn - track * pars.SectorsOnTrack; sn < sec0NtNum; sn++, si++) { if (pars.Image.Sectors[sn] == SectorProcessResult.Good || (sectors[si] & 1) == 1) { continue; } if ((sectors[si] & 2) == 0) { // 4 (100b) означает что заголовок не найден за нужное число попыток // и больше читать этот сектор не надо, т.к. все попытки исчерпаны. sectors[si] |= 4; if (!badWritten) { pars.Image.WriteBadSectors(sn, 1, true); } noHeaderCnt++; } } if (scanResult) { pars.CurrentTrackFormat.Sync(workTrackFormat); } Log.Trace?.Out($"На треке {track} не найдены заголовки {noHeaderCnt} секторов."); if (noHeaderCnt > 0) { missedHeaders = true; } if (maxExtraSectors > 0) { Log.Info?.Out($"Трек {track} имеет несоответствующий формат: {longestTrackFormat.GetFormatName()} | {longestTrackFormat.Layout.Cnt} sectors | {longestTrackFormat.ToStringAsSectorArray()}"); } } } } else if (error == 23) { writeBad = false; pars.Image.WriteBadSectors(diskSectorNum, memoryHandle, 1, false); } if (writeBad && !badWritten) { pars.Image.WriteBadSectors(diskSectorNum, 1, noHeader); } } if (Aborted) { return; } } Log.Trace?.Out($"Время чтения трека: {GP.ToString(trackTimer.ElapsedMs, 2)}"); trackTimer.Restart(); if (!wasError) { break; } } }
public DiskReader(DiskReaderParams pars) { Params = pars; }
public ReaderBase(Control parent, int sectorSize, int sectorsOnTrack, DiskReaderParams dparams) { Parent = parent; SectorSize = sectorSize; SectorsOnTrack = sectorsOnTrack; parent.SuspendLayout(); Params = dparams; readSide = new GroupBox() { Parent = parent, Left = 202, Top = 9, Width = 105, Height = 83, Text = "Read Side" }; side0 = new RadioButton() { Parent = readSide, Left = 6, Top = 19, Text = "Side 0", AutoSize = true }; side1 = new RadioButton() { Parent = readSide, Left = 6, Top = 39, Text = "Side 1", AutoSize = true }; sideBoth = new RadioButton() { Parent = readSide, Left = 6, Top = 60, Text = "Both", AutoSize = true, Checked = true }; sectorReadAttemptsL = new Label() { Parent = parent, Left = 312, Top = 3, Text = "Sector Read Attempts", AutoSize = true }; sectorReadAttempts = new TextBox() { Parent = parent, Left = 315, Top = 19, Text = "1" }; firstTrackL = new Label() { Parent = parent, Left = 313, Top = 44, Text = "First Track", AutoSize = true }; lastTrackL = new Label() { Parent = parent, Left = 375, Top = 44, Text = "Last Track", AutoSize = true }; firstTrack = new TextBox() { Parent = parent, Left = 315, Top = 61, Width = 56, Text = "0" }; lastTrack = new TextBox() { Parent = parent, Left = 378, Top = 61, Width = 56, Text = MainForm.MaxTrack.ToString() }; imageGB = new GroupBox() { Parent = parent, Left = 651, Top = 5, Width = 381, Height = 213, Text = "Образ" }; newImage = new Button() { Parent = imageGB, Left = 300, Top = 37, Width = 75, Height = 23, Text = "New" }; loadImage = new Button() { Parent = imageGB, Left = 300, Top = 66, Width = 75, Height = 23, Text = "Load" }; saveImage = new Button() { Parent = imageGB, Left = 300, Top = 94, Width = 75, Height = 23, Text = "Save" }; showCatalogue = new Button() { Parent = imageGB, Left = 170, Top = 184, Width = 75, Height = 23, Text = "Catalogue" }; showCatFromTrack = new Button() { Parent = imageGB, Left = 250, Top = 184, Width = 128, Height = 23, Text = "Catalogue From Track" }; setSize = new Button() { Parent = imageGB, Left = 10, Top = 184, Width = 75, Height = 23, Text = "Set Size" }; mergeImage = new Button() { Parent = imageGB, Left = 90, Top = 184, Width = 75, Height = 23, Text = "Merge" }; readForward = new Button() { Parent = parent, Left = 549, Top = 10, Width = 96, Height = 23, Text = "Read Forward" }; readBackward = new Button() { Parent = parent, Left = 549, Top = 36, Width = 96, Height = 23, Text = "Read Backward" }; readRandomSectors = new Button() { Parent = parent, Left = 511, Top = 72, Width = 134, Height = 23, Text = "Read Random Sectors" }; abortButton = new Button() { Parent = parent, Left = 568, Top = 193, Width = 75, Height = 23, Text = "Abort" }; readCatalogue = new Button() { Parent = parent, Left = 6, Top = 50, Width = 144, Height = 23, Text = "Read Catalogue" }; dataRateL = new Label() { Parent = parent, Left = 3, Top = 10, Text = "Data Rate", AutoSize = true }; dataRate = new ComboBox() { Parent = parent, Left = 6, Top = 26, Width = 121, Height = 21, DropDownStyle = ComboBoxStyle.DropDownList }; upperSidePanel = new GroupBox() { Parent = parent, Left = 316, Top = 99, Width = 156, Height = 89, Text = "Upper Side Head Parameter" }; upperSide0 = new RadioButton() { Parent = upperSidePanel, Left = 6, Top = 20, Text = "Head = 0", AutoSize = true }; upperSide1 = new RadioButton() { Parent = upperSidePanel, Left = 6, Top = 43, Text = "Head = 1", AutoSize = true }; upperSideAutodetect = new RadioButton() { Parent = upperSidePanel, Left = 6, Top = 66, Text = "Autodetect", AutoSize = true, Checked = true }; readModePanel = new GroupBox() { Parent = parent, Left = 202, Top = 99, Width = 105, Height = 62, Text = "Read Mode" }; readModeStandard = new RadioButton() { Parent = readModePanel, Left = 6, Top = 19, Text = "Standard", AutoSize = true, Checked = !Timer.IsHighResolution }; readModeFast = new RadioButton() { Parent = readModePanel, Left = 6, Top = 39, Text = "Fast", AutoSize = true, Checked = Timer.IsHighResolution, Enabled = Timer.IsHighResolution }; trackLayoutL = new Label() { Parent = parent, Left = 0, Top = 205, Text = "Sector Layout:", AutoSize = true }; trackLayoutLV = new Label() { Parent = parent, Left = 75, Top = 205, Text = "...", AutoSize = true }; drivePanel = new GroupBox() { Parent = parent, Left = 152, Top = 9, Width = 46, Height = 62, Text = "Drive" }; driveA = new RadioButton() { Parent = drivePanel, Left = 6, Top = 19, Text = "A:", AutoSize = true, Checked = Params.Drive == Drive.A }; driveB = new RadioButton() { Parent = drivePanel, Left = 6, Top = 39, Text = "B:", AutoSize = true, Checked = Params.Drive == Drive.B }; trackLayoutL.Visible = MainForm.Dev; trackLayoutLV.Visible = MainForm.Dev; for (int i = 0; i < DataRateArray.Length; i++) { dataRate.Items.Add(DataRateArray[i].ToString().Replace("FD_RATE_", "")); } dataRate.MouseWheel += DataRate_MouseWheel; FillControls(); stats = new ImageStatsTable(imageGB, SystemColors.Window, SystemColors.ControlText); stats.SetPosition(6, 16); stats.Repaint(); map = new Map(MainForm.MaxTrack, SectorSize, SectorsOnTrack, parent, Color.White, stats); map.SetPosition(0, 227); map.ReadBoundsChanged += Map_ReadBoundsChanged; map.FirstTrack = Params.FirstTrack; map.LastTrack = Params.LastTrack; map.Repaint(); sectorReadAttempts.TextChanged += SectorReadAttempts_TextChanged; firstTrack.TextChanged += SectorReadAttempts_TextChanged; lastTrack.TextChanged += SectorReadAttempts_TextChanged; side0.CheckedChanged += SectorReadAttempts_TextChanged; side1.CheckedChanged += SectorReadAttempts_TextChanged; sideBoth.CheckedChanged += SectorReadAttempts_TextChanged; dataRate.SelectedIndexChanged += SectorReadAttempts_TextChanged; upperSide0.CheckedChanged += SectorReadAttempts_TextChanged; upperSide1.CheckedChanged += SectorReadAttempts_TextChanged; readModeStandard.CheckedChanged += SectorReadAttempts_TextChanged; readModeFast.CheckedChanged += SectorReadAttempts_TextChanged; driveA.CheckedChanged += SectorReadAttempts_TextChanged; driveB.CheckedChanged += SectorReadAttempts_TextChanged; abortButton.Click += AbortButton; setSize.Click += SetSize; parent.ResumeLayout(false); }