Initial support for twin drives and 5.25" drives.

This commit is contained in:
David Given
2019-02-11 23:43:44 +01:00
parent b6f99d4429
commit 2527ac2ce9
13 changed files with 119 additions and 24 deletions

View File

@@ -2900,6 +2900,39 @@
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
<filters />
</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>
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>

View File

Binary file not shown.

View File

@@ -6,7 +6,7 @@
#include "../protocol.h"
#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 DISKSTATUS_WPT 1
@@ -22,6 +22,7 @@ static bool motor_on = false;
static uint32_t motor_on_time = 0;
static bool homed = false;
static int current_track = 0;
static int current_drive = 0;
#define BUFFER_COUNT 16
#define BUFFER_SIZE 64
@@ -540,6 +541,19 @@ static void cmd_erase(struct erase_frame* f)
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 uint8_t input_buffer[FRAME_SIZE];
@@ -580,6 +594,10 @@ static void handle_command(void)
cmd_recalibrate();
break;
case F_FRAME_SET_DRIVE_CMD:
cmd_set_drive((struct set_drive_frame*) f);
break;
default:
send_error(F_ERROR_BAD_COMMAND);
}
@@ -594,6 +612,7 @@ int main(void)
CAPTURE_DMA_FINISHED_IRQ_StartEx(&capture_dma_finished_irq_cb);
REPLAY_DMA_FINISHED_IRQ_StartEx(&replay_dma_finished_irq_cb);
CAPTURE_COUNTER_Start();
DRIVE_REG_Write(0);
/* UART_Start(); */
USBFS_Start(0, USBFS_DWR_VDDD_OPERATION);

View File

@@ -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
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?
**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
they're increasingly hard to find. The FluxEngine should work with any
standard 3.5" drive. It's theoretically capable of supporting 5.25"
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).
standard 3.5" or 5.25" drive.
- 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
@@ -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
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`).
If left unspecified, you get the default specified by the command, which will
vary depending on which disk format you're using (and is usually the right
one).
If you have two drives, do `:d=1` (but bear in mind that you need to specify
exactly one drive; ranges won't work). If left unspecified, you get the
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

View File

@@ -79,17 +79,22 @@ void DataSpec::set(const std::string& spec)
for (size_t i = 1; i < words.size(); 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);
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& sides = modifiers["s"].data;
for (auto track : tracks)
{
for (auto side : sides)
locations.push_back({ track, side });
locations.push_back({ drive, track, side });
}
}
}

View File

@@ -6,14 +6,15 @@ class DataSpec
public:
struct Location
{
unsigned drive;
unsigned track;
unsigned side;
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
{ return (track != other.track) || (side != other.side); }
{ return (drive != other.drive) || (track != other.track) || (side != other.side); }
};
struct Modifier
@@ -44,6 +45,7 @@ public:
std::string filename;
std::map<std::string, Modifier> modifiers;
std::vector<Location> locations;
unsigned drive;
};
std::ostream& operator << (std::ostream& os, const DataSpec& dataSpec)

View File

@@ -15,7 +15,7 @@
static DataSpecFlag source(
{ "--source", "-s" },
"source for data",
":t=0-79:s=0-1");
":t=0-79:s=0-1:d=0");
static StringFlag destination(
{ "--write-flux", "-f" },
@@ -63,6 +63,7 @@ std::unique_ptr<Fluxmap> ReaderTrack::read()
std::unique_ptr<Fluxmap> CapturedReaderTrack::reallyRead()
{
usbSetDrive(drive);
usbSeek(track);
return usbRead(side, revolutions);
}
@@ -104,6 +105,7 @@ std::vector<std::unique_ptr<ReaderTrack>> readTracks()
dataSpec.filename.empty()
? (ReaderTrack*)new CapturedReaderTrack()
: (ReaderTrack*)new FileReaderTrack());
t->drive = location.drive;
t->track = location.track;
t->side = location.side;
tracks.push_back(std::move(t));

View File

@@ -10,6 +10,7 @@ class ReaderTrack
public:
virtual ~ReaderTrack() {}
int drive;
int track;
int side;

View File

@@ -244,3 +244,15 @@ void usbErase(int side)
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);
}

View File

@@ -11,5 +11,6 @@ extern void usbTestBulkTransport();
extern std::unique_ptr<Fluxmap> usbRead(int side, int revolutions);
extern void usbWrite(int side, const Fluxmap& fluxmap);
extern void usbErase(int side);
extern void usbSetDrive(int drive);
#endif

View File

@@ -56,6 +56,8 @@ enum
F_FRAME_ERASE_REPLY, /* any_frame */
F_FRAME_RECALIBRATE_CMD, /* any_frame */
F_FRAME_RECALIBRATE_REPLY, /* any_frame */
F_FRAME_SET_DRIVE_CMD, /* setdrive_frame */
F_FRAME_SET_DRIVE_REPLY, /* any_frame */
};
enum
@@ -121,4 +123,10 @@ struct erase_frame
uint8_t side;
};
struct set_drive_frame
{
struct frame_header f;
uint8_t drive;
};
#endif

View File

@@ -1,11 +1,18 @@
#include "globals.h"
#include "flags.h"
#include "usb.h"
#include "dataspec.h"
static DataSpecFlag source(
{ "--source", "-s" },
"source for data",
":d=0");
int main(int argc, const char* argv[])
{
Flag::parseFlags(argc, argv);
usbSetDrive(source.value.drive);
nanoseconds_t period = usbGetRotationalPeriod();
std::cout << "Rotational period is " << period/1000 << " ms (" << 60e6/period << " rpm)" << std::endl;

View File

@@ -35,40 +35,40 @@ static void test_parsemod(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.locations
== std::vector<DataSpec::Location>
{{0, 0}, {0, 1}, {1, 0}, {1, 1}, {2, 0}, {2, 1}}));
assert((std::string)spec == "foo:s=0-1:t=0-2");
{{0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {0, 2, 0}, {0, 2, 1}}));
assert((std::string)spec == "foo:d=0:s=0-1:t=0-2");
spec.set("bar");
assert(spec.filename == "bar");
assert((spec.locations
== std::vector<DataSpec::Location>
{{0, 0}, {0, 1}, {1, 0}, {1, 1}, {2, 0}, {2, 1}}));
assert((std::string)spec == "bar:s=0-1:t=0-2");
{{0, 0, 0}, {0, 0, 1}, {0, 1, 0}, {0, 1, 1}, {0, 2, 0}, {0, 2, 1}}));
assert((std::string)spec == "bar:d=0:s=0-1:t=0-2");
spec.set(":t=0");
assert(spec.filename.empty());
assert((spec.locations
== std::vector<DataSpec::Location>
{{0, 0}, {0, 1}}));
assert((std::string)spec == ":s=0-1:t=0");
{{0, 0, 0}, {0, 0, 1}}));
assert((std::string)spec == ":d=0:s=0-1:t=0");
spec.set(":s=1");
assert(spec.filename.empty());
assert((spec.locations
== std::vector<DataSpec::Location>
{{0, 1}}));
assert((std::string)spec == ":s=1:t=0");
{{0, 0, 1}}));
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.locations
== std::vector<DataSpec::Location>
{{9, 1}}));
assert((std::string)spec == ":s=1:t=9");
{{1, 9, 1}}));
assert((std::string)spec == ":d=1:s=1:t=9");
}
int main(int argc, const char* argv[])