mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Initial support for twin drives and 5.25" drives.
This commit is contained in:
@@ -2900,6 +2900,39 @@
|
|||||||
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
|
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
|
||||||
<filters />
|
<filters />
|
||||||
</CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0>
|
</CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0>
|
||||||
|
<CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3">
|
||||||
|
<CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1">
|
||||||
|
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DRIVE_REG" persistent="">
|
||||||
|
<Hidden v="False" />
|
||||||
|
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||||
|
<CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2">
|
||||||
|
<dependencies>
|
||||||
|
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
|
||||||
|
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DRIVE_REG.h" persistent="Generated_Source\PSoC5\DRIVE_REG.h">
|
||||||
|
<Hidden v="False" />
|
||||||
|
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||||
|
<build_action v="HEADER;;;;" />
|
||||||
|
<PropertyDeltas />
|
||||||
|
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
|
||||||
|
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
|
||||||
|
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DRIVE_REG.c" persistent="Generated_Source\PSoC5\DRIVE_REG.c">
|
||||||
|
<Hidden v="False" />
|
||||||
|
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||||
|
<build_action v="SOURCE_C;CortexM3;;;" />
|
||||||
|
<PropertyDeltas />
|
||||||
|
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
|
||||||
|
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
|
||||||
|
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DRIVE_REG_PM.c" persistent="Generated_Source\PSoC5\DRIVE_REG_PM.c">
|
||||||
|
<Hidden v="False" />
|
||||||
|
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
|
||||||
|
<build_action v="SOURCE_C;CortexM3;;;" />
|
||||||
|
<PropertyDeltas />
|
||||||
|
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
|
||||||
|
</dependencies>
|
||||||
|
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
|
||||||
|
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
|
||||||
|
<filters />
|
||||||
|
</CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
|
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
|
||||||
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
|
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
|
||||||
|
|||||||
Binary file not shown.
@@ -6,7 +6,7 @@
|
|||||||
#include "../protocol.h"
|
#include "../protocol.h"
|
||||||
|
|
||||||
#define MOTOR_ON_TIME 5000 /* milliseconds */
|
#define MOTOR_ON_TIME 5000 /* milliseconds */
|
||||||
#define STEP_INTERVAL_TIME 3 /* ms */
|
#define STEP_INTERVAL_TIME 6 /* ms */
|
||||||
#define STEP_SETTLING_TIME 40 /* ms */
|
#define STEP_SETTLING_TIME 40 /* ms */
|
||||||
|
|
||||||
#define DISKSTATUS_WPT 1
|
#define DISKSTATUS_WPT 1
|
||||||
@@ -22,6 +22,7 @@ static bool motor_on = false;
|
|||||||
static uint32_t motor_on_time = 0;
|
static uint32_t motor_on_time = 0;
|
||||||
static bool homed = false;
|
static bool homed = false;
|
||||||
static int current_track = 0;
|
static int current_track = 0;
|
||||||
|
static int current_drive = 0;
|
||||||
|
|
||||||
#define BUFFER_COUNT 16
|
#define BUFFER_COUNT 16
|
||||||
#define BUFFER_SIZE 64
|
#define BUFFER_SIZE 64
|
||||||
@@ -540,6 +541,19 @@ static void cmd_erase(struct erase_frame* f)
|
|||||||
send_reply((struct any_frame*) &r);
|
send_reply((struct any_frame*) &r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cmd_set_drive(struct set_drive_frame* f)
|
||||||
|
{
|
||||||
|
if (current_drive != f->drive)
|
||||||
|
{
|
||||||
|
current_drive = f->drive;
|
||||||
|
DRIVE_REG_Write(current_drive);
|
||||||
|
homed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_SET_DRIVE_REPLY);
|
||||||
|
send_reply((struct any_frame*) &r);
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_command(void)
|
static void handle_command(void)
|
||||||
{
|
{
|
||||||
static uint8_t input_buffer[FRAME_SIZE];
|
static uint8_t input_buffer[FRAME_SIZE];
|
||||||
@@ -580,6 +594,10 @@ static void handle_command(void)
|
|||||||
cmd_recalibrate();
|
cmd_recalibrate();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case F_FRAME_SET_DRIVE_CMD:
|
||||||
|
cmd_set_drive((struct set_drive_frame*) f);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
send_error(F_ERROR_BAD_COMMAND);
|
send_error(F_ERROR_BAD_COMMAND);
|
||||||
}
|
}
|
||||||
@@ -594,6 +612,7 @@ int main(void)
|
|||||||
CAPTURE_DMA_FINISHED_IRQ_StartEx(&capture_dma_finished_irq_cb);
|
CAPTURE_DMA_FINISHED_IRQ_StartEx(&capture_dma_finished_irq_cb);
|
||||||
REPLAY_DMA_FINISHED_IRQ_StartEx(&replay_dma_finished_irq_cb);
|
REPLAY_DMA_FINISHED_IRQ_StartEx(&replay_dma_finished_irq_cb);
|
||||||
CAPTURE_COUNTER_Start();
|
CAPTURE_COUNTER_Start();
|
||||||
|
DRIVE_REG_Write(0);
|
||||||
/* UART_Start(); */
|
/* UART_Start(); */
|
||||||
USBFS_Start(0, USBFS_DWR_VDDD_OPERATION);
|
USBFS_Start(0, USBFS_DWR_VDDD_OPERATION);
|
||||||
|
|
||||||
|
|||||||
17
README.md
17
README.md
@@ -40,6 +40,12 @@ in software. It doesn't rely on any floppy disk controller to interpret the
|
|||||||
pulsetrain, so we can be a lot cleverer. In fact, the disk doesn't even have
|
pulsetrain, so we can be a lot cleverer. In fact, the disk doesn't even have
|
||||||
to be spinning at the same speed.
|
to be spinning at the same speed.
|
||||||
|
|
||||||
|
**Q.** Does it work on 5.25" drives?
|
||||||
|
|
||||||
|
**A.** Yes! Although PC 5.25" drives spin at 360 RPM rather than 300 RPM,
|
||||||
|
which means there's only 166ms of data on one per track rather than 200ms;
|
||||||
|
if you try to write a 3.5" format disk onto one it probably won't work.
|
||||||
|
|
||||||
**Q.** That's awesome! What formats does it support?
|
**Q.** That's awesome! What formats does it support?
|
||||||
|
|
||||||
**A.** I'm glad you asked the question. Not a lot, currently.
|
**A.** I'm glad you asked the question. Not a lot, currently.
|
||||||
@@ -91,9 +97,7 @@ Here's the physical stuff you need.
|
|||||||
|
|
||||||
- one (1) standard PC floppy disk drive. You'll have to search around as
|
- one (1) standard PC floppy disk drive. You'll have to search around as
|
||||||
they're increasingly hard to find. The FluxEngine should work with any
|
they're increasingly hard to find. The FluxEngine should work with any
|
||||||
standard 3.5" drive. It's theoretically capable of supporting 5.25"
|
standard 3.5" or 5.25" drive.
|
||||||
drives too but I'd need to modify the firmware timings. If you want this,
|
|
||||||
[get in touch](https://github.com/davidgiven/fluxengine/issues/new).
|
|
||||||
|
|
||||||
- some way of connecting the board to your drive. My prototype above uses a
|
- some way of connecting the board to your drive. My prototype above uses a
|
||||||
set of headers to let me attach the board directly on the back of the
|
set of headers to let me attach the board directly on the back of the
|
||||||
@@ -297,9 +301,10 @@ Commands which take `--source` or `--dest` take a parameter of the syntax
|
|||||||
disk; otherwise, you can specify a `.flux` file. The colon-separated
|
disk; otherwise, you can specify a `.flux` file. The colon-separated
|
||||||
modifiers limit which bits of the disk are accessed. To specify tracks, do
|
modifiers limit which bits of the disk are accessed. To specify tracks, do
|
||||||
`:t=0-9` (or just `:t=7`). For sides, do `:s=0-1` (or commonly just `:s=0`).
|
`:t=0-9` (or just `:t=7`). For sides, do `:s=0-1` (or commonly just `:s=0`).
|
||||||
If left unspecified, you get the default specified by the command, which will
|
If you have two drives, do `:d=1` (but bear in mind that you need to specify
|
||||||
vary depending on which disk format you're using (and is usually the right
|
exactly one drive; ranges won't work). If left unspecified, you get the
|
||||||
one).
|
default specified by the command, which will vary depending on which disk
|
||||||
|
format you're using (and is usually the right one).
|
||||||
|
|
||||||
### How it works
|
### How it works
|
||||||
|
|
||||||
|
|||||||
@@ -79,17 +79,22 @@ void DataSpec::set(const std::string& spec)
|
|||||||
for (size_t i = 1; i < words.size(); i++)
|
for (size_t i = 1; i < words.size(); i++)
|
||||||
{
|
{
|
||||||
auto mod = parseMod(words[i]);
|
auto mod = parseMod(words[i]);
|
||||||
if ((mod.name != "t") && (mod.name != "s"))
|
if ((mod.name != "t") && (mod.name != "s") && (mod.name != "d"))
|
||||||
Error() << fmt::format("unknown data modifier '{}'", mod.name);
|
Error() << fmt::format("unknown data modifier '{}'", mod.name);
|
||||||
modifiers[mod.name] = mod;
|
modifiers[mod.name] = mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto& drives = modifiers["d"].data;
|
||||||
|
if (drives.size() != 1)
|
||||||
|
Error() << "you must specify exactly one drive";
|
||||||
|
drive = *drives.begin();
|
||||||
|
|
||||||
const auto& tracks = modifiers["t"].data;
|
const auto& tracks = modifiers["t"].data;
|
||||||
const auto& sides = modifiers["s"].data;
|
const auto& sides = modifiers["s"].data;
|
||||||
for (auto track : tracks)
|
for (auto track : tracks)
|
||||||
{
|
{
|
||||||
for (auto side : sides)
|
for (auto side : sides)
|
||||||
locations.push_back({ track, side });
|
locations.push_back({ drive, track, side });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,15 @@ class DataSpec
|
|||||||
public:
|
public:
|
||||||
struct Location
|
struct Location
|
||||||
{
|
{
|
||||||
|
unsigned drive;
|
||||||
unsigned track;
|
unsigned track;
|
||||||
unsigned side;
|
unsigned side;
|
||||||
|
|
||||||
bool operator == (const Location& other) const
|
bool operator == (const Location& other) const
|
||||||
{ return (track == other.track) && (side == other.side); }
|
{ return (drive == other.drive) && (track == other.track) && (side == other.side); }
|
||||||
|
|
||||||
bool operator != (const Location& other) const
|
bool operator != (const Location& other) const
|
||||||
{ return (track != other.track) || (side != other.side); }
|
{ return (drive != other.drive) || (track != other.track) || (side != other.side); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Modifier
|
struct Modifier
|
||||||
@@ -44,6 +45,7 @@ public:
|
|||||||
std::string filename;
|
std::string filename;
|
||||||
std::map<std::string, Modifier> modifiers;
|
std::map<std::string, Modifier> modifiers;
|
||||||
std::vector<Location> locations;
|
std::vector<Location> locations;
|
||||||
|
unsigned drive;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator << (std::ostream& os, const DataSpec& dataSpec)
|
std::ostream& operator << (std::ostream& os, const DataSpec& dataSpec)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
static DataSpecFlag source(
|
static DataSpecFlag source(
|
||||||
{ "--source", "-s" },
|
{ "--source", "-s" },
|
||||||
"source for data",
|
"source for data",
|
||||||
":t=0-79:s=0-1");
|
":t=0-79:s=0-1:d=0");
|
||||||
|
|
||||||
static StringFlag destination(
|
static StringFlag destination(
|
||||||
{ "--write-flux", "-f" },
|
{ "--write-flux", "-f" },
|
||||||
@@ -63,6 +63,7 @@ std::unique_ptr<Fluxmap> ReaderTrack::read()
|
|||||||
|
|
||||||
std::unique_ptr<Fluxmap> CapturedReaderTrack::reallyRead()
|
std::unique_ptr<Fluxmap> CapturedReaderTrack::reallyRead()
|
||||||
{
|
{
|
||||||
|
usbSetDrive(drive);
|
||||||
usbSeek(track);
|
usbSeek(track);
|
||||||
return usbRead(side, revolutions);
|
return usbRead(side, revolutions);
|
||||||
}
|
}
|
||||||
@@ -104,6 +105,7 @@ std::vector<std::unique_ptr<ReaderTrack>> readTracks()
|
|||||||
dataSpec.filename.empty()
|
dataSpec.filename.empty()
|
||||||
? (ReaderTrack*)new CapturedReaderTrack()
|
? (ReaderTrack*)new CapturedReaderTrack()
|
||||||
: (ReaderTrack*)new FileReaderTrack());
|
: (ReaderTrack*)new FileReaderTrack());
|
||||||
|
t->drive = location.drive;
|
||||||
t->track = location.track;
|
t->track = location.track;
|
||||||
t->side = location.side;
|
t->side = location.side;
|
||||||
tracks.push_back(std::move(t));
|
tracks.push_back(std::move(t));
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ class ReaderTrack
|
|||||||
public:
|
public:
|
||||||
virtual ~ReaderTrack() {}
|
virtual ~ReaderTrack() {}
|
||||||
|
|
||||||
|
int drive;
|
||||||
int track;
|
int track;
|
||||||
int side;
|
int side;
|
||||||
|
|
||||||
|
|||||||
12
lib/usb.cc
12
lib/usb.cc
@@ -244,3 +244,15 @@ void usbErase(int side)
|
|||||||
await_reply<struct any_frame>(F_FRAME_ERASE_REPLY);
|
await_reply<struct any_frame>(F_FRAME_ERASE_REPLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void usbSetDrive(int drive)
|
||||||
|
{
|
||||||
|
usb_init();
|
||||||
|
|
||||||
|
struct set_drive_frame f = {
|
||||||
|
{ .type = F_FRAME_SET_DRIVE_CMD, .size = sizeof(f) },
|
||||||
|
.drive = (uint8_t) drive
|
||||||
|
};
|
||||||
|
usb_cmd_send(&f, f.f.size);
|
||||||
|
await_reply<struct any_frame>(F_FRAME_SET_DRIVE_REPLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,5 +11,6 @@ extern void usbTestBulkTransport();
|
|||||||
extern std::unique_ptr<Fluxmap> usbRead(int side, int revolutions);
|
extern std::unique_ptr<Fluxmap> usbRead(int side, int revolutions);
|
||||||
extern void usbWrite(int side, const Fluxmap& fluxmap);
|
extern void usbWrite(int side, const Fluxmap& fluxmap);
|
||||||
extern void usbErase(int side);
|
extern void usbErase(int side);
|
||||||
|
extern void usbSetDrive(int drive);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ enum
|
|||||||
F_FRAME_ERASE_REPLY, /* any_frame */
|
F_FRAME_ERASE_REPLY, /* any_frame */
|
||||||
F_FRAME_RECALIBRATE_CMD, /* any_frame */
|
F_FRAME_RECALIBRATE_CMD, /* any_frame */
|
||||||
F_FRAME_RECALIBRATE_REPLY, /* any_frame */
|
F_FRAME_RECALIBRATE_REPLY, /* any_frame */
|
||||||
|
F_FRAME_SET_DRIVE_CMD, /* setdrive_frame */
|
||||||
|
F_FRAME_SET_DRIVE_REPLY, /* any_frame */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@@ -121,4 +123,10 @@ struct erase_frame
|
|||||||
uint8_t side;
|
uint8_t side;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct set_drive_frame
|
||||||
|
{
|
||||||
|
struct frame_header f;
|
||||||
|
uint8_t drive;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "flags.h"
|
#include "flags.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
|
#include "dataspec.h"
|
||||||
|
|
||||||
|
static DataSpecFlag source(
|
||||||
|
{ "--source", "-s" },
|
||||||
|
"source for data",
|
||||||
|
":d=0");
|
||||||
|
|
||||||
int main(int argc, const char* argv[])
|
int main(int argc, const char* argv[])
|
||||||
{
|
{
|
||||||
Flag::parseFlags(argc, argv);
|
Flag::parseFlags(argc, argv);
|
||||||
|
|
||||||
|
usbSetDrive(source.value.drive);
|
||||||
nanoseconds_t period = usbGetRotationalPeriod();
|
nanoseconds_t period = usbGetRotationalPeriod();
|
||||||
std::cout << "Rotational period is " << period/1000 << " ms (" << 60e6/period << " rpm)" << std::endl;
|
std::cout << "Rotational period is " << period/1000 << " ms (" << 60e6/period << " rpm)" << std::endl;
|
||||||
|
|
||||||
|
|||||||
@@ -35,40 +35,40 @@ static void test_parsemod(void)
|
|||||||
|
|
||||||
static void test_dataspec(void)
|
static void test_dataspec(void)
|
||||||
{
|
{
|
||||||
DataSpec spec("foo:t=0-2:s=0-1");
|
DataSpec spec("foo:t=0-2:s=0-1:d=0");
|
||||||
assert(spec.filename == "foo");
|
assert(spec.filename == "foo");
|
||||||
assert((spec.locations
|
assert((spec.locations
|
||||||
== std::vector<DataSpec::Location>
|
== std::vector<DataSpec::Location>
|
||||||
{{0, 0}, {0, 1}, {1, 0}, {1, 1}, {2, 0}, {2, 1}}));
|
{{0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {0, 2, 0}, {0, 2, 1}}));
|
||||||
assert((std::string)spec == "foo:s=0-1:t=0-2");
|
assert((std::string)spec == "foo:d=0:s=0-1:t=0-2");
|
||||||
|
|
||||||
spec.set("bar");
|
spec.set("bar");
|
||||||
assert(spec.filename == "bar");
|
assert(spec.filename == "bar");
|
||||||
assert((spec.locations
|
assert((spec.locations
|
||||||
== std::vector<DataSpec::Location>
|
== std::vector<DataSpec::Location>
|
||||||
{{0, 0}, {0, 1}, {1, 0}, {1, 1}, {2, 0}, {2, 1}}));
|
{{0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {0, 2, 0}, {0, 2, 1}}));
|
||||||
assert((std::string)spec == "bar:s=0-1:t=0-2");
|
assert((std::string)spec == "bar:d=0:s=0-1:t=0-2");
|
||||||
|
|
||||||
spec.set(":t=0");
|
spec.set(":t=0");
|
||||||
assert(spec.filename.empty());
|
assert(spec.filename.empty());
|
||||||
assert((spec.locations
|
assert((spec.locations
|
||||||
== std::vector<DataSpec::Location>
|
== std::vector<DataSpec::Location>
|
||||||
{{0, 0}, {0, 1}}));
|
{{0, 0, 0}, {0, 0, 1}}));
|
||||||
assert((std::string)spec == ":s=0-1:t=0");
|
assert((std::string)spec == ":d=0:s=0-1:t=0");
|
||||||
|
|
||||||
spec.set(":s=1");
|
spec.set(":s=1");
|
||||||
assert(spec.filename.empty());
|
assert(spec.filename.empty());
|
||||||
assert((spec.locations
|
assert((spec.locations
|
||||||
== std::vector<DataSpec::Location>
|
== std::vector<DataSpec::Location>
|
||||||
{{0, 1}}));
|
{{0, 0, 1}}));
|
||||||
assert((std::string)spec == ":s=1:t=0");
|
assert((std::string)spec == ":d=0:s=1:t=0");
|
||||||
|
|
||||||
spec.set(":t=9");
|
spec.set(":t=9:d=1");
|
||||||
assert(spec.filename.empty());
|
assert(spec.filename.empty());
|
||||||
assert((spec.locations
|
assert((spec.locations
|
||||||
== std::vector<DataSpec::Location>
|
== std::vector<DataSpec::Location>
|
||||||
{{9, 1}}));
|
{{1, 9, 1}}));
|
||||||
assert((std::string)spec == ":s=1:t=9");
|
assert((std::string)spec == ":d=1:s=1:t=9");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[])
|
int main(int argc, const char* argv[])
|
||||||
|
|||||||
Reference in New Issue
Block a user