From 0c55bcb45f726da6b9d81bc4f2a3f918b0d710ee Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Sat, 21 Aug 2021 21:05:00 +0200 Subject: [PATCH 01/16] switch to uint32_t --- ArduinoFloppyReader/lib/ADFWriter.cpp | 66 ++++++++++---------- ArduinoFloppyReader/lib/ArduinoInterface.cpp | 12 ++-- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/ArduinoFloppyReader/lib/ADFWriter.cpp b/ArduinoFloppyReader/lib/ADFWriter.cpp index 3b39bf7..4eff24a 100644 --- a/ArduinoFloppyReader/lib/ADFWriter.cpp +++ b/ArduinoFloppyReader/lib/ADFWriter.cpp @@ -89,13 +89,13 @@ typedef struct alignas(8) { unsigned char sectorNumber; // The sector we just read (0 to 11) unsigned char sectorsRemaining; // How many more sectors remain until the gap (0 to 10) - unsigned long sectorLabel[4]; // OS Recovery Data, we ignore this + uint32_t sectorLabel[4]; // OS Recovery Data, we ignore this - unsigned long headerChecksum; // Read from the header, header checksum - unsigned long dataChecksum; // Read from the header, data checksum + uint32_t headerChecksum; // Read from the header, header checksum + uint32_t dataChecksum; // Read from the header, data checksum - unsigned long headerChecksumCalculated; // The header checksum we calculate - unsigned long dataChecksumCalculated; // The data checksum we calculate + uint32_t headerChecksumCalculated; // The header checksum we calculate + uint32_t dataChecksumCalculated; // The data checksum we calculate RawDecodedSector data; // decoded sector data @@ -116,15 +116,15 @@ struct DecodedTrack { // *input; MFM coded data buffer (size == 2*data_size) // *output; decoded data buffer (size == data_size) // Returns the checksum calculated over the data -unsigned long decodeMFMdata(const unsigned long* input, unsigned long* output, const unsigned int data_size) { - unsigned long odd_bits, even_bits; - unsigned long chksum = 0L; +uint32_t decodeMFMdata(const uint32_t* input, uint32_t* output, const unsigned int data_size) { + uint32_t odd_bits, even_bits; + uint32_t chksum = 0L; unsigned int count; // the decoding is made here long by long : with data_size/4 iterations for (count = 0; count < data_size / 4; count++) { odd_bits = *input; // longs with odd bits - even_bits = *(unsigned long*)(((unsigned char*)input) + data_size); // longs with even bits - located 'data_size' bytes after the odd bits + even_bits = *(uint32_t*)(((unsigned char*)input) + data_size); // longs with even bits - located 'data_size' bytes after the odd bits chksum ^= odd_bits; // XOR Checksum chksum ^= even_bits; @@ -140,12 +140,12 @@ unsigned long decodeMFMdata(const unsigned long* input, unsigned long* output, c // *input; RAW data buffer (size == data_size) // *output; MFM encoded buffer (size == data_size*2) // Returns the checksum calculated over the data -unsigned long encodeMFMdataPart1(const unsigned long* input, unsigned long* output, const unsigned int data_size) { - unsigned long chksum = 0L; +uint32_t encodeMFMdataPart1(const uint32_t* input, uint32_t* output, const unsigned int data_size) { + uint32_t chksum = 0L; unsigned int count; - unsigned long* outputOdd = output; - unsigned long* outputEven = (unsigned long*)(((unsigned char*)output) + data_size); + uint32_t* outputOdd = output; + uint32_t* outputEven = (uint32_t*)(((unsigned char*)output) + data_size); // Encode over two passes. First split out the odd and even data, then encode the MFM values, the /4 is because we're working in longs, not bytes for (count = 0; count < data_size / 4; count++) { @@ -301,11 +301,11 @@ bool decodeSector(const RawEncodedSector& rawSector, const unsigned int trackNum unsigned char* sectorData = (unsigned char*)rawSector; // Read the first 4 bytes (8). This is the track header data - sector.headerChecksumCalculated = decodeMFMdata((unsigned long*)(sectorData + 8), (unsigned long*)§or, 4); + sector.headerChecksumCalculated = decodeMFMdata((uint32_t*)(sectorData + 8), (uint32_t*)§or, 4); // Decode the label data and update the checksum - sector.headerChecksumCalculated ^= decodeMFMdata((unsigned long*)(sectorData + 16), (unsigned long*)§or.sectorLabel[0], 16); + sector.headerChecksumCalculated ^= decodeMFMdata((uint32_t*)(sectorData + 16), (uint32_t*)§or.sectorLabel[0], 16); // Get the checksum for the header - decodeMFMdata((unsigned long*)(sectorData + 48), (unsigned long*)§or.headerChecksum, 4); // (computed on mfm longs, longs between offsets 8 and 44 == 2 * (1 + 4) longs) + decodeMFMdata((uint32_t*)(sectorData + 48), (uint32_t*)§or.headerChecksum, 4); // (computed on mfm longs, longs between offsets 8 and 44 == 2 * (1 + 4) longs) // If the header checksum fails we just cant trust anything we received, so we just drop it if ((sector.headerChecksum != sector.headerChecksumCalculated) && (!ignoreHeaderChecksum)) { return false; @@ -329,7 +329,7 @@ bool decodeSector(const RawEncodedSector& rawSector, const unsigned int trackNum if (sector.trackNumber != targetTrackNumber) return false; // this'd be weird // Get the checksum for the data - decodeMFMdata((unsigned long*)(sectorData + 56), (unsigned long*)§or.dataChecksum, 4); + decodeMFMdata((uint32_t*)(sectorData + 56), (uint32_t*)§or.dataChecksum, 4); // Lets see if we already have this one @@ -342,7 +342,7 @@ bool decodeSector(const RawEncodedSector& rawSector, const unsigned int trackNum if (index != decodedTrack.validSectors.end()) return true; // Decode the data and receive it's checksum - sector.dataChecksumCalculated = decodeMFMdata((unsigned long*)(sectorData + 64), (unsigned long*)§or.data[0], SECTOR_BYTES); // (from 64 to 1088 == 2*512 bytes) + sector.dataChecksumCalculated = decodeMFMdata((uint32_t*)(sectorData + 64), (uint32_t*)§or.data[0], SECTOR_BYTES); // (from 64 to 1088 == 2*512 bytes) // Is the data valid? if (sector.dataChecksum != sector.dataChecksumCalculated) { @@ -384,15 +384,15 @@ void encodeSector(const unsigned int trackNumber, const DiskSurface surface, con header.sectorsRemaining = NUM_SECTORS_PER_TRACK - sectorNumber; //1..11 - header.headerChecksumCalculated = encodeMFMdataPart1((const unsigned long*)&header, (unsigned long*)&encodedSector[8], 4); + header.headerChecksumCalculated = encodeMFMdataPart1((const uint32_t*)&header, (uint32_t*)&encodedSector[8], 4); // Then theres the 16 bytes of the volume label that isnt used anyway - header.headerChecksumCalculated ^= encodeMFMdataPart1((const unsigned long*)&header.sectorLabel, (unsigned long*)&encodedSector[16], 16); + header.headerChecksumCalculated ^= encodeMFMdataPart1((const uint32_t*)&header.sectorLabel, (uint32_t*)&encodedSector[16], 16); // Thats 40 bytes written as everything doubles (8+4+4+16+16). - Encode the header checksum - encodeMFMdataPart1((const unsigned long*)&header.headerChecksumCalculated, (unsigned long*)&encodedSector[48], 4); + encodeMFMdataPart1((const uint32_t*)&header.headerChecksumCalculated, (uint32_t*)&encodedSector[48], 4); // And move on to the data section. Next should be the checksum, but we cant encode that until we actually know its value! - header.dataChecksumCalculated = encodeMFMdataPart1((const unsigned long*)&input, (unsigned long*)&encodedSector[64], SECTOR_BYTES); + header.dataChecksumCalculated = encodeMFMdataPart1((const uint32_t*)&input, (uint32_t*)&encodedSector[64], SECTOR_BYTES); // And add the checksum - encodeMFMdataPart1( (const unsigned long*)&header.dataChecksumCalculated, (unsigned long*)&encodedSector[56], 4); + encodeMFMdataPart1( (const uint32_t*)&header.dataChecksumCalculated, (uint32_t*)&encodedSector[56], 4); // Now fill in the MFM clock bits bool lastBit = encodedSector[7] & (1 << 0); @@ -418,14 +418,14 @@ void encodeSector(const unsigned int trackNumber, const DiskSurface surface, con // Find sectors within raw data read from the drive by searching bit-by-bit for the SYNC bytes void findSectors(const RawTrackData& track, unsigned int trackNumber, DiskSurface side, unsigned short trackSync, DecodedTrack& decodedTrack, bool ignoreHeaderChecksum) { // Work out what we need to search for which is 2AAAAAAAsyncsync - //const unsigned long long search = (trackSync | (((DWORD)trackSync) << 16)) | (((long long)0x2AAAAAAA) << 32); + //const uint32_t long search = (trackSync | (((DWORD)trackSync) << 16)) | (((long long)0x2AAAAAAA) << 32); // For speed and to ignore some data errors, we now just search for syncsync and ignore the 2AAAAAAA part // Work out what we need to search for which is syncsync - const unsigned long search = (trackSync | (((unsigned long)trackSync) << 16)); + const uint32_t search = (trackSync | (((uint32_t)trackSync) << 16)); // Prepare our test buffer - unsigned long decoded = 0; + uint32_t decoded = 0; // Keep runnign until we run out of data unsigned int byteIndex = 0; @@ -1243,7 +1243,7 @@ struct SCPFileHeader { unsigned char bitcellEncoding; unsigned char numHeads; unsigned char timeBase; - unsigned long checksum; + uint32_t checksum; }; struct SCPTrackHeader { @@ -1252,9 +1252,9 @@ struct SCPTrackHeader { }; struct SCPTrackRevolution { - unsigned long indexTime; // Time in NS/25 for this revolution - unsigned long trackLength; // Number of bit-cells in this revolution - unsigned long dataOffset; // From the start of SCPTrackHeader + uint32_t indexTime; // Time in NS/25 for this revolution + uint32_t trackLength; // Number of bit-cells in this revolution + uint32_t dataOffset; // From the start of SCPTrackHeader }; // Track data is 16-bit value in NS/25. If =0 means no flux transition for max time @@ -1324,7 +1324,7 @@ ADFResult ADFWriter::DiskToSCP(const std::wstring& outputFile, const unsigned in } // Pad out the records. Theres 4 bytes for each track - unsigned long notPresent = 0; + uint32_t notPresent = 0; for (unsigned int a = 0; a <168; a++) { try { hADFFile.write((const char*)¬Present, sizeof(notPresent)); @@ -1433,7 +1433,7 @@ ADFResult ADFWriter::DiskToSCP(const std::wstring& outputFile, const unsigned in } // Get the current position - unsigned long currentPosition = (unsigned long)hADFFile.tellp(); + uint32_t currentPosition = (uint32_t)hADFFile.tellp(); // Move to the beginning of the file, and write the offset for where this starts hADFFile.seekp(sizeof(header) + (track.header.trackNumber * 4), std::fstream::beg); @@ -1487,7 +1487,7 @@ ADFResult ADFWriter::DiskToSCP(const std::wstring& outputFile, const unsigned in while (hADFFile.good()) { try { hADFFile.read((char*)buffer, sizeof(buffer)); - const unsigned long read = sizeof(buffer) / 4; + const uint32_t read = sizeof(buffer) / 4; for (size_t pos = 0; pos < read; pos++) header.checksum += buffer[pos]; } diff --git a/ArduinoFloppyReader/lib/ArduinoInterface.cpp b/ArduinoFloppyReader/lib/ArduinoInterface.cpp index 1843172..74f8bfc 100644 --- a/ArduinoFloppyReader/lib/ArduinoInterface.cpp +++ b/ArduinoFloppyReader/lib/ArduinoInterface.cpp @@ -265,7 +265,7 @@ DiagnosticResponse ArduinoInterface::testTransferSpeed() { unsigned char buffer[256]; for (int a = 0; a <= 10; a++) { - unsigned long read; + uint32_t read; read = m_comPort.read(buffer, sizeof(buffer)); @@ -340,7 +340,7 @@ DiagnosticResponse ArduinoInterface::attemptToSync(std::string& versionString, S buffer[0] = SPECIAL_ABORT_CHAR; buffer[1] = COMMAND_VERSION; - unsigned long size = port.write(&buffer[0], 2); + uint32_t size = port.write(&buffer[0], 2); if (size != 2) { // Couldn't write to device port.closePort(); @@ -462,7 +462,7 @@ DiagnosticResponse ArduinoInterface::openPort(const std::wstring& portName, bool char buffer[2]; int counter = 0; for (;;) { - unsigned long size = m_comPort.read(buffer, 1); + uint32_t size = m_comPort.read(buffer, 1); if (size < 1) if (counter++>=10) break; } @@ -931,10 +931,10 @@ DiagnosticResponse ArduinoInterface::readRotation(RotationExtractor& extractor, for (;;) { // More efficient to read several bytes in one go - unsigned long bytesAvailable = m_comPort.getBytesWaiting(); + uint32_t bytesAvailable = m_comPort.getBytesWaiting(); if (bytesAvailable < 1) bytesAvailable = 1; if (bytesAvailable > sizeof(tempReadBuffer)) bytesAvailable = sizeof(tempReadBuffer); - unsigned long bytesRead = m_comPort.read(tempReadBuffer, m_abortSignalled ? 1 : bytesAvailable); + uint32_t bytesRead = m_comPort.read(tempReadBuffer, m_abortSignalled ? 1 : bytesAvailable); for (size_t a = 0; a < bytesRead; a++) { @@ -1327,7 +1327,7 @@ DiagnosticResponse ArduinoInterface::runCommand(const char command, const char p bool ArduinoInterface::deviceRead(void* target, const unsigned int numBytes, const bool failIfNotAllRead) { if (!m_comPort.isPortOpen()) return false; - unsigned long read = m_comPort.read(target, numBytes); + uint32_t read = m_comPort.read(target, numBytes); if (read < numBytes) { if (failIfNotAllRead) return false; From 31495c20bd565a9e6e3e283e7b6dfe8a7b2a1fc3 Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Fri, 10 Sep 2021 22:14:43 +0200 Subject: [PATCH 02/16] GTK+ GUI --- ArduinoFloppyReader/.gitignore | 5 + .../ArduinoFloppyReader/Garduino.glade | 571 ++++++++++++++++++ .../GarduinoReaderWriter.cpp | 387 ++++++++++++ .../ArduinoFloppyReader/makefile | 22 +- 4 files changed, 979 insertions(+), 6 deletions(-) create mode 100644 ArduinoFloppyReader/ArduinoFloppyReader/Garduino.glade create mode 100644 ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp diff --git a/ArduinoFloppyReader/.gitignore b/ArduinoFloppyReader/.gitignore index 4ce6fdd..b490478 100644 --- a/ArduinoFloppyReader/.gitignore +++ b/ArduinoFloppyReader/.gitignore @@ -27,6 +27,11 @@ bld/ [Oo]bj/ [Ll]og/ +ArduinoReaderWriter +GarduinoReaderWriter +*~ +.vscode/ + # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot diff --git a/ArduinoFloppyReader/ArduinoFloppyReader/Garduino.glade b/ArduinoFloppyReader/ArduinoFloppyReader/Garduino.glade new file mode 100644 index 0000000..85b1f55 --- /dev/null +++ b/ArduinoFloppyReader/ArduinoFloppyReader/Garduino.glade @@ -0,0 +1,571 @@ + + + + + + 500 + 300 + False + Arduino Amiga Floppy Disk Reader and Writer + + + True + False + vertical + 5 + + + True + False + 0 + + + True + False + 1 + 1 + 12 + 12 + + + True + False + 20 + True + + + True + False + Arduino connected on: + + + False + True + 0 + + + + + True + False + + + False + True + 1 + + + + + Run Diagnostics + True + False + True + True + + + False + True + 2 + + + + + + + + + True + False + 10 + Arduino Configuration + + + + + + False + True + 0 + + + + + True + False + 0 + + + True + False + 10 + 10 + 12 + 12 + + + True + False + vertical + + + True + False + + + True + False + Save to + + + False + True + 0 + + + + + True + False + 1 + + ADF + SCP + + + + False + True + 1 + + + + + True + True + + + True + True + 2 + + + + + True + False + select-folder + + + + False + True + 3 + + + + + Copy Disk + True + False + True + True + + + False + True + 4 + + + + + False + True + 0 + + + + + True + False + + + True + False + SCP will have limited resolution enough for most Amiga disks. + + + True + True + 0 + + + + + True + False + Tracks: + + + False + True + 1 + + + + + 80 + True + True + False + True + True + radio82 + + + False + True + 10 + 2 + + + + + 82 + True + True + False + True + True + radio80 + + + False + True + end + 2 + + + + + False + True + 1 + + + + + True + False + + + Always Ignore Read Errors + True + True + False + True + True + + + True + True + 0 + + + + + False + True + 2 + + + + + + + + + True + False + 10 + Copy Disk to ADF or SCP File (read) + + + + + False + True + 6 + 1 + + + + + True + False + 0 + + + True + False + 12 + 12 + + + True + False + vertical + + + True + False + + + True + False + ADF File: + + + False + True + 0 + + + + + True + False + + + + True + True + 1 + + + + + Write Disk + True + False + True + True + + + False + True + 2 + + + + + False + True + 0 + + + + + True + False + + + Verify Write + True + True + False + True + + + True + True + 0 + + + + + Use Write Compensation (V1.8+ firmware) + True + True + False + True + + + True + True + end + 1 + + + + + False + True + 1 + + + + + True + False + With precomp do not use a USB hub and try to use a USB2 port if possible + + + False + True + 2 + + + + + + + + + True + False + 10 + Write ADF File to Disk (write) + + + + + False + True + 6 + 2 + + + + + True + False + 12 + + + True + False + Cylinder: + + + True + True + 0 + + + + + True + False + 0 + + + True + True + 1 + + + + + True + False + Current Side: + + + True + True + 2 + + + + + True + False + Upper + + + True + True + 3 + + + + + True + False + Good Sectors: + + + True + True + 4 + + + + + True + False + 0 + + + True + True + 5 + + + + + True + False + Partial Sectors + + + True + True + 6 + + + + + True + False + 0 + + + True + True + 7 + + + + + False + True + 6 + 3 + + + + + statusBar + True + False + 10 + 10 + 10 + 10 + 6 + 6 + vertical + + + False + True + end + 4 + + + + + + diff --git a/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp b/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp new file mode 100644 index 0000000..d3c3e20 --- /dev/null +++ b/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp @@ -0,0 +1,387 @@ +#include +#include +#include +#include +#include +#include +#include "../lib/ArduinoInterface.h" +#include "../lib/ADFWriter.h" + +enum Tracks +{ + eighty = 80, + eightytwo = 82, +}; + +enum ReadType +{ + ADF = 1, + SCP = 2, +}; + +class WindowState +{ +public: + Glib::ustring serialPort; + ReadType type; + Tracks tracks; + bool verify; + bool writeCompensation; + Glib::ustring readFileName; + Glib::ustring readFolder; + Glib::ustring writeFileName; +}; + +class MainWindow : public Gtk::ApplicationWindow +{ +public: + MainWindow(BaseObjectType *obj, Glib::RefPtr const &builder) + : Gtk::ApplicationWindow(obj), builder{builder} + { + get_widgets(); + std::vector portList; + ArduinoFloppyReader::ArduinoInterface::enumeratePorts(portList); + for (std::wstring port : portList) + { + const std::string portString(port.begin(), port.end()); + Glib::ustring text = Glib::ustring(portString.c_str(), port.size()); + portsCombo->append(text); + } + if (portList.size() > 0) + { + portsCombo->set_active(0); + diagnosticsButton->set_sensitive(true); + } + diagnosticsButton->signal_clicked().connect([this]() + { + Glib::ustring serial = portsCombo->get_active_text(); + run_diagnostics(serial); + }); + + auto readerCallback = [this](const int currentTrack, const ArduinoFloppyReader::DiskSurface currentSide, const int retryCounter, const int sectorsFound, const int badSectorsFound) -> ArduinoFloppyReader::WriteResponse + { + std::string side = (currentSide == ArduinoFloppyReader::DiskSurface::dsUpper ? "Upper" : "Lower"); + std::cout << "currentTrack: " << currentTrack << " side: " << side << " retryCount: " << retryCounter << std::endl; + cylinderCount->set_text(Glib::ustring::sprintf("%i", currentTrack)); + goodCount->set_text(Glib::ustring::sprintf("%i", sectorsFound)); + partialCount->set_text(Glib::ustring::sprintf("%i", badSectorsFound)); + sideLabel->set_text(side); + while (gtk_events_pending()) + gtk_main_iteration(); + + if (retryCounter > 20) + { + if (alwaysIgnore->get_active()) + { + return ArduinoFloppyReader::WriteResponse::wrSkipBadChecksums; + } + Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "Verify error writing track.\nDisk Write Error", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_NONE); + dialog.add_button("Abort", 1); + dialog.add_button("Retry", 2); + dialog.add_button("Ignore", 3); + int response = dialog.run(); + dialog.hide(); + + switch (response) + { + case 1: + return ArduinoFloppyReader::WriteResponse::wrAbort; + case 2: + return ArduinoFloppyReader::WriteResponse::wrRetry; + case 3: + return ArduinoFloppyReader::WriteResponse::wrSkipBadChecksums; + } + + } + + // Just continue + return ArduinoFloppyReader::WriteResponse::wrContinue; + }; + + fileEntry->signal_changed().connect([this]() + { + if (fileEntry->get_text_length() > 0 && diagnosticsButton->get_sensitive()) + { + copyButton->set_sensitive(true); + } + else + { + copyButton->set_sensitive(false); + } + }); + copyButton->signal_clicked().connect([this, readerCallback]() + { + Glib::ustring folder = folderButton->get_filename(); + Glib::ustring filename = folder + "/" + fileEntry->get_buffer()->get_text(); + ArduinoFloppyReader::ADFWriter writer; + Glib::ustring serial = portsCombo->get_active_text(); + writer.openDevice(std::wstring(serial.begin(), serial.end())); + bool tracks80 = trackButton->get_active(); + ArduinoFloppyReader::ADFResult readerResult; + if (typeSelector->get_active_text() == "ADF") + { + readerResult = writer.DiskToADF(std::wstring(filename.begin(), filename.end()), tracks80 ? 80 : 82, readerCallback); + } + else + { + readerResult = writer.DiskToSCP(std::wstring(filename.begin(), filename.end()), tracks80 ? 80 : 82, 3, readerCallback); + } + // Handle the result + handleResult(writer, readerResult); + }); + + writeFolderSelector->signal_file_set().connect([this]() + { + std::cout<< "got filename" << writeFolderSelector->get_filename() << std::endl; + if (this->writeFolderSelector->get_filename() != "" && diagnosticsButton->get_sensitive()) + { + writeButton->set_sensitive(true); + } + else + { + writeButton->set_sensitive(false); + } + }); + auto writerCallback = [this](const int currentTrack, const ArduinoFloppyReader::DiskSurface currentSide, const bool isVerifyError) -> ArduinoFloppyReader::WriteResponse + { + std::string side = (currentSide == ArduinoFloppyReader::DiskSurface::dsUpper ? "Upper" : "Lower"); + std::cout << "writing: currentTrack: " << currentTrack << " side: " << side << std::endl; + + cylinderCount->set_text(Glib::ustring::sprintf("%i", currentTrack)); + sideLabel->set_text(side); + if (isVerifyError) + { + Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "Verify error writing track.\nDisk Write Error", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_NONE); + dialog.add_button("Abort", 1); + dialog.add_button("Retry", 2); + dialog.add_button("Ignore", 3); + int response = dialog.run(); + dialog.hide(); + + switch (response) + { + case 1: + return ArduinoFloppyReader::WriteResponse::wrAbort; + case 2: + return ArduinoFloppyReader::WriteResponse::wrRetry; + case 3: + return ArduinoFloppyReader::WriteResponse::wrSkipBadChecksums; + } + } + // Just continue + return ArduinoFloppyReader::WriteResponse::wrContinue; + }; + writeButton->signal_clicked().connect([this, writerCallback]() + { + Glib::ustring filename = writeFolderSelector->get_filename(); + ArduinoFloppyReader::ADFWriter writer; + Glib::ustring serial = portsCombo->get_active_text(); + writer.openDevice(std::wstring(serial.begin(), serial.end())); + ArduinoFloppyReader::ADFResult readerResult; + readerResult = writer.ADFToDisk(std::wstring(filename.begin(), filename.end()), verify->get_active(), writeCompensation->get_active(), writerCallback); + // Handle the result + handleResult(writer, readerResult); + }); + } + + virtual ~MainWindow() = default; + +private: + Glib::RefPtr builder; + Gtk::ComboBoxText *portsCombo = nullptr; + Gtk::Button *diagnosticsButton = nullptr; + Gtk::Button *copyButton = nullptr; + Gtk::Label *cylinderCount = nullptr; + Gtk::Label *sideLabel = nullptr; + Gtk::Label *goodCount = nullptr; + Gtk::Label *partialCount = nullptr; + Gtk::CheckButton *verify = nullptr; + Gtk::CheckButton *alwaysIgnore = nullptr; + Gtk::CheckButton *writeCompensation = nullptr; + Gtk::FileChooserButton *writeFolderSelector = nullptr; + Gtk::Button *writeButton = nullptr; + Gtk::Entry *fileEntry = nullptr; + Gtk::FileChooserButton *folderButton = nullptr; + Gtk::ComboBoxText *typeSelector = nullptr; + Gtk::RadioButton *trackButton = nullptr; + Gtk::Statusbar *statusBar = nullptr; + + void get_widgets() + { + builder->get_widget("serialPortsCombo", portsCombo); + builder->get_widget("diagnosticsButton", diagnosticsButton); + builder->get_widget("copyButton", copyButton); + builder->get_widget("cylinderCount", cylinderCount); + builder->get_widget("sideLabel", sideLabel); + builder->get_widget("goodCount", goodCount); + builder->get_widget("partialCount", partialCount); + builder->get_widget("fileNameEntry", fileEntry); + builder->get_widget("folderSelector", folderButton); + builder->get_widget("typeSelector", typeSelector); + builder->get_widget("radio80", trackButton); + builder->get_widget("alwaysIgnore", alwaysIgnore); + builder->get_widget("verify", verify); + builder->get_widget("writeCompensation", writeCompensation); + builder->get_widget("writeFolderSelector", writeFolderSelector); + builder->get_widget("writeButton", writeButton); + builder->get_widget("statusBar", statusBar); + } + + void reset() + { + cylinderCount->set_text("0"); + goodCount->set_text("0"); + partialCount->set_text("0"); + sideLabel->set_text("Upper"); + } + + void handleResult(ArduinoFloppyReader::ADFWriter writer, ArduinoFloppyReader::ADFResult readerResult) + { + switch (readerResult) + { + case ArduinoFloppyReader::ADFResult::adfrComplete: + { + Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "Completed", false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK); + dialog.run(); + dialog.hide(); + break; + } + case ArduinoFloppyReader::ADFResult::adfrAborted: + { + Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "Aborted", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); + dialog.run(); + dialog.hide(); + break; + } + case ArduinoFloppyReader::ADFResult::adfrFileError: + { + Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "Unable to open the specified file to write to it.\nOutput File Error", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); + dialog.run(); + dialog.hide(); + break; + } + case ArduinoFloppyReader::ADFResult::adfrFileIOError: + { + Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "An error occured writing to the specified file.\nOutput File Error", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); + dialog.run(); + dialog.hide(); + break; + } + case ArduinoFloppyReader::ADFResult::adfrFirmwareTooOld: + { + Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "This requires firmware V1.8 or newer.\nFirmware out of date", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); + dialog.run(); + dialog.hide(); + break; + } + case ArduinoFloppyReader::ADFResult::adfrDiskWriteProtected: + { + Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "The disk is write protected", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); + dialog.run(); + dialog.hide(); + break; + } + case ArduinoFloppyReader::ADFResult::adfrCompletedWithErrors: + { + Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, "Completed with some errors", false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK); + dialog.run(); + dialog.hide(); + break; + } + case ArduinoFloppyReader::ADFResult::adfrDriveError: + { + std::string msg = "An error occured communicating with the Arduino interface:\r\n\r\n"; + msg += writer.getLastError(); + Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, msg.c_str(), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); + dialog.run(); + dialog.hide(); + break; + } + } + reset(); + } + + bool showQuestion(bool isQuestion, const std::string question) + { + Gtk::ButtonsType buttons = Gtk::BUTTONS_OK_CANCEL; + if (isQuestion) + { + buttons = Gtk::BUTTONS_YES_NO; + } + + Gtk::MessageDialog dialog = Gtk::MessageDialog(*this, question, false, Gtk::MESSAGE_QUESTION, buttons); + int Answer = dialog.run(); + dialog.hide(); + + // Process user choice + bool isYes = false; + switch (Answer) + { + case (Gtk::RESPONSE_OK): + isYes = true; + break; + case (Gtk::RESPONSE_CANCEL): + std::cout << "Cancel clicked." << std::endl; + break; + case (Gtk::RESPONSE_YES): + std::cout << "Yes clicked." << std::endl; + isYes = true; + break; + case (Gtk::RESPONSE_NO): + std::cout << "No clicked." << std::endl; + break; + default: + std::cout << "Unexpected button clicked." << std::endl; + break; + } + return isYes; + } + + void showStatus(bool isError, std::string status) + { + std::string strLine; + + if (isError) + strLine = "DIAGNOSTICS FAILED: "; + strLine += status.c_str(); + std::cerr << strLine << std::endl; + statusBar->pop(); + statusBar->push(strLine); + } + + void run_diagnostics(Glib::ustring serial) + { + ArduinoFloppyReader::ADFWriter writer; + writer.runDiagnostics( + std::wstring(serial.begin(), serial.end()), [this, serial](bool isError, const std::string message) -> void + { + while (gtk_events_pending()) + gtk_main_iteration(); + this->showStatus(isError, message); + }, + [this, serial](bool isQuestion, const std::string question) -> bool + { + while (gtk_events_pending()) + gtk_main_iteration(); + return this->showQuestion(isQuestion, question); + }); + } +}; + +int main(int argc, char *argv[]) +{ + auto app = Gtk::Application::create(argc, argv, "be.sourcery.Garduino"); + auto builder = Gtk::Builder::create(); + + builder->add_from_file("Garduino.glade"); + + MainWindow *wnd = nullptr; + + builder->get_widget_derived("MainWindow", wnd); + + auto r = app->run(*wnd); + + delete wnd; + + return r; +} diff --git a/ArduinoFloppyReader/ArduinoFloppyReader/makefile b/ArduinoFloppyReader/ArduinoFloppyReader/makefile index 9453425..edb080b 100644 --- a/ArduinoFloppyReader/ArduinoFloppyReader/makefile +++ b/ArduinoFloppyReader/ArduinoFloppyReader/makefile @@ -9,7 +9,8 @@ CC = g++ # define any compile-time flags -CFLAGS = -Wall -std=c++14 -Wno-psabi -O3 +CFLAGS = -Wall -std=c++14 -Wno-psabi -O0 +GCFLAGS = ${CFLAGS} $(shell pkg-config --cflags gtkmm-3.0) # define any directories containing header files other than /usr/include # @@ -19,15 +20,17 @@ INCLUDES = -I../lib # if I wanted to include libraries not in /usr/lib I'd specify # their path using -Lpath, something like: LFLAGS = -L../lib +GLFLAGS = ${LFLAGS} $(shell pkg-config --libs gtkmm-3.0) # define any libraries to link into executable: # if I want to link in libraries (libx.so or libx.a) I use the -llibname # option, something like (this will link in libmylib.so and libm.so: LIBS = -# define the C source files -SRCS = Main.cpp ../lib/SerialIO.cpp ../lib/RotationExtractor.cpp ../lib/ArduinoInterface.cpp ../lib/ADFWriter.cpp - +# define the C surce files +COMMON_SRC = ../lib/SerialIO.cpp ../lib/RotationExtractor.cpp ../lib/ArduinoInterface.cpp ../lib/ADFWriter.cpp +SRCS = Main.cpp ${COMMON_SRC} +GSRCS = GarduinoReaderWriter.cpp ${COMMON_SRC} # define the C object files # # This uses Suffix Replacement within a macro: @@ -37,10 +40,14 @@ SRCS = Main.cpp ../lib/SerialIO.cpp ../lib/RotationExtractor.cpp ../lib/ArduinoI # with the .o suffix # OBJS = $(SRCS:.c=.o) +GOBJS = $(GSRCS:.c=.o) # define the executable file MAIN = ArduinoReaderWriter +#GUI +GARDUINO = GarduinoReaderWriter + # # The following part of the makefile is generic; it can be used to # build any executable just by changing the definitions above and by @@ -49,12 +56,15 @@ MAIN = ArduinoReaderWriter .PHONY: depend clean -all: $(MAIN) +all: $(MAIN) $(GARDUINO) @echo ArduinoReaderWriter ready $(MAIN): $(OBJS) $(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS) +$(GARDUINO): $(GOBJS) makefile Garduino.glade + $(CC) $(GCFLAGS) $(INCLUDES) -o $(GARDUINO) $(GOBJS) $(GLFLAGS) $(LIBS) + # this is a suffix replacement rule for building .o's from .c's # it uses automatic variables $<: the name of the prerequisite of # the rule(a .c file) and $@: the name of the target of the rule (a .o file) @@ -63,7 +73,7 @@ $(MAIN): $(OBJS) $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ clean: - $(RM) *.o *~ $(MAIN) + $(RM) *.o *~ $(MAIN) ${GARDUINO} depend: $(SRCS) makedepend $(INCLUDES) $^ From 40fce7a5228b63680ef1295aa59e35410a9bb59e Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Sat, 11 Sep 2021 21:56:13 +0200 Subject: [PATCH 03/16] add linux GUI instructions --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index d18e1b0..0901d49 100644 --- a/readme.md +++ b/readme.md @@ -4,6 +4,8 @@ Created by Robert Smith @RobSmithDev https://amiga.robsmithdev.co.uk +# This repo adds a GTK+ GUI for linux +To compile: make all; ./GarduinoReaderWriter # What is it? This project uses an Arduino to interface with a floppy disk drive and From afa193797431f044240488847f18f24c8592a6b4 Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Sat, 11 Sep 2021 21:57:54 +0200 Subject: [PATCH 04/16] update linux readme --- ArduinoFloppyReader/ArduinoFloppyReader/readme.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ArduinoFloppyReader/ArduinoFloppyReader/readme.txt b/ArduinoFloppyReader/ArduinoFloppyReader/readme.txt index 2d2a3bd..065cd27 100644 --- a/ArduinoFloppyReader/ArduinoFloppyReader/readme.txt +++ b/ArduinoFloppyReader/ArduinoFloppyReader/readme.txt @@ -5,6 +5,9 @@ This is a console application It should build with Visual Studio 2019 -It will also compile on some distros of Linux. +It will also compile on some distros of Linux. +To compile/run the GTK+ GUI: +make all; ./GarduinoReaderWriter + It has been tested on Raspberry Pi OS (Raspbian - Debian-based) and can be compiled using the provided makefile \ No newline at end of file From 5530eba4a7052f90b1ab93f9d1a0066a4faad7b6 Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Sat, 11 Sep 2021 22:03:25 +0200 Subject: [PATCH 05/16] add linux build requirement --- ArduinoFloppyReader/ArduinoFloppyReader/readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ArduinoFloppyReader/ArduinoFloppyReader/readme.txt b/ArduinoFloppyReader/ArduinoFloppyReader/readme.txt index 065cd27..608a4f9 100644 --- a/ArduinoFloppyReader/ArduinoFloppyReader/readme.txt +++ b/ArduinoFloppyReader/ArduinoFloppyReader/readme.txt @@ -6,7 +6,7 @@ This is a console application It should build with Visual Studio 2019 It will also compile on some distros of Linux. -To compile/run the GTK+ GUI: +To compile/run the GTK+ GUI (requires gtkmm-3.x): make all; ./GarduinoReaderWriter From 839af11a3d116ceeb6354cb6f7124891cd770f6f Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Sat, 11 Sep 2021 22:04:16 +0200 Subject: [PATCH 06/16] update linux build requirement --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 0901d49..09a4f77 100644 --- a/readme.md +++ b/readme.md @@ -5,7 +5,7 @@ Created by Robert Smith @RobSmithDev https://amiga.robsmithdev.co.uk # This repo adds a GTK+ GUI for linux -To compile: make all; ./GarduinoReaderWriter +To compile (requires gtkmm-3.x): make all; ./GarduinoReaderWriter # What is it? This project uses an Arduino to interface with a floppy disk drive and From 03b193f70e912bfaab411bde718c6c4387bd9d2d Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Tue, 14 Sep 2021 23:16:56 +0200 Subject: [PATCH 07/16] remove unused code --- .../GarduinoReaderWriter.cpp | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp b/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp index d3c3e20..62e45e1 100644 --- a/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp +++ b/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp @@ -7,31 +7,6 @@ #include "../lib/ArduinoInterface.h" #include "../lib/ADFWriter.h" -enum Tracks -{ - eighty = 80, - eightytwo = 82, -}; - -enum ReadType -{ - ADF = 1, - SCP = 2, -}; - -class WindowState -{ -public: - Glib::ustring serialPort; - ReadType type; - Tracks tracks; - bool verify; - bool writeCompensation; - Glib::ustring readFileName; - Glib::ustring readFolder; - Glib::ustring writeFileName; -}; - class MainWindow : public Gtk::ApplicationWindow { public: From afc0b485707a3e87a2da618cc72d54fb173a09a1 Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Tue, 14 Sep 2021 23:18:13 +0200 Subject: [PATCH 08/16] update GUI after setting the status so all the status text is shown --- .../ArduinoFloppyReader/GarduinoReaderWriter.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp b/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp index 62e45e1..5e415e7 100644 --- a/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp +++ b/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp @@ -66,7 +66,6 @@ class MainWindow : public Gtk::ApplicationWindow case 3: return ArduinoFloppyReader::WriteResponse::wrSkipBadChecksums; } - } // Just continue @@ -107,7 +106,7 @@ class MainWindow : public Gtk::ApplicationWindow writeFolderSelector->signal_file_set().connect([this]() { - std::cout<< "got filename" << writeFolderSelector->get_filename() << std::endl; + std::cout << "got filename " << writeFolderSelector->get_filename() << std::endl; if (this->writeFolderSelector->get_filename() != "" && diagnosticsButton->get_sensitive()) { writeButton->set_sensitive(true); @@ -322,6 +321,8 @@ class MainWindow : public Gtk::ApplicationWindow std::cerr << strLine << std::endl; statusBar->pop(); statusBar->push(strLine); + while (gtk_events_pending()) + gtk_main_iteration(); } void run_diagnostics(Glib::ustring serial) From 1f217ab710a9cfab40befa50517755d7b54e566a Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Tue, 14 Sep 2021 23:52:37 +0200 Subject: [PATCH 09/16] add action --- c-cpp.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 c-cpp.yml diff --git a/c-cpp.yml b/c-cpp.yml new file mode 100644 index 0000000..c40c47a --- /dev/null +++ b/c-cpp.yml @@ -0,0 +1,22 @@ +name: C/C++ CI + +on: + push: + branches: [ linux ] + pull_request: + branches: [ linux ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Install gtkmm + run: sudo apt-get install libgtkmm-3.0-dev + - name: make + run: | + cd ArduinoFloppyReader/ArduinoFloppyReader + make all + From 9061907a91d66d2654a2b8860298d0761a7a8378 Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Tue, 14 Sep 2021 23:54:25 +0200 Subject: [PATCH 10/16] move to correct place? --- c-cpp.yml => .github/workflows/c-cpp.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename c-cpp.yml => .github/workflows/c-cpp.yml (100%) diff --git a/c-cpp.yml b/.github/workflows/c-cpp.yml similarity index 100% rename from c-cpp.yml rename to .github/workflows/c-cpp.yml From bcf02c4607b9a35b77046bb2e29818e8f5615a84 Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Wed, 15 Sep 2021 00:02:09 +0200 Subject: [PATCH 11/16] Update c-cpp.yml publish --- .github/workflows/c-cpp.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index c40c47a..0539e55 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -19,4 +19,9 @@ jobs: run: | cd ArduinoFloppyReader/ArduinoFloppyReader make all + - name: Upload Artifact + uses: actions/upload-artifact@v2 + with: + name: WebApp1 + path: /home/runner/work/ArduinoFloppyDiskReader/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter From c008113216223a25f6b70c803d54603510b164b8 Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Wed, 15 Sep 2021 00:03:51 +0200 Subject: [PATCH 12/16] Update c-cpp.yml --- .github/workflows/c-cpp.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 0539e55..e7fd47e 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -22,6 +22,6 @@ jobs: - name: Upload Artifact uses: actions/upload-artifact@v2 with: - name: WebApp1 - path: /home/runner/work/ArduinoFloppyDiskReader/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter + name: GTK GUI + path: ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter From 4a78ad03b9a99a6ed853b910d1c6653bd4be6b26 Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Wed, 15 Sep 2021 21:47:42 +0200 Subject: [PATCH 13/16] some GUI fixes --- .../ArduinoFloppyReader/Garduino.glade | 159 +++++++++++------- .../GarduinoReaderWriter.cpp | 49 +++--- ArduinoFloppyReader/lib/ADFWriter.cpp | 1 - 3 files changed, 126 insertions(+), 83 deletions(-) diff --git a/ArduinoFloppyReader/ArduinoFloppyReader/Garduino.glade b/ArduinoFloppyReader/ArduinoFloppyReader/Garduino.glade index 85b1f55..cfdea86 100644 --- a/ArduinoFloppyReader/ArduinoFloppyReader/Garduino.glade +++ b/ArduinoFloppyReader/ArduinoFloppyReader/Garduino.glade @@ -3,8 +3,8 @@ - 500 - 300 + 700 + 600 False Arduino Amiga Floppy Disk Reader and Writer @@ -14,73 +14,97 @@ vertical 5 - + True False - 0 - + True False - 1 - 1 - 12 - 12 + 0 - + True False - 20 - True - - - True - False - Arduino connected on: - - - False - True - 0 - - + 1 + 1 + 12 + 12 - + True False + center + 20 + True + + + True + False + Arduino connected on: + + + False + True + 0 + + + + + True + False + + + False + True + 1 + + + + + Run Diagnostics + True + False + True + True + + + False + True + 2 + + - - False - True - 1 - - - - - Run Diagnostics - True - False - True - True - - - False - True - 2 - + + + True + False + 10 + Arduino Configuration + + + + + False + True + 0 + - - + + True False - 10 - Arduino Configuration - + ../ArduinoFloppyReaderWin/res/floppy.bmp + + True + True + 1 + @@ -257,12 +281,14 @@ True False + center Always Ignore Read Errors True True False + start True True @@ -374,6 +400,7 @@ True True False + start True @@ -388,6 +415,7 @@ True True False + start True @@ -546,23 +574,32 @@ - - statusBar + True False - 10 - 10 - 10 - 10 - 6 - 6 - vertical + never + in + 100 + False + False + 300 + True + True + + + True + True + False + False + False + True + + - False + True True - end - 4 + 5 diff --git a/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp b/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp index 5e415e7..5a2ca82 100644 --- a/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp +++ b/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp @@ -29,8 +29,10 @@ class MainWindow : public Gtk::ApplicationWindow } diagnosticsButton->signal_clicked().connect([this]() { + diagnosticsButton->set_sensitive(false); Glib::ustring serial = portsCombo->get_active_text(); run_diagnostics(serial); + diagnosticsButton->set_sensitive(true); }); auto readerCallback = [this](const int currentTrack, const ArduinoFloppyReader::DiskSurface currentSide, const int retryCounter, const int sectorsFound, const int badSectorsFound) -> ArduinoFloppyReader::WriteResponse @@ -41,8 +43,6 @@ class MainWindow : public Gtk::ApplicationWindow goodCount->set_text(Glib::ustring::sprintf("%i", sectorsFound)); partialCount->set_text(Glib::ustring::sprintf("%i", badSectorsFound)); sideLabel->set_text(side); - while (gtk_events_pending()) - gtk_main_iteration(); if (retryCounter > 20) { @@ -178,7 +178,8 @@ class MainWindow : public Gtk::ApplicationWindow Gtk::FileChooserButton *folderButton = nullptr; Gtk::ComboBoxText *typeSelector = nullptr; Gtk::RadioButton *trackButton = nullptr; - Gtk::Statusbar *statusBar = nullptr; + Gtk::TextView *statusBar = nullptr; + Gtk::Image *diskImage = nullptr; void get_widgets() { @@ -308,6 +309,10 @@ class MainWindow : public Gtk::ApplicationWindow std::cout << "Unexpected button clicked." << std::endl; break; } + while (Gtk::Main::events_pending()) + { + Gtk::Main::iteration(); + } return isYes; } @@ -315,14 +320,22 @@ class MainWindow : public Gtk::ApplicationWindow { std::string strLine; + while (Gtk::Main::events_pending()) + { + Gtk::Main::iteration(); + } if (isError) strLine = "DIAGNOSTICS FAILED: "; - strLine += status.c_str(); - std::cerr << strLine << std::endl; - statusBar->pop(); - statusBar->push(strLine); - while (gtk_events_pending()) - gtk_main_iteration(); + strLine += (status + "\n").c_str(); + std::cerr << strLine; + auto buffer = statusBar->get_buffer(); + buffer->insert(buffer->end(), strLine); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + statusBar->scroll_to(buffer->get_insert(), 0); + while (Gtk::Main::events_pending()) + { + Gtk::Main::iteration(); + } } void run_diagnostics(Glib::ustring serial) @@ -330,17 +343,15 @@ class MainWindow : public Gtk::ApplicationWindow ArduinoFloppyReader::ADFWriter writer; writer.runDiagnostics( std::wstring(serial.begin(), serial.end()), [this, serial](bool isError, const std::string message) -> void - { - while (gtk_events_pending()) - gtk_main_iteration(); - this->showStatus(isError, message); - }, + { this->showStatus(isError, message); }, [this, serial](bool isQuestion, const std::string question) -> bool { - while (gtk_events_pending()) - gtk_main_iteration(); return this->showQuestion(isQuestion, question); }); + while (Gtk::Main::events_pending()) + { + Gtk::Main::iteration(); + } } }; @@ -355,9 +366,5 @@ int main(int argc, char *argv[]) builder->get_widget_derived("MainWindow", wnd); - auto r = app->run(*wnd); - - delete wnd; - - return r; + return app->run(*wnd); } diff --git a/ArduinoFloppyReader/lib/ADFWriter.cpp b/ArduinoFloppyReader/lib/ADFWriter.cpp index 4eff24a..85f074c 100644 --- a/ArduinoFloppyReader/lib/ADFWriter.cpp +++ b/ArduinoFloppyReader/lib/ADFWriter.cpp @@ -666,7 +666,6 @@ bool ADFWriter::runDiagnostics(const std::wstring& portName, std::function start = std::chrono::steady_clock::now(); - messageOutput(false, "Testing Disk Change pin."); messageOutput(false, "*** Please remove disk from drive *** (you have 30 seconds)"); while (std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count() < 30000) { std::this_thread::sleep_for(std::chrono::milliseconds(250)); From dd7f8056e2fa6c44e646484b149e5748e3b0a4a5 Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Mon, 27 Sep 2021 23:05:21 +0200 Subject: [PATCH 14/16] wxwidgets --- .../WarduinoReaderWriter.cpp | 141 ++++++++++++++++++ .../ArduinoFloppyReader/makefile | 13 +- 2 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 ArduinoFloppyReader/ArduinoFloppyReader/WarduinoReaderWriter.cpp diff --git a/ArduinoFloppyReader/ArduinoFloppyReader/WarduinoReaderWriter.cpp b/ArduinoFloppyReader/ArduinoFloppyReader/WarduinoReaderWriter.cpp new file mode 100644 index 0000000..5e0ae5c --- /dev/null +++ b/ArduinoFloppyReader/ArduinoFloppyReader/WarduinoReaderWriter.cpp @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include "../lib/ArduinoInterface.h" +#include "../lib/ADFWriter.h" + +class WarduinoApp : public wxApp +{ +public: + virtual bool OnInit(); +}; + +class MyFrame : public wxFrame +{ +public: + MyFrame(); + +private: + // wxTextCtrl *textctrl; + wxComboBox *portCombo; + wxButton *diagnosticsButton; + void OnDiagnostics(wxCommandEvent &WXUNUSED(event)); + void run_diagnostics(std::string serial); + void showStatus(bool isError, std::string status); + bool showQuestion(bool isQuestion, const std::string question); +}; + +enum +{ + BUTTON_Diagnostics = wxID_HIGHEST + 1, + COMBO_Ports = BUTTON_Diagnostics + 1, +}; + +bool WarduinoApp::OnInit() +{ + MyFrame *frame = new MyFrame(); + frame->Show(true); + return true; +} +MyFrame::MyFrame() + : wxFrame(NULL, wxID_ANY, "Arduino Amiga Floppy Disk Reader and Writer") +{ + CreateStatusBar(); + SetStatusText("Welcome to wxWidgets!"); + + portCombo = new wxComboBox(this, COMBO_Ports); + std::vector portList; + ArduinoFloppyReader::ArduinoInterface::enumeratePorts(portList); + for (std::wstring port : portList) + { + const std::string portString(port.begin(), port.end()); + portCombo->Append(portString); + } + if (portList.size() > 0) { + portCombo->SetSelection(0); + } + diagnosticsButton = new wxButton(this, BUTTON_Diagnostics, "Run Diagnostics"); + Connect(BUTTON_Diagnostics, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MyFrame::OnDiagnostics)); + wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL); + wxBoxSizer *hbox1 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer *hbox2 = new wxBoxSizer(wxHORIZONTAL); + + hbox1->Add(new wxStaticText(this, -1, "Arduino connected on")); + hbox1->Add(portCombo); + hbox1->Add(diagnosticsButton); + vbox->Add(hbox1, 1, wxEXPAND); + + + vbox->Add(hbox2, 0, wxALIGN_CENTER, 10); + this->SetSizer(vbox); + + Centre(); + Show(true); +} +void MyFrame::OnDiagnostics(wxCommandEvent &WXUNUSED(event)) +{ + auto serial = this->portCombo->GetValue(); + run_diagnostics(serial.c_str().AsChar()); +} + +bool MyFrame::showQuestion(bool isQuestion, const std::string question) +{ + long style = (wxOK | wxCANCEL); + if (isQuestion) + { + style = (wxYES | wxNO); + } + + wxMessageDialog dial(NULL, question.c_str(), wxT("Question"), style | wxICON_QUESTION); + auto Answer = dial.ShowModal(); + // Process user choice + bool isYes = false; + switch (Answer) + { + case (wxID_OK): + isYes = true; + break; + case (wxID_CANCEL): + std::cout << "Cancel clicked." << std::endl; + break; + case (wxID_YES): + std::cout << "Yes clicked." << std::endl; + isYes = true; + break; + case (wxID_NO): + std::cout << "No clicked." << std::endl; + break; + default: + std::cout << "Unexpected answer: " << Answer << std::endl; + break; + } + return isYes; +} + +void MyFrame::showStatus(bool isError, std::string status) +{ + std::string strLine; + + if (isError) + strLine = "DIAGNOSTICS FAILED: "; + strLine += (status + "\n").c_str(); + std::cerr << strLine; + auto statusBar = GetStatusBar(); + statusBar->SetStatusText(strLine); +} + +void MyFrame::run_diagnostics(std::string serial) +{ + ArduinoFloppyReader::ADFWriter writer; + writer.runDiagnostics( + std::wstring(serial.begin(), serial.end()), [this, serial](bool isError, const std::string message) -> void + { this->showStatus(isError, message); }, + [this, serial](bool isQuestion, const std::string question) -> bool + { + return this->showQuestion(isQuestion, question); + }); +} + +wxIMPLEMENT_APP(WarduinoApp); diff --git a/ArduinoFloppyReader/ArduinoFloppyReader/makefile b/ArduinoFloppyReader/ArduinoFloppyReader/makefile index edb080b..0208ab2 100644 --- a/ArduinoFloppyReader/ArduinoFloppyReader/makefile +++ b/ArduinoFloppyReader/ArduinoFloppyReader/makefile @@ -9,8 +9,9 @@ CC = g++ # define any compile-time flags -CFLAGS = -Wall -std=c++14 -Wno-psabi -O0 +CFLAGS = -Wall -std=c++14 -Wno-psabi -O0 -g GCFLAGS = ${CFLAGS} $(shell pkg-config --cflags gtkmm-3.0) +WCFLAGS = ${CFLAGS} $(shell wx-config --cflags) # define any directories containing header files other than /usr/include # @@ -21,6 +22,7 @@ INCLUDES = -I../lib # their path using -Lpath, something like: LFLAGS = -L../lib GLFLAGS = ${LFLAGS} $(shell pkg-config --libs gtkmm-3.0) +WLFLAGS = ${LFLAGS} $(shell wx-config --libs) # define any libraries to link into executable: # if I want to link in libraries (libx.so or libx.a) I use the -llibname @@ -31,6 +33,8 @@ LIBS = COMMON_SRC = ../lib/SerialIO.cpp ../lib/RotationExtractor.cpp ../lib/ArduinoInterface.cpp ../lib/ADFWriter.cpp SRCS = Main.cpp ${COMMON_SRC} GSRCS = GarduinoReaderWriter.cpp ${COMMON_SRC} +WSRCS = WarduinoReaderWriter.cpp ${COMMON_SRC} + # define the C object files # # This uses Suffix Replacement within a macro: @@ -41,12 +45,14 @@ GSRCS = GarduinoReaderWriter.cpp ${COMMON_SRC} # OBJS = $(SRCS:.c=.o) GOBJS = $(GSRCS:.c=.o) +WOBJS = $(WSRCS:.c=.o) # define the executable file MAIN = ArduinoReaderWriter #GUI GARDUINO = GarduinoReaderWriter +WARDUINO = WarduinoReaderWriter # # The following part of the makefile is generic; it can be used to @@ -56,7 +62,7 @@ GARDUINO = GarduinoReaderWriter .PHONY: depend clean -all: $(MAIN) $(GARDUINO) +all: $(MAIN) $(GARDUINO) $(WARDUINO) @echo ArduinoReaderWriter ready $(MAIN): $(OBJS) @@ -65,6 +71,9 @@ $(MAIN): $(OBJS) $(GARDUINO): $(GOBJS) makefile Garduino.glade $(CC) $(GCFLAGS) $(INCLUDES) -o $(GARDUINO) $(GOBJS) $(GLFLAGS) $(LIBS) +$(WARDUINO): $(WOBJS) makefile + $(CC) $(WCFLAGS) $(INCLUDES) -o $(WARDUINO) $(WOBJS) $(WLFLAGS) $(LIBS) + # this is a suffix replacement rule for building .o's from .c's # it uses automatic variables $<: the name of the prerequisite of # the rule(a .c file) and $@: the name of the target of the rule (a .o file) From d6c3a3f768607e2ad2621c2cc8ec0f1175614549 Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Mon, 27 Sep 2021 23:35:01 +0200 Subject: [PATCH 15/16] some more layouting --- .../WarduinoReaderWriter.cpp | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/ArduinoFloppyReader/ArduinoFloppyReader/WarduinoReaderWriter.cpp b/ArduinoFloppyReader/ArduinoFloppyReader/WarduinoReaderWriter.cpp index 5e0ae5c..feef0b5 100644 --- a/ArduinoFloppyReader/ArduinoFloppyReader/WarduinoReaderWriter.cpp +++ b/ArduinoFloppyReader/ArduinoFloppyReader/WarduinoReaderWriter.cpp @@ -21,6 +21,8 @@ class MyFrame : public wxFrame // wxTextCtrl *textctrl; wxComboBox *portCombo; wxButton *diagnosticsButton; + wxButton *readButton; + wxButton *writeButton; void OnDiagnostics(wxCommandEvent &WXUNUSED(event)); void run_diagnostics(std::string serial); void showStatus(bool isError, std::string status); @@ -40,12 +42,35 @@ bool WarduinoApp::OnInit() return true; } MyFrame::MyFrame() - : wxFrame(NULL, wxID_ANY, "Arduino Amiga Floppy Disk Reader and Writer") + : wxFrame(NULL, wxID_ANY, "Arduino Amiga Floppy Disk Reader and Writer", wxDefaultPosition, wxSize(600, 650)) { CreateStatusBar(); SetStatusText("Welcome to wxWidgets!"); + wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL); + wxBoxSizer *hbox1 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer *hbox2 = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer *hbox3 = new wxBoxSizer(wxHORIZONTAL); + wxStaticBox *frameDiag = new wxStaticBox(this, wxID_ANY, "Arduino Configuration", wxDefaultPosition, wxSize(600, 200)); + wxStaticBox *frameCopy = new wxStaticBox(this, wxID_ANY, "Copy Disk to ADF or SCP File (read)", wxDefaultPosition, wxSize(600, 200)); + wxStaticBox *frameWrite = new wxStaticBox(this, wxID_ANY, "Write ADF File to Disk (write)", wxDefaultPosition, wxSize(600, 200)); + + auto arduinoLabel = new wxStaticText(this, -1, "Arduino connected on"); + frameDiag->SetSizer(hbox1); + frameCopy->SetSizer(hbox2); + frameWrite->SetSizer(hbox3); + hbox1->Add(arduinoLabel); + vbox->Add(frameDiag, 1); + vbox->Add(frameCopy, 1); + vbox->Add(frameWrite, 1); + auto saveLabel = new wxStaticText(this, -1, "Save to"); + hbox2->Add(saveLabel); + auto writeLabel = new wxStaticText(this, -1, "ADF File"); + hbox3->Add(writeLabel); + this->SetSizer(vbox); + portCombo = new wxComboBox(this, COMBO_Ports); + hbox1->Add(portCombo); std::vector portList; ArduinoFloppyReader::ArduinoInterface::enumeratePorts(portList); for (std::wstring port : portList) @@ -56,21 +81,9 @@ MyFrame::MyFrame() if (portList.size() > 0) { portCombo->SetSelection(0); } - diagnosticsButton = new wxButton(this, BUTTON_Diagnostics, "Run Diagnostics"); + diagnosticsButton = new wxButton(frameDiag, BUTTON_Diagnostics, "Run Diagnostics"); Connect(BUTTON_Diagnostics, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(MyFrame::OnDiagnostics)); - wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL); - wxBoxSizer *hbox1 = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer *hbox2 = new wxBoxSizer(wxHORIZONTAL); - - hbox1->Add(new wxStaticText(this, -1, "Arduino connected on")); - hbox1->Add(portCombo); hbox1->Add(diagnosticsButton); - vbox->Add(hbox1, 1, wxEXPAND); - - - vbox->Add(hbox2, 0, wxALIGN_CENTER, 10); - this->SetSizer(vbox); - Centre(); Show(true); } From ae45eeedd5dc719bddbe55e2f90cc381820b20ef Mon Sep 17 00:00:00 2001 From: Jos Dehaes Date: Thu, 11 Nov 2021 22:33:33 +0100 Subject: [PATCH 16/16] update --- .../ArduinoFloppyReader/GarduinoReaderWriter.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp b/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp index 5a2ca82..d213111 100644 --- a/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp +++ b/ArduinoFloppyReader/ArduinoFloppyReader/GarduinoReaderWriter.cpp @@ -44,6 +44,10 @@ class MainWindow : public Gtk::ApplicationWindow partialCount->set_text(Glib::ustring::sprintf("%i", badSectorsFound)); sideLabel->set_text(side); + while (Gtk::Main::events_pending()) + { + Gtk::Main::iteration(); + } if (retryCounter > 20) { if (alwaysIgnore->get_active()) @@ -85,6 +89,11 @@ class MainWindow : public Gtk::ApplicationWindow }); copyButton->signal_clicked().connect([this, readerCallback]() { + copyButton->set_sensitive(false); + while (Gtk::Main::events_pending()) + { + Gtk::Main::iteration(); + } Glib::ustring folder = folderButton->get_filename(); Glib::ustring filename = folder + "/" + fileEntry->get_buffer()->get_text(); ArduinoFloppyReader::ADFWriter writer; @@ -102,6 +111,7 @@ class MainWindow : public Gtk::ApplicationWindow } // Handle the result handleResult(writer, readerResult); + copyButton->set_sensitive(true); }); writeFolderSelector->signal_file_set().connect([this]() @@ -147,6 +157,11 @@ class MainWindow : public Gtk::ApplicationWindow }; writeButton->signal_clicked().connect([this, writerCallback]() { + writeButton->set_sensitive(false); + while (Gtk::Main::events_pending()) + { + Gtk::Main::iteration(); + } Glib::ustring filename = writeFolderSelector->get_filename(); ArduinoFloppyReader::ADFWriter writer; Glib::ustring serial = portsCombo->get_active_text(); @@ -155,6 +170,7 @@ class MainWindow : public Gtk::ApplicationWindow readerResult = writer.ADFToDisk(std::wstring(filename.begin(), filename.end()), verify->get_active(), writeCompensation->get_active(), writerCallback); // Handle the result handleResult(writer, readerResult); + writeButton->set_sensitive(true); }); }