mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Reads mostly work; writes not yet.
This commit is contained in:
1
build.py
1
build.py
@@ -211,6 +211,7 @@ cxxlibrary(
|
|||||||
"lib/proto.h": "./lib/proto.h",
|
"lib/proto.h": "./lib/proto.h",
|
||||||
"lib/readerwriter.h": "./lib/readerwriter.h",
|
"lib/readerwriter.h": "./lib/readerwriter.h",
|
||||||
"lib/sector.h": "./lib/sector.h",
|
"lib/sector.h": "./lib/sector.h",
|
||||||
|
"lib/usb/applesauce.h": "./lib/usb/applesauce.h",
|
||||||
"lib/usb/greaseweazle.h": "./lib/usb/greaseweazle.h",
|
"lib/usb/greaseweazle.h": "./lib/usb/greaseweazle.h",
|
||||||
"lib/usb/usb.h": "./lib/usb/usb.h",
|
"lib/usb/usb.h": "./lib/usb/usb.h",
|
||||||
"lib/usb/usbfinder.h": "./lib/usb/usbfinder.h",
|
"lib/usb/usbfinder.h": "./lib/usb/usbfinder.h",
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ bool FluxmapReader::findEvent(int event, unsigned& ticks)
|
|||||||
{
|
{
|
||||||
ticks = 0;
|
ticks = 0;
|
||||||
|
|
||||||
for (;;)
|
while (!eof())
|
||||||
{
|
{
|
||||||
unsigned thisTicks;
|
unsigned thisTicks;
|
||||||
int thisEvent;
|
int thisEvent;
|
||||||
@@ -57,11 +57,11 @@ bool FluxmapReader::findEvent(int event, unsigned& ticks)
|
|||||||
if (thisEvent == F_EOF)
|
if (thisEvent == F_EOF)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (eof())
|
|
||||||
return false;
|
|
||||||
if ((event == thisEvent) || (event & thisEvent))
|
if ((event == thisEvent) || (event & thisEvent))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned FluxmapReader::readInterval(nanoseconds_t clock)
|
unsigned FluxmapReader::readInterval(nanoseconds_t clock)
|
||||||
|
|||||||
@@ -4,13 +4,44 @@
|
|||||||
#include "lib/bytes.h"
|
#include "lib/bytes.h"
|
||||||
#include "greaseweazle.h"
|
#include "greaseweazle.h"
|
||||||
#include "lib/fluxmap.h"
|
#include "lib/fluxmap.h"
|
||||||
|
#include "lib/decoders/fluxmapreader.h"
|
||||||
#include "lib/a2r.h"
|
#include "lib/a2r.h"
|
||||||
|
|
||||||
static uint32_t a2r_to_ticks(uint32_t a2rticks)
|
static double a2r_to_ticks(double a2rticks)
|
||||||
{
|
{
|
||||||
return a2rticks * A2R_NS_PER_TICK / NS_PER_TICK;
|
return a2rticks * A2R_NS_PER_TICK / NS_PER_TICK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double ticks_to_a2r(double flticks)
|
||||||
|
{
|
||||||
|
return flticks * NS_PER_TICK / A2R_NS_PER_TICK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bytes fluxEngineToApplesauce(const Bytes& fldata)
|
||||||
|
{
|
||||||
|
Fluxmap fluxmap(fldata);
|
||||||
|
FluxmapReader fmr(fluxmap);
|
||||||
|
Bytes asdata;
|
||||||
|
ByteWriter bw(asdata);
|
||||||
|
|
||||||
|
while (!fmr.eof())
|
||||||
|
{
|
||||||
|
unsigned ticks;
|
||||||
|
if (!fmr.findEvent(F_BIT_PULSE, ticks))
|
||||||
|
break;
|
||||||
|
|
||||||
|
uint32_t applesauceTicks = ticks_to_a2r(ticks);
|
||||||
|
while (applesauceTicks >= 255)
|
||||||
|
{
|
||||||
|
bw.write_8(255);
|
||||||
|
applesauceTicks -= 255;
|
||||||
|
}
|
||||||
|
bw.write_8(applesauceTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
return asdata;
|
||||||
|
}
|
||||||
|
|
||||||
Bytes applesauceToFluxEngine(const Bytes& asdata)
|
Bytes applesauceToFluxEngine(const Bytes& asdata)
|
||||||
{
|
{
|
||||||
ByteReader br(asdata);
|
ByteReader br(asdata);
|
||||||
|
|||||||
@@ -6,3 +6,4 @@
|
|||||||
#define APPLESAUCE_ID ((APPLESAUCE_VID << 16) | APPLESAUCE_PID)
|
#define APPLESAUCE_ID ((APPLESAUCE_VID << 16) | APPLESAUCE_PID)
|
||||||
|
|
||||||
extern Bytes applesauceToFluxEngine(const Bytes& asdata);
|
extern Bytes applesauceToFluxEngine(const Bytes& asdata);
|
||||||
|
extern Bytes fluxEngineToApplesauce(const Bytes& fldata);
|
||||||
|
|||||||
@@ -43,26 +43,33 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::string sendrecv(const std::string& command)
|
std::string sendrecv(const std::string& command)
|
||||||
{
|
{
|
||||||
fmt::print(fmt::format("> {}\n", command));
|
if (_config.verbose())
|
||||||
|
fmt::print(fmt::format("> {}\n", command));
|
||||||
_serial->writeLine(command);
|
_serial->writeLine(command);
|
||||||
auto r = _serial->readLine();
|
auto r = _serial->readLine();
|
||||||
fmt::print(fmt::format("< {}\n", r));
|
if (_config.verbose())
|
||||||
|
fmt::print(fmt::format("< {}\n", r));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool doCommand(const std::string& command)
|
void checkCommandResult(const std::string& result)
|
||||||
{
|
{
|
||||||
return sendrecv(command) == ".";
|
if (result != ".")
|
||||||
|
throw ApplesauceException(
|
||||||
|
fmt::format("low-level Applesauce error: '{}'", result));
|
||||||
|
}
|
||||||
|
|
||||||
|
void doCommand(const std::string& command)
|
||||||
|
{
|
||||||
|
checkCommandResult(sendrecv(command));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string doCommandX(const std::string& command)
|
std::string doCommandX(const std::string& command)
|
||||||
{
|
{
|
||||||
std::string r = sendrecv(command);
|
doCommand(command);
|
||||||
if (r != ".")
|
std::string r = _serial->readLine();
|
||||||
throw ApplesauceException(
|
if (_config.verbose())
|
||||||
fmt::format("low-level Applesauce error: '{}'", r));
|
fmt::print(fmt::format("<< {}\n", r));
|
||||||
r = _serial->readLine();
|
|
||||||
fmt::print(fmt::format("<< {}\n", r));
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,11 +77,18 @@ private:
|
|||||||
{
|
{
|
||||||
if (!_connected)
|
if (!_connected)
|
||||||
{
|
{
|
||||||
if (!doCommand("connect"))
|
try
|
||||||
error("Applesauce could not find any drives");
|
{
|
||||||
doCommand("drive:enable");
|
doCommand("connect");
|
||||||
doCommand("motor:on");
|
doCommand("drive:enable");
|
||||||
_connected = true;
|
doCommand("motor:on");
|
||||||
|
doCommand("head:zero");
|
||||||
|
_connected = true;
|
||||||
|
}
|
||||||
|
catch (const ApplesauceException& e)
|
||||||
|
{
|
||||||
|
error("Applesauce could not connect to a drive");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,10 +109,12 @@ public:
|
|||||||
connect();
|
connect();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
double rpm = std::stod(doCommandX("sync:?speed")) / 1000.0;
|
double period_us = std::stod(doCommandX("sync:?speed"));
|
||||||
sendrecv("X");
|
_serial->writeByte('X');
|
||||||
fmt::print("< {}\n", _serial->readLine());
|
std::string r = _serial->readLine();
|
||||||
return 60e9 / rpm;
|
if (_config.verbose())
|
||||||
|
fmt::print("<< {}\n", r);
|
||||||
|
return period_us * 1e3;
|
||||||
}
|
}
|
||||||
catch (const ApplesauceException& e)
|
catch (const ApplesauceException& e)
|
||||||
{
|
{
|
||||||
@@ -111,8 +127,7 @@ public:
|
|||||||
int max = std::stoi(sendrecv("data:?max"));
|
int max = std::stoi(sendrecv("data:?max"));
|
||||||
fmt::print("Writing data: ");
|
fmt::print("Writing data: ");
|
||||||
|
|
||||||
if (!doCommand(fmt::format("data:>{}", max)))
|
doCommand(fmt::format("data:>{}", max));
|
||||||
error("Cannot write to Applesauce");
|
|
||||||
|
|
||||||
Bytes junk(max);
|
Bytes junk(max);
|
||||||
uint32_t seed = 0;
|
uint32_t seed = 0;
|
||||||
@@ -138,8 +153,7 @@ public:
|
|||||||
int max = std::stoi(sendrecv("data:?max"));
|
int max = std::stoi(sendrecv("data:?max"));
|
||||||
fmt::print("Reading data: ");
|
fmt::print("Reading data: ");
|
||||||
|
|
||||||
if (!doCommand(fmt::format("data:<{}", max)))
|
doCommand(fmt::format("data:<{}", max));
|
||||||
error("Cannot read from Applesauce");
|
|
||||||
|
|
||||||
double start_time = getCurrentTime();
|
double start_time = getCurrentTime();
|
||||||
_serial->readBytes(max);
|
_serial->readBytes(max);
|
||||||
@@ -161,7 +175,7 @@ public:
|
|||||||
error("hard sectors are currently unsupported on the Applesauce");
|
error("hard sectors are currently unsupported on the Applesauce");
|
||||||
|
|
||||||
connect();
|
connect();
|
||||||
doCommand(fmt::format("disk:side{}", side));
|
doCommand(fmt::format("head:side{}", side));
|
||||||
doCommand(synced ? "sync:on" : "sync:off");
|
doCommand(synced ? "sync:on" : "sync:off");
|
||||||
doCommand("data:clear");
|
doCommand("data:clear");
|
||||||
doCommandX("disk:read");
|
doCommandX("disk:read");
|
||||||
@@ -180,7 +194,25 @@ public:
|
|||||||
{
|
{
|
||||||
if (hardSectorThreshold != 0)
|
if (hardSectorThreshold != 0)
|
||||||
error("hard sectors are currently unsupported on the Applesauce");
|
error("hard sectors are currently unsupported on the Applesauce");
|
||||||
error("unsupported operation write on the Greaseweazle");
|
|
||||||
|
if (sendrecv("disk:?write") == "-")
|
||||||
|
error("cannot write --- disk is write protected");
|
||||||
|
if (sendrecv("?safe") == "+")
|
||||||
|
error("cannot write --- Applesauce 'safe' switch is on");
|
||||||
|
|
||||||
|
connect();
|
||||||
|
doCommand(fmt::format("head:side{}", side));
|
||||||
|
doCommand("sync:on");
|
||||||
|
doCommand("data:clear");
|
||||||
|
|
||||||
|
Bytes asdata = fluxEngineToApplesauce(fldata);
|
||||||
|
doCommand(fmt::format("data:>{}", asdata.size()));
|
||||||
|
_serial->write(asdata);
|
||||||
|
checkCommandResult(_serial->readLine());
|
||||||
|
|
||||||
|
doCommand("disk:wclear");
|
||||||
|
doCommand("disk:wcmd");
|
||||||
|
doCommandX("disk:write");
|
||||||
}
|
}
|
||||||
|
|
||||||
void erase(int side, nanoseconds_t hardSectorThreshold) override
|
void erase(int side, nanoseconds_t hardSectorThreshold) override
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ message GreaseweazleProto {
|
|||||||
message ApplesauceProto {
|
message ApplesauceProto {
|
||||||
optional string port = 1
|
optional string port = 1
|
||||||
[(help) = "Applesauce serial port to use"];
|
[(help) = "Applesauce serial port to use"];
|
||||||
|
optional bool verbose = 2
|
||||||
|
[(help) = "Enable verbose protocol logging", default = false];
|
||||||
}
|
}
|
||||||
|
|
||||||
message UsbProto {
|
message UsbProto {
|
||||||
|
|||||||
74
tests/applesauce.cc
Normal file
74
tests/applesauce.cc
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "lib/globals.h"
|
||||||
|
#include "lib/fluxmap.h"
|
||||||
|
#include "lib/usb/applesauce.h"
|
||||||
|
|
||||||
|
static void test_convert(const Bytes& asbytes, const Bytes& flbytes)
|
||||||
|
{
|
||||||
|
Bytes astoflbytes = applesauceToFluxEngine(asbytes);
|
||||||
|
Bytes fltoasbytes = fluxEngineToApplesauce(flbytes);
|
||||||
|
|
||||||
|
if (astoflbytes != flbytes)
|
||||||
|
{
|
||||||
|
std::cout << "Applesauce to FluxEngine conversion failed.\n";
|
||||||
|
std::cout << "Applesauce bytes:" << std::endl;
|
||||||
|
hexdump(std::cout, asbytes);
|
||||||
|
std::cout << std::endl << "Produced this:" << std::endl;
|
||||||
|
hexdump(std::cout, astoflbytes);
|
||||||
|
std::cout << std::endl << "Expected this:" << std::endl;
|
||||||
|
hexdump(std::cout, flbytes);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fltoasbytes != asbytes)
|
||||||
|
{
|
||||||
|
std::cout << "FluxEngine to Applesauce conversion failed.\n";
|
||||||
|
std::cout << "FluxEngine bytes:" << std::endl;
|
||||||
|
hexdump(std::cout, flbytes);
|
||||||
|
std::cout << std::endl << "Produced this:" << std::endl;
|
||||||
|
hexdump(std::cout, fltoasbytes);
|
||||||
|
std::cout << std::endl << "Expected this:" << std::endl;
|
||||||
|
hexdump(std::cout, asbytes);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_conversions()
|
||||||
|
{
|
||||||
|
/* Simple one-byte intervals. */
|
||||||
|
|
||||||
|
test_convert(Bytes{0x20, 0x20, 0x20, 0x20}, Bytes{0xb0, 0xb0, 0xb0, 0xb0});
|
||||||
|
|
||||||
|
/* Long, multibyte intervals. */
|
||||||
|
|
||||||
|
test_convert(Bytes{0xff, 0x1f, 0x20, 0xff, 0xff, 0x20},
|
||||||
|
Bytes{0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0xb3,
|
||||||
|
0xb0,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0x3f,
|
||||||
|
0xb9});
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[])
|
||||||
|
{
|
||||||
|
test_conversions();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ tests = [
|
|||||||
"agg",
|
"agg",
|
||||||
"amiga",
|
"amiga",
|
||||||
"applesingle",
|
"applesingle",
|
||||||
|
"applesauce",
|
||||||
"bitaccumulator",
|
"bitaccumulator",
|
||||||
"bytes",
|
"bytes",
|
||||||
"compression",
|
"compression",
|
||||||
|
|||||||
Reference in New Issue
Block a user