diff --git a/lib/fluxsink/hardwarefluxsink.cc b/lib/fluxsink/hardwarefluxsink.cc index 2dcb7b0c..36e16731 100644 --- a/lib/fluxsink/hardwarefluxsink.cc +++ b/lib/fluxsink/hardwarefluxsink.cc @@ -6,6 +6,7 @@ #include "usb/usb.h" #include "fluxsink/fluxsink.h" #include "lib/fluxsink/fluxsink.pb.h" +#include "lib/readerwriter.cc" #include "fmt/format.h" class HardwareFluxSink : public FluxSink @@ -14,32 +15,8 @@ public: HardwareFluxSink(const HardwareFluxSinkProto& conf): _config(conf) { - if (config.drive().has_hard_sector_count()) - { - int retries = 5; - usbSetDrive(config.drive().drive(), config.drive().high_density(), config.drive().index_mode()); - - nanoseconds_t oneRevolution = config.drive().rotational_period_ms() * 1e6; - if (oneRevolution == 0) - { - Logger() << BeginSpeedOperationLogMessage(); - - do { - oneRevolution = usbGetRotationalPeriod(config.drive().hard_sector_count()); - _hardSectorThreshold = oneRevolution * 3 / (4 * config.drive().hard_sector_count()); - retries--; - } while ((oneRevolution == 0) && (retries > 0)); - config.mutable_drive()->set_rotational_period_ms(oneRevolution / 1e6); - - Logger() << EndSpeedOperationLogMessage { oneRevolution }; - } - - if (oneRevolution == 0) { - Error() << "Failed\nIs a disk in the drive?"; - } - } - else - _hardSectorThreshold = 0; + nanoseconds_t oneRevolution; + measureDiskRotation(oneRevolution, _hardSectorThreshold); } ~HardwareFluxSink() diff --git a/lib/fluxsource/hardwarefluxsource.cc b/lib/fluxsource/hardwarefluxsource.cc index 54f6066a..165f7ed7 100644 --- a/lib/fluxsource/hardwarefluxsource.cc +++ b/lib/fluxsource/hardwarefluxsource.cc @@ -6,6 +6,7 @@ #include "usb/usb.h" #include "fluxsource/fluxsource.h" #include "lib/fluxsource/fluxsource.pb.h" +#include "lib/readerwriter.h" #include "fmt/format.h" class HardwareFluxSource : public FluxSource @@ -50,35 +51,7 @@ private: public: HardwareFluxSource(const HardwareFluxSourceProto& conf): _config(conf) { - int retries = 5; - usbSetDrive(config.drive().drive(), config.drive().high_density(), config.drive().index_mode()); - Logger() << BeginSpeedOperationLogMessage(); - - _oneRevolution = config.drive().rotational_period_ms() * 1e6; - _hardSectorThreshold = 0; - if (_oneRevolution == 0) - { - Logger() << BeginOperationLogMessage{"Measuring drive rotational speed"}; - do - { - _oneRevolution = - usbGetRotationalPeriod(config.drive().hard_sector_count()); - if (config.drive().hard_sector_count() != 0) - _hardSectorThreshold = - _oneRevolution * 3 / (4 * config.drive().hard_sector_count()); - else - _hardSectorThreshold = 0; - - retries--; - } while ((_oneRevolution == 0) && (retries > 0)); - config.mutable_drive()->set_rotational_period_ms(_oneRevolution / 1e6); - Logger() << EndOperationLogMessage{}; - } - - if (_oneRevolution == 0) - Error() << "Failed\nIs a disk in the drive?"; - - Logger() << EndSpeedOperationLogMessage{_oneRevolution}; + measureDiskRotation(_oneRevolution, _hardSectorThreshold); } ~HardwareFluxSource() {} diff --git a/lib/image.cc b/lib/image.cc index 85a40102..89a6a1bb 100644 --- a/lib/image.cc +++ b/lib/image.cc @@ -1,6 +1,7 @@ #include "globals.h" #include "sector.h" #include "image.h" +#include "layout.h" Image::Image() {} @@ -21,6 +22,20 @@ void Image::clear() _geometry = {0, 0, 0}; } +void Image::createBlankImage() +{ + clear(); + for (const auto& trackAndHead : Layout::getTrackOrdering()) + { + unsigned track = trackAndHead.first; + unsigned side = trackAndHead.second; + auto layout = Layout::getLayoutOfTrack(track, side); + Bytes blank(layout.sector_size()); + for (unsigned sectorId : Layout::getSectorsInTrack(layout)) + put(track, side, sectorId)->data = blank; + } +} + bool Image::empty() const { return _sectors.empty(); @@ -62,6 +77,15 @@ void Image::erase(unsigned track, unsigned side, unsigned sectorid) _sectors.erase(key); } +std::set> Image::tracks() const +{ + std::set> result; + for (const auto& e : _sectors) + result.insert( + std::make_pair(std::get<0>(e.first), std::get<1>(e.first))); + return result; +} + void Image::calculateSize() { _geometry = {}; diff --git a/lib/image.h b/lib/image.h index 5afcb34e..b9af10ae 100644 --- a/lib/image.h +++ b/lib/image.h @@ -56,6 +56,7 @@ public: void calculateSize(); void clear(); + void createBlankImage(); bool empty() const; bool contains(unsigned track, unsigned side, unsigned sectorId) const; std::shared_ptr get( @@ -64,6 +65,8 @@ public: unsigned track, unsigned side, unsigned sectorId); void erase(unsigned track, unsigned side, unsigned sectorId); + std::set> tracks() const; + const_iterator begin() const { return const_iterator(_sectors.cbegin()); diff --git a/lib/readerwriter.cc b/lib/readerwriter.cc index 9f1f7966..67bd3c8e 100644 --- a/lib/readerwriter.cc +++ b/lib/readerwriter.cc @@ -56,6 +56,46 @@ private: _cache; }; +void measureDiskRotation( + nanoseconds_t& oneRevolution, nanoseconds_t& hardSectorThreshold) +{ + Logger() << BeginSpeedOperationLogMessage(); + + int retries = 5; + usbSetDrive(config.drive().drive(), + config.drive().high_density(), + config.drive().index_mode()); + oneRevolution = config.drive().rotational_period_ms() * 1e6; + if (config.drive().hard_sector_count() != 0) + hardSectorThreshold = + oneRevolution * 3 / (4 * config.drive().hard_sector_count()); + else + hardSectorThreshold = 0; + + if (oneRevolution == 0) + { + Logger() << BeginOperationLogMessage{ + "Measuring drive rotational speed"}; + do + { + oneRevolution = + usbGetRotationalPeriod(config.drive().hard_sector_count()); + if (config.drive().hard_sector_count() != 0) + hardSectorThreshold = oneRevolution * 3 / + (4 * config.drive().hard_sector_count()); + + retries--; + } while ((oneRevolution == 0) && (retries > 0)); + config.mutable_drive()->set_rotational_period_ms(oneRevolution / 1e6); + Logger() << EndOperationLogMessage{}; + } + + if (oneRevolution == 0) + Error() << "Failed\nIs a disk in the drive?"; + + Logger() << EndSpeedOperationLogMessage{oneRevolution}; +} + /* Given a set of sectors, deduplicates them sensibly (e.g. if there is a good * and bad version of the same sector, the bad version is dropped). */ diff --git a/lib/readerwriter.h b/lib/readerwriter.h index 5045bb6f..c5a5a1fe 100644 --- a/lib/readerwriter.h +++ b/lib/readerwriter.h @@ -14,6 +14,9 @@ class ImageWriter; class Location; class TrackFlux; +extern void measureDiskRotation( + nanoseconds_t& oneRevolution, nanoseconds_t& hardSectorThreshold); + extern void writeTracks(FluxSink& fluxSink, const std::function( const Location& location)> producer); @@ -31,9 +34,8 @@ extern void writeDiskCommand(const Image& image, extern void writeRawDiskCommand(FluxSource& fluxSource, FluxSink& fluxSink); -extern std::shared_ptr readAndDecodeTrack(FluxSource& fluxSource, - AbstractDecoder& decoder, - const Location& location); +extern std::shared_ptr readAndDecodeTrack( + FluxSource& fluxSource, AbstractDecoder& decoder, const Location& location); extern std::shared_ptr readDiskCommand( FluxSource& fluxsource, AbstractDecoder& decoder); diff --git a/lib/vfs/fluxsectorinterface.cc b/lib/vfs/fluxsectorinterface.cc index c45a0293..7c1349d3 100644 --- a/lib/vfs/fluxsectorinterface.cc +++ b/lib/vfs/fluxsectorinterface.cc @@ -116,6 +116,8 @@ public: void discardChanges() override { + _loadedTracks.clear(); + _readSectors.clear(); _changedTracks.clear(); _changedSectors.clear(); } diff --git a/lib/vfs/imagesectorinterface.cc b/lib/vfs/imagesectorinterface.cc index 61d489f3..d02222f0 100644 --- a/lib/vfs/imagesectorinterface.cc +++ b/lib/vfs/imagesectorinterface.cc @@ -3,16 +3,19 @@ #include "lib/imagereader/imagereader.h" #include "lib/imagewriter/imagewriter.h" #include "lib/image.h" +#include "lib/layout.h" +#include "lib/sector.h" +#include "lib/bytes.h" class ImageSectorInterface : public SectorInterface { public: ImageSectorInterface(std::shared_ptr reader, std::shared_ptr writer): - _image(reader->readImage()), _reader(reader), _writer(writer) { + discardChanges(); } public: @@ -47,7 +50,13 @@ public: void discardChanges() override { - _image = _reader->readImage(); + if (_reader) + _image = _reader->readImage(); + else + { + _image = std::make_shared(); + _image->createBlankImage(); + } _changed = false; } diff --git a/lib/vfs/vfs.cc b/lib/vfs/vfs.cc index db10c97c..806cfee9 100644 --- a/lib/vfs/vfs.cc +++ b/lib/vfs/vfs.cc @@ -210,30 +210,33 @@ std::unique_ptr Filesystem::createFilesystem( std::unique_ptr Filesystem::createFilesystemFromConfig() { std::shared_ptr sectorInterface; - if (config.has_flux_source()) + if (config.has_flux_source() || config.has_flux_sink()) { - std::shared_ptr fluxSource( - FluxSource::create(config.flux_source())); - std::shared_ptr decoder( - AbstractDecoder::create(config.decoder())); + std::shared_ptr fluxSource; + std::shared_ptr decoder; + std::shared_ptr fluxSink; + std::shared_ptr encoder; + if (config.flux_source().source_case() != + FluxSourceProto::SOURCE_NOT_SET) + { + fluxSource = FluxSource::create(config.flux_source()); + decoder = AbstractDecoder::create(config.decoder()); + } if (config.flux_sink().has_drive()) { - std::shared_ptr fluxSink( - FluxSink::create(config.flux_sink())); - std::shared_ptr encoder( - AbstractEncoder::create(config.encoder())); - sectorInterface = SectorInterface::createFluxSectorInterface( - fluxSource, fluxSink, encoder, decoder); + fluxSink = FluxSink::create(config.flux_sink()); + encoder = AbstractEncoder::create(config.encoder()); } - else - sectorInterface = SectorInterface::createFluxSectorInterface( - fluxSource, nullptr, nullptr, decoder); + sectorInterface = SectorInterface::createFluxSectorInterface( + fluxSource, fluxSink, encoder, decoder); } else { - std::shared_ptr reader( - ImageReader::create(config.image_reader())); + std::shared_ptr reader; std::shared_ptr writer; + if (config.image_reader().format_case() != + ImageReaderProto::FORMAT_NOT_SET) + reader = ImageReader::create(config.image_reader()); if (config.image_writer().format_case() != ImageWriterProto::FORMAT_NOT_SET) writer = ImageWriter::create(config.image_writer()); diff --git a/src/gui/layout.cpp b/src/gui/layout.cpp index 63466a7f..658effee 100644 --- a/src/gui/layout.cpp +++ b/src/gui/layout.cpp @@ -190,6 +190,11 @@ MainWindowGen::MainWindowGen( wxWindow* parent, wxWindowID id, const wxString& t gSizer9->Add( browseButton, 0, wxALL|wxEXPAND, 5 ); + formatButton = new wxButton( idlePanel, wxID_ANY, wxT("Format disk"), wxDefaultPosition, wxDefaultSize, 0 ); + + formatButton->SetBitmap( wxArtProvider::GetBitmap( wxART_DELETE, wxART_BUTTON ) ); + gSizer9->Add( formatButton, 0, wxALL|wxEXPAND, 5 ); + fgSizer8->Add( gSizer9, 1, wxEXPAND, 5 ); @@ -387,6 +392,7 @@ MainWindowGen::MainWindowGen( wxWindow* parent, wxWindowID id, const wxString& t readButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnReadButton ), NULL, this ); writeButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnWriteButton ), NULL, this ); browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnBrowseButton ), NULL, this ); + formatButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnFormatButton ), NULL, this ); this->Connect( imagerBackTool->GetId(), wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( MainWindowGen::OnBackButton ) ); imagerSaveImageButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnSaveImageButton ), NULL, this ); imagerSaveFluxButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnSaveFluxButton ), NULL, this ); @@ -427,6 +433,7 @@ MainWindowGen::~MainWindowGen() readButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnReadButton ), NULL, this ); writeButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnWriteButton ), NULL, this ); browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnBrowseButton ), NULL, this ); + formatButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnFormatButton ), NULL, this ); this->Disconnect( imagerBackTool->GetId(), wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( MainWindowGen::OnBackButton ) ); imagerSaveImageButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnSaveImageButton ), NULL, this ); imagerSaveFluxButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainWindowGen::OnSaveFluxButton ), NULL, this ); diff --git a/src/gui/layout.fbp b/src/gui/layout.fbp index 7069c78f..70011602 100644 --- a/src/gui/layout.fbp +++ b/src/gui/layout.fbp @@ -1654,6 +1654,81 @@ OnBrowseButton + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + 0 + + + Load From Art Provider; wxART_DELETE; wxART_BUTTON + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 0 + 1 + + 1 + + + 0 + 0 + wxID_ANY + Format disk + + 0 + + 0 + + + 0 + + 1 + formatButton + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnFormatButton + + diff --git a/src/gui/layout.h b/src/gui/layout.h index f4879625..aaab1cf1 100644 --- a/src/gui/layout.h +++ b/src/gui/layout.h @@ -77,6 +77,7 @@ class MainWindowGen : public wxFrame wxButton* readButton; wxButton* writeButton; wxButton* browseButton; + wxButton* formatButton; wxPanel* imagePanel; wxAuiToolBar* imagerToolbar; wxAuiToolBarItem* imagerBackTool; @@ -120,6 +121,7 @@ class MainWindowGen : public wxFrame virtual void OnReadButton( wxCommandEvent& event ) { event.Skip(); } virtual void OnWriteButton( wxCommandEvent& event ) { event.Skip(); } virtual void OnBrowseButton( wxCommandEvent& event ) { event.Skip(); } + virtual void OnFormatButton( wxCommandEvent& event ) { event.Skip(); } virtual void OnBackButton( wxCommandEvent& event ) { event.Skip(); } virtual void OnSaveImageButton( wxCommandEvent& event ) { event.Skip(); } virtual void OnSaveFluxButton( wxCommandEvent& event ) { event.Skip(); } diff --git a/src/gui/mainwindow.cc b/src/gui/mainwindow.cc index 99dbb829..0a1c0998 100644 --- a/src/gui/mainwindow.cc +++ b/src/gui/mainwindow.cc @@ -232,8 +232,8 @@ public: void OnControlsChanged(wxFileDirPickerEvent& event) { - SaveConfig(); - UpdateState(); + wxCommandEvent e; + OnControlsChanged(e); } void OnReadButton(wxCommandEvent&) @@ -472,6 +472,42 @@ public: } } + void OnFormatButton(wxCommandEvent& event) override + { + try + { + PrepareConfig(); + + visualiser->Clear(); + _filesystemModel->Clear(Path()); + _currentDisk = nullptr; + + _state = STATE_BROWSING_WORKING; + UpdateState(); + ShowConfig(); + + QueueBrowserOperation( + [this]() + { + _filesystem = Filesystem::createFilesystemFromConfig(); + _filesystemCapabilities = _filesystem->capabilities(); + _filesystemIsReadOnly = _filesystem->isReadOnly(); + + runOnUiThread( + [&]() + { + wxCommandEvent e; + OnBrowserFormatButton(e); + }); + }); + } + catch (const ErrorException& e) + { + wxMessageBox(e.message, "Error", wxOK | wxICON_ERROR); + _state = STATE_IDLE; + } + } + void OnBrowserMoreMenuButton(wxAuiToolBarEvent& event) { browserToolbar->SetToolSticky(event.GetId(), true); @@ -1295,8 +1331,6 @@ public: void UpdateState() { - bool running = wxGetApp().IsWorkerThreadRunning(); - if (_state < STATE_IDLE__LAST) { dataNotebook->SetSelection(0); @@ -1330,6 +1364,7 @@ public: { dataNotebook->SetSelection(2); + bool running = !_filesystemQueue.empty(); bool selection = browserTree->GetSelection().IsOk(); browserToolbar->EnableTool( @@ -1340,24 +1375,24 @@ public: bool needsFlushing = _filesystemNeedsFlushing; browserToolbar->EnableTool(browserInfoTool->GetId(), - (c & Filesystem::OP_GETDIRENT) && selection); + !running && (c & Filesystem::OP_GETDIRENT) && selection); browserToolbar->EnableTool(browserViewTool->GetId(), - (c & Filesystem::OP_GETFILE) && selection); + !running && (c & Filesystem::OP_GETFILE) && selection); browserToolbar->EnableTool(browserSaveTool->GetId(), - (c & Filesystem::OP_GETFILE) && selection); + !running && (c & Filesystem::OP_GETFILE) && selection); browserMoreMenu->Enable(browserAddMenuItem->GetId(), - !ro && (c & Filesystem::OP_PUTFILE)); + !running && !ro && (c & Filesystem::OP_PUTFILE)); browserMoreMenu->Enable(browserNewDirectoryMenuItem->GetId(), - !ro && (c & Filesystem::OP_CREATEDIR)); + !running && !ro && (c & Filesystem::OP_CREATEDIR)); browserMoreMenu->Enable(browserRenameMenuItem->GetId(), - !ro && (c & Filesystem::OP_MOVE) && selection); + !running && !ro && (c & Filesystem::OP_MOVE) && selection); browserMoreMenu->Enable(browserDeleteMenuItem->GetId(), - !ro && (c & Filesystem::OP_DELETE) && selection); - browserToolbar->EnableTool( - browserFormatTool->GetId(), !ro && (c & Filesystem::OP_CREATE)); + !running && !ro && (c & Filesystem::OP_DELETE) && selection); + browserToolbar->EnableTool(browserFormatTool->GetId(), + !running && !ro && (c & Filesystem::OP_CREATE)); - browserDiscardButton->Enable(needsFlushing); - browserCommitButton->Enable(needsFlushing); + browserDiscardButton->Enable(!running && needsFlushing); + browserCommitButton->Enable(!running && needsFlushing); } Refresh();