Exemplo n.º 1
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);
        }
Exemplo n.º 2
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);
        }