From 8d7507ba270f61d09469f53e48401e0303eb476b Mon Sep 17 00:00:00 2001 From: tomascz Date: Sun, 7 Nov 2021 16:18:25 +0100 Subject: [PATCH] [#64] Internal FDD improvements and bugfixes (Part 7: Allowing for manual head calibration during dumping) --- Main/src/FDD.cpp | 5 +++++ Main/src/FDD.h | 1 + Main/src/Image.cpp | 5 +++++ Main/src/Image.h | 1 + Main/src/Image_Dump.cpp | 19 +++++++++++++++++-- 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Main/src/FDD.cpp b/Main/src/FDD.cpp index 5da6a0ec..12ff4a85 100644 --- a/Main/src/FDD.cpp +++ b/Main/src/FDD.cpp @@ -809,6 +809,11 @@ error: switch (const TStdWinError err=::GetLastError()){ return Revolution::INFINITY; } + TStdWinError CFDD::SeekHeadsHome(){ + // attempts to send Heads "home"; returns Windows standard i/o error + return fddHead.SeekHome() ? ERROR_SUCCESS : ::GetLastError(); + } + CFDD::PInternalTrack CFDD::__scanTrack__(TCylinder cyl,THead head){ // scans given Track and returns the number of discovered Sectors; returns Null if Track cannot be scanned (e.g. due to an hardware error or "out-of-range" error) // - attempting to scan the specified Track diff --git a/Main/src/FDD.h b/Main/src/FDD.h index cd18bdc7..df595057 100644 --- a/Main/src/FDD.h +++ b/Main/src/FDD.h @@ -136,6 +136,7 @@ TCylinder GetCylinderCount() const override; THead GetHeadCount() const override; BYTE GetAvailableRevolutionCount() const override; + TStdWinError SeekHeadsHome() override; TSector ScanTrack(TCylinder cyl,THead head,Codec::PType pCodec=nullptr,PSectorId bufferId=nullptr,PWORD bufferLength=nullptr,PLogTime startTimesNanoseconds=nullptr,PBYTE pAvgGap3=nullptr) const override; void GetTrackData(TCylinder cyl,THead head,Revolution::TType rev,PCSectorId bufferId,PCBYTE bufferNumbersOfSectorsToSkip,TSector nSectors,PSectorData *outBufferData,PWORD outBufferLengths,TFdcStatus *outFdcStatuses) override; TStdWinError MarkSectorAsDirty(RCPhysicalAddress chs,BYTE nSectorsToSkip,PCFdcStatus pFdcStatus) override; diff --git a/Main/src/Image.cpp b/Main/src/Image.cpp index 1d9fdbaa..ccf145d4 100644 --- a/Main/src/Image.cpp +++ b/Main/src/Image.cpp @@ -670,6 +670,11 @@ namespace Medium{ return 1; } + TStdWinError CImage::SeekHeadsHome(){ + // attempts to send Heads "home"; returns Windows standard i/o error + return ERROR_NOT_SUPPORTED; + } + TSector CImage::GetCountOfHealthySectors(TCylinder cyl,THead head) const{ // returns the number of Sectors whose data are healthy EXCLUSIVELY_LOCK_THIS_IMAGE(); diff --git a/Main/src/Image.h b/Main/src/Image.h index 78e1b2ef..68e8d5cc 100644 --- a/Main/src/Image.h +++ b/Main/src/Image.h @@ -635,6 +635,7 @@ THead GetNumberOfFormattedSides(TCylinder cyl) const; TTrack GetTrackCount() const; virtual BYTE GetAvailableRevolutionCount() const; + virtual TStdWinError SeekHeadsHome(); virtual TSector ScanTrack(TCylinder cyl,THead head,Codec::PType pCodec=nullptr,PSectorId bufferId=nullptr,PWORD bufferLength=nullptr,PLogTime startTimesNanoseconds=nullptr,PBYTE pAvgGap3=nullptr) const=0; virtual TLogTime EstimateNanosecondsPerOneByte() const; TSector GetCountOfHealthySectors(TCylinder cyl,THead head) const; diff --git a/Main/src/Image_Dump.cpp b/Main/src/Image_Dump.cpp index c6fd1bb1..e538592f 100644 --- a/Main/src/Image_Dump.cpp +++ b/Main/src/Image_Dump.cpp @@ -159,6 +159,8 @@ #define RESOLVE_EXCLUDE_ID IDIGNORE #define RESOLVE_EXCLUDE_UNKNOWN IDCONTINUE + #define RETRY_OPTIONS_COUNT 2 + #define NO_STATUS_ERROR _T("- no error\r\n") static UINT AFX_CDECL __dump_thread__(PVOID _pCancelableAction){ @@ -174,6 +176,7 @@ TPhysicalAddress chs; TTrack track; bool trackWriteable; // Track can be written at once using CImage::WriteTrack + bool canCalibrateHeads; BYTE nTrials; struct{ WORD automaticallyAcceptedErrors; @@ -185,6 +188,7 @@ } exclusion; } p; ::ZeroMemory(&p,sizeof(p)); + p.canCalibrateHeads=dp.source->SeekHeadsHome()!=ERROR_NOT_SUPPORTED; const bool targetSupportsTrackWriting=dp.target->WriteTrack(0,0,CImage::CTrackReaderWriter::Invalid)!=ERROR_NOT_SUPPORTED; const Utils::CByteIdentity sectorIdAndPositionIdentity; TPhysicalAddress chsPrev=TPhysicalAddress::Invalid; @@ -303,17 +307,28 @@ resolveActions[4].menuItemFlags=MF_GRAYED*( rFdcStatus.DescribesMissingDam() || !rFdcStatus.DescribesIdFieldCrcError()&&!rFdcStatus.DescribesDataFieldCrcError() ); // enabled only if either ID or Data field with error ConvertDlgButtonToSplitButton( IDNO, resolveActions, RESOLVE_OPTIONS_COUNT ); EnableDlgItem( IDNO, dynamic_cast(dp.target.get())==nullptr ); // recovering errors is allowed only if the Target Image can accept them + // > converting the "Retry" button to a SplitButton + static constexpr Utils::TSplitButtonAction RetryActions[RETRY_OPTIONS_COUNT]={ + { IDRETRY, _T("Retry") }, + { ID_HEAD, _T("Calibrate head and retry"), MF_GRAYED*!rp.canCalibrateHeads }, + }; + ConvertDlgButtonToSplitButton( IDRETRY, RetryActions, RETRY_OPTIONS_COUNT ); // > the "Retry" button enabled only if not all Revolutions yet exhausted - EnableDlgItem( IDRETRY, rp.nTrialsGetAvailableRevolutionCount() ); + const BYTE nRevsAvailable=dp.source->GetAvailableRevolutionCount(); + EnableDlgItem( IDRETRY, nRevsAvailable>=Revolution::MAX||rp.nTrialsSeekHeadsHome()) + Utils::Information( _T("Can't calibrate"), err, _T("Retrying without calibration.") ); + //fallthrough case IDRETRY: UpdateData(TRUE); - EndDialog(wParam); + EndDialog(IDRETRY); return 0; case ID_ERROR: rp.acceptance.automaticallyAcceptedErrors|=rFdcStatus.ToWord();