Skip to content

Commit

Permalink
Reads mostly work; writes not yet.
Browse files Browse the repository at this point in the history
  • Loading branch information
davidgiven committed Sep 29, 2024
1 parent 6b28f36 commit 38b8cd2
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 29 deletions.
1 change: 1 addition & 0 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@
"lib/proto.h": "./lib/proto.h",
"lib/readerwriter.h": "./lib/readerwriter.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/usb.h": "./lib/usb/usb.h",
"lib/usb/usbfinder.h": "./lib/usb/usbfinder.h",
Expand Down
6 changes: 3 additions & 3 deletions lib/decoders/fluxmapreader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ bool FluxmapReader::findEvent(int event, unsigned& ticks)
{
ticks = 0;

for (;;)
while (!eof())
{
unsigned thisTicks;
int thisEvent;
Expand All @@ -57,11 +57,11 @@ bool FluxmapReader::findEvent(int event, unsigned& ticks)
if (thisEvent == F_EOF)
return false;

if (eof())
return false;
if ((event == thisEvent) || (event & thisEvent))
return true;
}

return false;
}

unsigned FluxmapReader::readInterval(nanoseconds_t clock)
Expand Down
33 changes: 32 additions & 1 deletion lib/usb/applesauce.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,44 @@
#include "lib/bytes.h"
#include "greaseweazle.h"
#include "lib/fluxmap.h"
#include "lib/decoders/fluxmapreader.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;
}

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)
{
ByteReader br(asdata);
Expand Down
1 change: 1 addition & 0 deletions lib/usb/applesauce.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
#define APPLESAUCE_ID ((APPLESAUCE_VID << 16) | APPLESAUCE_PID)

extern Bytes applesauceToFluxEngine(const Bytes& asdata);
extern Bytes fluxEngineToApplesauce(const Bytes& fldata);
82 changes: 57 additions & 25 deletions lib/usb/applesauceusb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,38 +43,52 @@ class ApplesauceUsb : public USB
private:
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);
auto r = _serial->readLine();
fmt::print(fmt::format("< {}\n", r));
if (_config.verbose())
fmt::print(fmt::format("< {}\n", 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 r = sendrecv(command);
if (r != ".")
throw ApplesauceException(
fmt::format("low-level Applesauce error: '{}'", r));
r = _serial->readLine();
fmt::print(fmt::format("<< {}\n", r));
doCommand(command);
std::string r = _serial->readLine();
if (_config.verbose())
fmt::print(fmt::format("<< {}\n", r));
return r;
}

void connect()
{
if (!_connected)
{
if (!doCommand("connect"))
error("Applesauce could not find any drives");
doCommand("drive:enable");
doCommand("motor:on");
_connected = true;
try
{
doCommand("connect");
doCommand("drive:enable");
doCommand("motor:on");
doCommand("head:zero");
_connected = true;
}
catch (const ApplesauceException& e)
{
error("Applesauce could not connect to a drive");
}
}
}

Expand All @@ -95,10 +109,12 @@ class ApplesauceUsb : public USB
connect();
try
{
double rpm = std::stod(doCommandX("sync:?speed")) / 1000.0;
sendrecv("X");
fmt::print("< {}\n", _serial->readLine());
return 60e9 / rpm;
double period_us = std::stod(doCommandX("sync:?speed"));
_serial->writeByte('X');
std::string r = _serial->readLine();
if (_config.verbose())
fmt::print("<< {}\n", r);
return period_us * 1e3;
}
catch (const ApplesauceException& e)
{
Expand All @@ -111,8 +127,7 @@ class ApplesauceUsb : public USB
int max = std::stoi(sendrecv("data:?max"));
fmt::print("Writing data: ");

if (!doCommand(fmt::format("data:>{}", max)))
error("Cannot write to Applesauce");
doCommand(fmt::format("data:>{}", max));

Bytes junk(max);
uint32_t seed = 0;
Expand All @@ -138,8 +153,7 @@ class ApplesauceUsb : public USB
int max = std::stoi(sendrecv("data:?max"));
fmt::print("Reading data: ");

if (!doCommand(fmt::format("data:<{}", max)))
error("Cannot read from Applesauce");
doCommand(fmt::format("data:<{}", max));

double start_time = getCurrentTime();
_serial->readBytes(max);
Expand All @@ -161,7 +175,7 @@ class ApplesauceUsb : public USB
error("hard sectors are currently unsupported on the Applesauce");

connect();
doCommand(fmt::format("disk:side{}", side));
doCommand(fmt::format("head:side{}", side));
doCommand(synced ? "sync:on" : "sync:off");
doCommand("data:clear");
doCommandX("disk:read");
Expand All @@ -180,7 +194,25 @@ class ApplesauceUsb : public USB
{
if (hardSectorThreshold != 0)
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
Expand Down
2 changes: 2 additions & 0 deletions lib/usb/usb.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ message GreaseweazleProto {
message ApplesauceProto {
optional string port = 1
[(help) = "Applesauce serial port to use"];
optional bool verbose = 2
[(help) = "Enable verbose protocol logging", default = false];
}

message UsbProto {
Expand Down
74 changes: 74 additions & 0 deletions tests/applesauce.cc
Original file line number Diff line number Diff line change
@@ -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;
}
1 change: 1 addition & 0 deletions tests/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"agg",
"amiga",
"applesingle",
"applesauce",
"bitaccumulator",
"bytes",
"compression",
Expand Down

0 comments on commit 38b8cd2

Please sign in to comment.