Greying out of the option buttons now works; but the whole way configs are

handled is pretty unsatisfactory and needs work.
This commit is contained in:
dg
2023-05-13 23:29:34 +00:00
parent dd8cc7bfd4
commit 4daaec46a7
10 changed files with 190 additions and 176 deletions

View File

@@ -50,7 +50,7 @@ void Config::set(std::string key, std::string value)
setProtoByString(*this, key, value);
}
std::string Config::get(std::string key)
std::string Config::get(std::string key) const
{
return getProtoByString(*this, key);
}
@@ -82,7 +82,7 @@ void Config::readConfigFile(std::string filename)
globalConfig()->MergeFrom(loadSingleConfigFile(filename));
}
const OptionProto& Config::findOption(const std::string& optionName)
const OptionProto& Config::findOption(const std::string& optionName) const
{
const OptionProto* found = nullptr;
@@ -108,10 +108,11 @@ const OptionProto& Config::findOption(const std::string& optionName)
return *found;
}
throw OptionNotFoundException("option name not found");
throw OptionNotFoundException(
fmt::format("option {} not found", optionName));
}
void Config::checkOptionValid(const OptionProto& option)
void Config::checkOptionValid(const OptionProto& option) const
{
for (const auto& req : option.requires())
{
@@ -151,7 +152,7 @@ void Config::checkOptionValid(const OptionProto& option)
}
}
bool Config::isOptionValid(const OptionProto& option)
bool Config::isOptionValid(const OptionProto& option) const
{
try
{
@@ -164,6 +165,11 @@ bool Config::isOptionValid(const OptionProto& option)
}
}
bool Config::isOptionValid(std::string option) const
{
return isOptionValid(findOption(option));
}
void Config::applyOption(const OptionProto& option)
{
if (option.config().option_size() > 0)

View File

@@ -57,7 +57,7 @@ public:
/* Set and get individual config keys. */
void set(std::string key, std::string value);
std::string get(std::string key);
std::string get(std::string key) const;
/* Reset the entire configuration. */
@@ -75,9 +75,10 @@ public:
/* Option management: look up an option by name, determine whether an option
* is valid, and apply an option. */
const OptionProto& findOption(const std::string& option);
void checkOptionValid(const OptionProto& option);
bool isOptionValid(const OptionProto& option);
const OptionProto& findOption(const std::string& option) const;
void checkOptionValid(const OptionProto& option) const;
bool isOptionValid(const OptionProto& option) const;
bool isOptionValid(std::string option) const;
void applyOption(const OptionProto& option);
/* Adjust overall inputs and outputs. */

View File

@@ -2,7 +2,7 @@ syntax = "proto2";
import "lib/common.proto";
// Next: 15
// Next: 17
message DriveProto
{
optional int32 drive = 1
@@ -11,6 +11,9 @@ message DriveProto
[ default = INDEXMODE_DRIVE, (help) = "index pulse source" ];
optional int32 hard_sector_count = 3
[ default = 0, (help) = "number of hard sectors on disk" ];
optional double hard_sector_threshold_ns = 16
[ default = 0, (help) = "index pulses longer than this interval are "
"considered sector markers; shorter indicates an true index marker" ];
optional bool high_density = 4
[ default = true, (help) = "set if this is a high density disk" ];
optional bool sync_with_index = 5

View File

@@ -11,32 +11,19 @@
class HardwareFluxSink : public FluxSink
{
public:
HardwareFluxSink(const HardwareFluxSinkProto& conf): _config(conf)
{
nanoseconds_t oneRevolution;
measureDiskRotation(oneRevolution, _hardSectorThreshold);
}
HardwareFluxSink(const HardwareFluxSinkProto& conf): _config(conf) {}
~HardwareFluxSink() {}
public:
void writeFlux(int track, int side, const Fluxmap& fluxmap) override
{
usbSetDrive(globalConfig()->drive().drive(),
globalConfig()->drive().high_density(),
globalConfig()->drive().index_mode());
#if 0
if (fluxSourceSinkFortyTrack)
{
if (track & 1)
error("cannot write to odd physical tracks in 40-track mode");
usbSeek(track / 2);
}
else
#endif
auto& drive = globalConfig()->drive();
usbSetDrive(drive.drive(), drive.high_density(), drive.index_mode());
usbSeek(track);
return usbWrite(side, fluxmap.rawBytes(), _hardSectorThreshold);
return usbWrite(
side, fluxmap.rawBytes(), drive.hard_sector_threshold_ns());
}
bool isHardware() const override
@@ -51,7 +38,6 @@ public:
private:
const HardwareFluxSinkProto& _config;
nanoseconds_t _hardSectorThreshold;
};
std::unique_ptr<FluxSink> FluxSink::createHardwareFluxSink(

View File

@@ -14,54 +14,48 @@ private:
class HardwareFluxSourceIterator : public FluxSourceIterator
{
public:
HardwareFluxSourceIterator(
const HardwareFluxSource& fluxsource, int track, int head):
_fluxsource(fluxsource),
HardwareFluxSourceIterator(int track, int head):
_track(track),
_head(head)
{
}
bool hasNext() const
bool hasNext() const override
{
return true;
}
std::unique_ptr<const Fluxmap> next()
std::unique_ptr<const Fluxmap> next() override
{
usbSetDrive(globalConfig()->drive().drive(),
globalConfig()->drive().high_density(),
globalConfig()->drive().index_mode());
const auto& drive = globalConfig()->drive();
usbSetDrive(
drive.drive(), drive.high_density(), drive.index_mode());
usbSeek(_track);
Bytes data = usbRead(_head,
globalConfig()->drive().sync_with_index(),
globalConfig()->drive().revolutions() *
_fluxsource._oneRevolution,
_fluxsource._hardSectorThreshold);
drive.sync_with_index(),
drive.revolutions() * drive.rotational_period_ms() * 1e6,
drive.hard_sector_threshold_ns());
auto fluxmap = std::make_unique<Fluxmap>();
fluxmap->appendBytes(data);
return fluxmap;
}
private:
const HardwareFluxSource& _fluxsource;
int _track;
int _head;
};
public:
HardwareFluxSource(const HardwareFluxSourceProto& conf): _config(conf)
{
measureDiskRotation(_oneRevolution, _hardSectorThreshold);
}
HardwareFluxSource(const HardwareFluxSourceProto& conf): _config(conf) {}
~HardwareFluxSource() {}
public:
std::unique_ptr<FluxSourceIterator> readFlux(int track, int head) override
{
return std::make_unique<HardwareFluxSourceIterator>(*this, track, head);
return std::make_unique<HardwareFluxSourceIterator>(track, head);
}
void recalibrate() override
@@ -81,8 +75,7 @@ public:
private:
const HardwareFluxSourceProto& _config;
nanoseconds_t _oneRevolution;
nanoseconds_t _hardSectorThreshold;
bool _measured;
};
std::unique_ptr<FluxSource> FluxSource::createHardwareFluxSource(

View File

@@ -55,33 +55,24 @@ private:
_cache;
};
void measureDiskRotation(
nanoseconds_t& oneRevolution, nanoseconds_t& hardSectorThreshold)
void measureDiskRotation()
{
log(BeginSpeedOperationLogMessage());
int retries = 5;
usbSetDrive(globalConfig()->drive().drive(),
globalConfig()->drive().high_density(),
globalConfig()->drive().index_mode());
oneRevolution = globalConfig()->drive().rotational_period_ms() * 1e6;
if (globalConfig()->drive().hard_sector_count() != 0)
hardSectorThreshold = oneRevolution * 3 /
(4 * globalConfig()->drive().hard_sector_count());
else
hardSectorThreshold = 0;
nanoseconds_t oneRevolution =
globalConfig()->drive().rotational_period_ms() * 1e6;
if (oneRevolution == 0)
{
usbSetDrive(globalConfig()->drive().drive(),
globalConfig()->drive().high_density(),
globalConfig()->drive().index_mode());
log(BeginOperationLogMessage{"Measuring drive rotational speed"});
int retries = 5;
do
{
oneRevolution = usbGetRotationalPeriod(
globalConfig()->drive().hard_sector_count());
if (globalConfig()->drive().hard_sector_count() != 0)
hardSectorThreshold =
oneRevolution * 3 /
(4 * globalConfig()->drive().hard_sector_count());
retries--;
} while ((oneRevolution == 0) && (retries > 0));
@@ -90,6 +81,13 @@ void measureDiskRotation(
log(EndOperationLogMessage{});
}
if (!globalConfig()->drive().hard_sector_threshold_ns())
{
globalConfig()->mutable_drive()->set_hard_sector_threshold_ns(
oneRevolution * 3 /
(4 * globalConfig()->drive().hard_sector_count()));
}
if (oneRevolution == 0)
error("Failed\nIs a disk in the drive?");
@@ -258,6 +256,8 @@ void writeTracks(FluxSink& fluxSink,
{
log(BeginOperationLogMessage{"Encoding and writing to disk"});
if (fluxSink.isHardware())
measureDiskRotation();
int index = 0;
for (auto& trackInfo : trackInfos)
{
@@ -495,6 +495,8 @@ std::shared_ptr<const DiskFlux> readDiskCommand(
auto diskflux = std::make_shared<DiskFlux>();
log(BeginOperationLogMessage{"Reading and decoding disk"});
if (fluxSource.isHardware())
measureDiskRotation();
auto locations = Layout::computeLocations();
unsigned index = 0;
for (auto& trackInfo : locations)
@@ -605,6 +607,8 @@ void rawReadDiskCommand(FluxSource& fluxsource, FluxSink& fluxsink)
{
log(BeginOperationLogMessage{"Performing raw read of disk"});
if (fluxsource.isHardware() || fluxsink.isHardware())
measureDiskRotation();
auto locations = Layout::computeLocations();
unsigned index = 0;
for (auto& trackInfo : locations)

View File

@@ -14,8 +14,7 @@ class ImageWriter;
class TrackInfo;
class TrackFlux;
extern void measureDiskRotation(
nanoseconds_t& oneRevolution, nanoseconds_t& hardSectorThreshold);
extern void measureDiskRotation();
extern void writeTracks(FluxSink& fluxSink,
const std::function<std::unique_ptr<const Fluxmap>(

View File

@@ -71,6 +71,11 @@ option_group {
comment: '140kB 5.25" 35-track SS'
set_by_default: true
requires {
key: "drive.tpi"
value: ["48", "96"]
}
config {
layout {
tpi: 48
@@ -91,6 +96,11 @@ option_group {
name: "640"
comment: '640kB 5.25" 80-track DS'
requires {
key: "drive.tpi"
value: ["96"]
}
config {
layout {
tpi: 96

View File

@@ -206,26 +206,6 @@ public:
globalConfig().readConfigFile(setting);
}
/* Apply any format options. */
std::set<std::string> options;
for (const auto& e : _formatOptions)
{
if (e.first == formatName)
options.insert(e.second);
}
/* Locate the device, if any. */
auto serial = _selectedDevice;
if (!serial.empty() && (serial[0] == '/'))
overrides.push_back(
std::make_pair("usb.greaseweazle.port", serial));
else
overrides.push_back(std::make_pair("usb.serial", serial));
ClearLog();
/* Apply the source/destination. */
switch (_selectedSource)
@@ -240,7 +220,6 @@ public:
globalConfig().setFluxSink(filename);
globalConfig().setFluxSource(filename);
globalConfig().setVerificationFluxSource(filename);
break;
}
@@ -259,6 +238,35 @@ public:
}
}
/* Apply any format options. */
std::set<std::string> options;
for (const auto& e : _formatOptions)
{
if (e.first == formatName)
{
try
{
if (globalConfig().isOptionValid(e.second))
options.insert(e.second);
}
catch (const OptionException& e)
{
}
}
}
/* Locate the device, if any. */
auto serial = _selectedDevice;
if (!serial.empty() && (serial[0] == '/'))
overrides.push_back(
std::make_pair("usb.greaseweazle.port", serial));
else
overrides.push_back(std::make_pair("usb.serial", serial));
ClearLog();
/* Resolve the rest of the stuff. */
globalConfig().initialise(options, overrides);
@@ -574,111 +582,107 @@ private:
void UpdateFormatOptions()
{
int formatSelection = formatChoice->GetSelection();
_currentlyDisplayedFormat = formatSelection;
PrepareConfig();
assert(!wxGetApp().IsWorkerThreadRunning());
int formatSelection = formatChoice->GetSelection();
if (formatSelection != _currentlyDisplayedFormat)
formatOptionsContainer->DestroyChildren();
auto* sizer = new wxBoxSizer(wxVERTICAL);
if (formatSelection == wxNOT_FOUND)
sizer->Add(new wxStaticText(
formatOptionsContainer, wxID_ANY, "(no format selected)"));
else
{
_currentlyDisplayedFormat = formatSelection;
formatOptionsContainer->DestroyChildren();
auto* sizer = new wxBoxSizer(wxVERTICAL);
std::string formatName = _formatNames[formatChoice->GetSelection()];
if (formatSelection == wxNOT_FOUND)
sizer->Add(new wxStaticText(
formatOptionsContainer, wxID_ANY, "(no format selected)"));
else
for (auto& group : globalConfig()->option_group())
{
globalConfig().clear();
std::string formatName =
_formatNames[formatChoice->GetSelection()];
globalConfig().readConfigFile(formatName);
sizer->Add(new wxStaticText(
formatOptionsContainer, wxID_ANY, group.comment() + ":"));
for (auto& group : globalConfig()->option_group())
bool first = true;
bool valueSet = false;
wxRadioButton* defaultButton = nullptr;
for (auto& option : group.option())
{
sizer->Add(new wxStaticText(formatOptionsContainer,
auto* rb = new wxRadioButton(formatOptionsContainer,
wxID_ANY,
group.comment() + ":"));
bool first = true;
bool valueSet = false;
wxRadioButton* defaultButton = nullptr;
for (auto& option : group.option())
{
auto* rb = new wxRadioButton(formatOptionsContainer,
wxID_ANY,
option.comment(),
wxDefaultPosition,
wxDefaultSize,
first ? wxRB_GROUP : 0);
auto key = std::make_pair(formatName, option.name());
sizer->Add(rb);
rb->Bind(wxEVT_RADIOBUTTON,
[=](wxCommandEvent& e)
{
for (auto& option : group.option())
{
_formatOptions.erase(std::make_pair(
formatName, option.name()));
}
_formatOptions.insert(key);
OnControlsChanged(e);
});
if (_formatOptions.find(key) != _formatOptions.end())
{
rb->SetValue(true);
valueSet = true;
}
if (option.set_by_default() || !defaultButton)
defaultButton = rb;
first = false;
}
if (!valueSet && defaultButton)
defaultButton->SetValue(true);
}
/* Anything that's _not_ in a group gets a checkbox. */
for (auto& option : globalConfig()->option())
{
auto* choice = new wxCheckBox(
formatOptionsContainer, wxID_ANY, option.comment());
option.comment(),
wxDefaultPosition,
wxDefaultSize,
first ? wxRB_GROUP : 0);
auto key = std::make_pair(formatName, option.name());
sizer->Add(choice);
sizer->Add(rb);
choice->SetValue(
(_formatOptions.find(key) != _formatOptions.end()) ||
option.set_by_default());
choice->Bind(wxEVT_CHECKBOX,
rb->Bind(wxEVT_RADIOBUTTON,
[=](wxCommandEvent& e)
{
if (choice->GetValue())
_formatOptions.insert(key);
else
_formatOptions.erase(key);
for (auto& option : group.option())
{
_formatOptions.erase(
std::make_pair(formatName, option.name()));
}
_formatOptions.insert(key);
OnControlsChanged(e);
});
if (_formatOptions.find(key) != _formatOptions.end())
{
rb->SetValue(true);
valueSet = true;
}
rb->Enable(globalConfig().isOptionValid(option));
if (option.set_by_default() || !defaultButton)
defaultButton = rb;
first = false;
}
if (globalConfig()->option().empty() &&
globalConfig()->option_group().empty())
sizer->Add(new wxStaticText(formatOptionsContainer,
wxID_ANY,
"(no options for this format)"));
if (!valueSet && defaultButton)
defaultButton->SetValue(true);
}
formatOptionsContainer->SetSizerAndFit(sizer);
Layout();
SafeFit();
/* Anything that's _not_ in a group gets a checkbox. */
for (auto& option : globalConfig()->option())
{
auto* choice = new wxCheckBox(
formatOptionsContainer, wxID_ANY, option.comment());
auto key = std::make_pair(formatName, option.name());
sizer->Add(choice);
choice->SetValue(
(_formatOptions.find(key) != _formatOptions.end()) ||
option.set_by_default());
choice->Bind(wxEVT_CHECKBOX,
[=](wxCommandEvent& e)
{
if (choice->GetValue())
_formatOptions.insert(key);
else
_formatOptions.erase(key);
OnControlsChanged(e);
});
}
if (globalConfig()->option().empty() &&
globalConfig()->option_group().empty())
sizer->Add(new wxStaticText(formatOptionsContainer,
wxID_ANY,
"(no options for this format)"));
}
formatOptionsContainer->SetSizerAndFit(sizer);
Layout();
SafeFit();
}
void UpdateDevices()

View File

@@ -74,6 +74,14 @@ static void test_option_validity()
int main(int argc, const char* argv[])
{
test_option_validity();
return 0;
try
{
test_option_validity();
return 0;
}
catch (const ErrorException& e)
{
fmt::print(stderr, "Error: {}\n", e.message);
return 1;
}
}