Do a very basic read/write visualisation. It looks like suck.

This commit is contained in:
David Given
2022-02-22 22:35:13 +01:00
parent 3d4cf7df26
commit 0aa0c6866c
11 changed files with 168 additions and 58 deletions

View File

@@ -50,4 +50,7 @@ private:
std::stringstream _stream;
};
template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
#endif

View File

@@ -6,25 +6,10 @@
#include "fmt/format.h"
#include "logger.h"
template <class... Ts>
struct overloaded : Ts...
{
using Ts::operator()...;
};
template <class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
static bool indented = false;
static std::function<void(std::shared_ptr<const AnyLogMessage>)> loggerImpl =
Logger::textLogger;
static void indent()
{
if (!indented)
std::cout << " ";
indented = false;
}
Logger& Logger::operator<<(std::shared_ptr<const AnyLogMessage> message)
{
loggerImpl(message);
@@ -45,6 +30,13 @@ void Logger::textLogger(std::shared_ptr<const AnyLogMessage> message)
std::string Logger::toString(const AnyLogMessage& message)
{
std::stringstream stream;
auto indent = [&]() {
if (!indented)
stream << " ";
indented = false;
};
std::visit(
overloaded{
/* Fallback --- do nothing */
@@ -66,8 +58,15 @@ std::string Logger::toString(const AnyLogMessage& message)
60e9 / m.rotationalPeriod);
},
/* Indicates that we're working on a given cylinder and head */
[&](const DiskContextLogMessage& m)
/* Indicates that we're starting a write operation. */
[&](const BeginWriteOperationLogMessage& m)
{
stream << fmt::format("{:2}.{}: ", m.cylinder, m.head);
indented = true;
},
/* Indicates that we're starting a read operation. */
[&](const BeginReadOperationLogMessage& m)
{
stream << fmt::format("{:2}.{}: ", m.cylinder, m.head);
indented = true;

View File

@@ -15,12 +15,6 @@ struct EndSpeedOperationLogMessage
nanoseconds_t rotationalPeriod;
};
struct DiskContextLogMessage
{
unsigned cylinder;
unsigned head;
};
struct SingleReadLogMessage
{
std::shared_ptr<TrackDataFlux> trackDataFlux;
@@ -34,13 +28,20 @@ struct TrackReadLogMessage
struct BeginReadOperationLogMessage
{
unsigned cylinder;
unsigned head;
};
struct EndReadOperationLogMessage
{
};
struct BeginWriteOperationLogMessage
{
unsigned cylinder;
unsigned head;
};
struct EndWriteOperationLogMessage
{
};
@@ -50,7 +51,6 @@ class TrackFlux;
typedef std::variant<std::string,
SingleReadLogMessage,
TrackReadLogMessage,
DiskContextLogMessage,
BeginSpeedOperationLogMessage,
EndSpeedOperationLogMessage,
BeginReadOperationLogMessage,

View File

@@ -23,8 +23,7 @@ static std::unique_ptr<FluxSink> outputFluxSink;
static std::shared_ptr<Fluxmap> readFluxmap(FluxSource& fluxsource, unsigned cylinder, unsigned head)
{
Logger() << DiskContextLogMessage { cylinder, head }
<< BeginReadOperationLogMessage();
Logger() << BeginReadOperationLogMessage { cylinder, head };
std::shared_ptr<Fluxmap> fluxmap = fluxsource.readFlux(cylinder, head);
fluxmap->rescale(1.0/config.flux_source().rescale());
Logger() << EndReadOperationLogMessage()
@@ -65,12 +64,12 @@ static std::set<std::shared_ptr<Sector>> collect_sectors(std::set<std::shared_pt
return sector_set;
}
void readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder, ImageWriter& writer)
std::shared_ptr<DiskFlux> readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder)
{
if (config.decoder().has_copy_flux_to())
outputFluxSink = FluxSink::create(config.decoder().copy_flux_to());
auto diskflux = std::make_unique<DiskFlux>();
auto diskflux = std::make_shared<DiskFlux>();
bool failures = false;
for (int cylinder : iterate(config.cylinders()))
{
@@ -177,13 +176,20 @@ void readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder, ImageWrit
all_sectors = collect_sectors(all_sectors);
diskflux->image.reset(new Image(all_sectors));
if (failures)
Logger() << "Warning: some sectors could not be decoded.";
return diskflux;
}
void readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder, ImageWriter& writer)
{
auto diskflux = readDiskCommand(fluxsource, decoder);
writer.printMap(*diskflux->image);
if (config.decoder().has_write_csv_to())
writer.writeCsv(*diskflux->image, config.decoder().write_csv_to());
writer.writeImage(*diskflux->image);
if (failures)
std::cerr << "Warning: some sectors could not be decoded." << std::endl;
}
void rawReadDiskCommand(FluxSource& fluxsource, FluxSink& fluxsink)

View File

@@ -2,6 +2,7 @@
#define READER_H
class AbstractDecoder;
class DiskFlux;
class FluxSink;
class FluxSource;
class Fluxmap;
@@ -10,6 +11,8 @@ class TrackDataFlux;
extern std::unique_ptr<TrackDataFlux> readAndDecodeTrack(
FluxSource& source, AbstractDecoder& decoder, unsigned cylinder, unsigned head);
extern std::shared_ptr<DiskFlux> readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder);
extern void readDiskCommand(FluxSource& source, AbstractDecoder& decoder, ImageWriter& writer);
extern void rawReadDiskCommand(FluxSource& source, FluxSink& sink);

View File

@@ -23,9 +23,7 @@ void writeTracks(FluxSink& fluxSink,
{
for (unsigned head : iterate(config.heads()))
{
Logger() << DiskContextLogMessage { cylinder, head }
<< fmt::format("{0:>3}.{1}: writing", cylinder, head)
<< BeginWriteOperationLogMessage();
Logger() << BeginWriteOperationLogMessage { cylinder, head };
std::unique_ptr<Fluxmap> fluxmap = producer(cylinder, head);
if (!fluxmap)
@@ -64,9 +62,6 @@ void writeTracksAndVerify(FluxSink& fluxSink,
{
for (unsigned head : iterate(config.heads()))
{
Logger() << DiskContextLogMessage { cylinder, head }
<< fmt::format("{0:>3}.{1}", cylinder, head);
auto sectors = encoder.collectSectors(cylinder, head, image);
std::unique_ptr<Fluxmap> fluxmap =
encoder.encode(cylinder, head, sectors, image);
@@ -74,7 +69,7 @@ void writeTracksAndVerify(FluxSink& fluxSink,
{
/* Erase this track rather than writing. */
Logger() << BeginWriteOperationLogMessage() << "erasing";
Logger() << BeginWriteOperationLogMessage { cylinder, head };
fluxmap.reset(new Fluxmap());
fluxSink.writeFlux(cylinder, head, *fluxmap);
Logger() << EndWriteOperationLogMessage();
@@ -91,14 +86,14 @@ void writeTracksAndVerify(FluxSink& fluxSink,
* let's leave it disabled for now. */
// fluxmap->precompensate(PRECOMPENSATION_THRESHOLD_TICKS,
// 2);
Logger() << BeginWriteOperationLogMessage() << "writing";
Logger() << BeginWriteOperationLogMessage { cylinder, head };
fluxSink.writeFlux(cylinder, head, *fluxmap);
Logger() << EndWriteOperationLogMessage()
<< fmt::format("{0} ms in {1} bytes",
int(fluxmap->duration() / 1e6),
fluxmap->bytes());
Logger() << "verifying" << BeginReadOperationLogMessage();
Logger() << BeginReadOperationLogMessage { cylinder, head };
std::shared_ptr<Fluxmap> writtenFluxmap =
fluxSource.readFlux(cylinder, head);
Logger() << EndReadOperationLogMessage()

View File

@@ -64,12 +64,6 @@ bool MyApp::OnInit()
Bind(EXEC_EVENT_TYPE, &MyApp::OnExec, this);
MainWindow* frame = new MainWindow();
frame->Show(true);
runOnWorkerThread(
[] {
printf("I'm a worker thread!\n");
}
);
return true;
}
@@ -105,7 +99,6 @@ void runOnWorkerThread(std::function<void()> callback)
void MyApp::OnExec(const ExecEvent& event)
{
printf("exec handler\n");
event.RunCallback();
execSemaphore.Post();
}

View File

@@ -2,12 +2,15 @@
#include "proto.h"
#include "gui.h"
#include "logger.h"
#include "reader.h"
#include "fluxsource/fluxsource.h"
#include "decoders/decoders.h"
#include "lib/usb/usbfinder.h"
#include "fmt/format.h"
#include <wx/wx.h>
#include "mainwindow.h"
#include <google/protobuf/text_format.h>
extern const std::map<std::string, std::string> formats;
@@ -17,10 +20,7 @@ MainWindow::MainWindow(): MainWindowGen(nullptr)
[&](std::shared_ptr<const AnyLogMessage> message) {
runOnUiThread(
[message, this]() {
std::cout << "UI thread got message "
<< Logger::toString(*message)
<< '\n'
<< std::flush;
OnLogMessage(message);
}
);
}
@@ -42,6 +42,8 @@ MainWindow::MainWindow(): MainWindowGen(nullptr)
if (deviceCombo->GetCount() > 0)
deviceCombo->SetValue(deviceCombo->GetString(0));
fluxSourceSinkCombo->SetValue(fluxSourceSinkCombo->GetString(0));
readFluxButton->Bind(wxEVT_BUTTON, &MainWindow::OnReadFluxButton, this);
}
@@ -58,21 +60,72 @@ void MainWindow::OnReadFluxButton(wxCommandEvent&)
fluxSourceSinkCombo->GetValue().ToStdString());
auto serial = deviceCombo->GetValue().ToStdString();
if (!serial.empty() && (serial[0] = '/'))
if (!serial.empty() && (serial[0] == '/'))
setProtoByString(&config, "usb.greaseweazle.port", serial);
else
setProtoByString(&config, "usb.serial", serial);
runOnWorkerThread(
/* Must make another copy of all local parameters. */
[=]() {
[config, this]() {
::config = config;
auto fluxSource = FluxSource::create(config.flux_source());
auto decoder = AbstractDecoder::create(config.decoder());
printf("Worker thread!\n");
auto diskflux = readDiskCommand(*fluxSource, *decoder);
runOnUiThread(
[&]() {
UpdateVisualisedFlux(diskflux);
}
);
}
);
}
void MainWindow::OnLogMessage(std::shared_ptr<const AnyLogMessage> message)
{
std::cout << "UI thread got message "
<< Logger::toString(*message)
<< '\n'
<< std::flush;
std::visit(
overloaded{
/* Fallback --- do nothing */
[&](const auto& m)
{
},
/* Indicates that we're starting a write operation. */
[&](const BeginWriteOperationLogMessage& m)
{
visualiser->SetMode(m.cylinder, m.head, VISMODE_WRITING);
},
[&](const EndWriteOperationLogMessage& m)
{
visualiser->SetMode(0, 0, VISMODE_NOTHING);
},
/* Indicates that we're starting a read operation. */
[&](const BeginReadOperationLogMessage& m)
{
visualiser->SetMode(m.cylinder, m.head, VISMODE_READING);
},
[&](const EndReadOperationLogMessage& m)
{
visualiser->SetMode(0, 0, VISMODE_NOTHING);
},
},
*message);
}
void MainWindow::UpdateVisualisedFlux(std::shared_ptr<DiskFlux>& flux)
{
_currentDisk = flux;
visualiser->SetDiskFlux(flux);
}
void MainWindow::UpdateDevices()
{
auto candidates = findUsbDevices();

View File

@@ -6,6 +6,7 @@
class CandidateDevice;
class ConfigProto;
class DiskFlux;
class MainWindow : public MainWindowGen
{
@@ -15,13 +16,15 @@ public:
private:
void OnExit(wxCommandEvent& event);
void OnReadFluxButton(wxCommandEvent&);
void OnLogMessage(std::unique_ptr<AnyLogMessage> message);
void OnLogMessage(std::shared_ptr<const AnyLogMessage> message);
void UpdateVisualisedFlux(std::shared_ptr<DiskFlux>& flux);
void UpdateDevices();
private:
std::vector<std::unique_ptr<ConfigProto>> _formats;
std::vector<std::unique_ptr<CandidateDevice>> _devices;
std::shared_ptr<DiskFlux> _currentDisk;
};
#endif

View File

@@ -1,11 +1,14 @@
#include "globals.h"
#include "visualisation.h"
#include "fmt/format.h"
#include <wx/wx.h>
#define BORDER 20
#define TICK 10
#define TRACKS 82
#define SECTORSIZE 4
VisualisationControl::VisualisationControl(wxWindow* parent,
wxWindowID id,
const wxPoint& pos,
@@ -43,11 +46,46 @@ void VisualisationControl::OnPaint(wxPaintEvent&)
dc.DrawLine({ w2, scaletop }, { w2, scalebottom });
dc.DrawLine({ w2-TICK, scaletop }, { w2+TICK, scaletop });
dc.DrawLine({ w2-TICK, scalebottom }, { w2+TICK, scalebottom });
dc.DrawLine(
{ w2-TICK, int(scaletop + 80*trackstep) },
{ w2+TICK, int(scaletop + 80*trackstep) });
for (int track = 0; track < TRACKS; track++)
if (_mode != VISMODE_NOTHING)
{
if (_mode == VISMODE_READING)
dc.SetBrush(*wxGREEN_BRUSH);
else if (_mode == VISMODE_WRITING)
dc.SetBrush(*wxRED_BRUSH);
int factor = (_head == 0) ? -1 : 1;
dc.SetPen(*wxTRANSPARENT_PEN);
int y = scaletop + (_cylinder * trackstep) - trackstep / 2;
dc.DrawRectangle(
{ w2 + factor*SECTORSIZE*2, y },
{ factor*SECTORSIZE*82, (int)trackstep }
);
}
dc.SetPen(*wxBLACK_PEN);
for (int track = 0; track <= TRACKS; track++)
{
int y = (double)track * trackstep;
dc.DrawLine({ w2-TICK/2, scaletop+y }, { w2+TICK/2, scaletop+y });
}
}
void VisualisationControl::SetMode(int cylinder, int head, int mode)
{
_cylinder = cylinder;
_head = head;
_mode = mode;
Refresh();
}
void VisualisationControl::SetDiskFlux(std::shared_ptr<DiskFlux>& disk)
{
_disk = disk;
Refresh();
}

View File

@@ -1,8 +1,17 @@
#ifndef VISUALISATION_H
#define VISUALISATION_H
#include <memory>
#include <wx/control.h>
class DiskFlux;
enum {
VISMODE_NOTHING,
VISMODE_READING,
VISMODE_WRITING
};
class VisualisationControl : public wxWindow
{
public:
@@ -12,10 +21,18 @@ public:
const wxSize& size = wxDefaultSize,
long style = 0);
public:
void SetMode(int head, int cylinder, int mode);
void SetDiskFlux(std::shared_ptr<DiskFlux>& disk);
private:
void OnPaint(wxPaintEvent & evt);
private:
int _head;
int _cylinder;
int _mode = VISMODE_NOTHING;
std::shared_ptr<DiskFlux> _disk;
wxDECLARE_EVENT_TABLE();
};