Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add formats for the Kaypro II. #318

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
PACKAGES = zlib sqlite3 libusb-1.0 protobuf

export CFLAGS = -x c++ --std=c++2a -ffunction-sections -fdata-sections
export CFLAGS = -x c++ --std=c++14 -ffunction-sections -fdata-sections
export LDFLAGS = -pthread

export COPTFLAGS = -Os
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ people who've had it work).
| [Brother 120kB](doc/disk-brother.md) | 🦄 | 🦖 | |
| [Brother 240kB](doc/disk-brother.md) | 🦄 | 🦄 | |
| [Brother FB-100](doc/disk-fb100.md) | 🦖 | | Tandy Model 100, Husky Hunter, knitting machines |
| [Kaypro II](doc/disk-ibm.md) | 🦄 | 🦄 | |
| [Macintosh 800kB](doc/disk-macintosh.md) | 🦄 | 🦄 | and probably the 400kB too |
| [TRS-80](doc/disk-trs80.md) | 🦖 | 🦖* | a minor variation of the IBM scheme |
{: .datatable }
Expand Down
9 changes: 6 additions & 3 deletions arch/ibm/encoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class IbmEncoder : public AbstractEncoder
if (!trackdata.use_fm())
clockRateUs /= 2.0;
int bitsPerRevolution = (trackdata.track_length_ms() * 1000.0) / clockRateUs;
_bits.resize(bitsPerRevolution);
_bits.resize(bitsPerRevolution*2);
_cursor = 0;

uint8_t idamUnencoded = decodeUint16(trackdata.idam_byte());
Expand Down Expand Up @@ -261,12 +261,15 @@ class IbmEncoder : public AbstractEncoder
}
}

if (_cursor >= _bits.size())
Error() << "track data overrun";
if (_cursor >= bitsPerRevolution)
Error() << fmt::format("track data overrun by {} bits ({:.3} ms)",
_cursor - bitsPerRevolution,
(_cursor - bitsPerRevolution) / (clockRateUs*1000.0));
while (_cursor < _bits.size())
writeFillerBytes(1, gapFill);

std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
_bits.resize(bitsPerRevolution);
fluxmap->appendBits(_bits, clockRateUs*1e3);
return fluxmap;
}
Expand Down
1 change: 1 addition & 0 deletions doc/disk-ibm.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ metadata. Systems which use IBM scheme disks include but are not limited to:
- the TRS-80
- late era Commodore machines (the 1571 and so on)
- most CP/M machines
- the Kaypro II
- etc

FluxEngine supports reading these. However, some variants are more peculiar
Expand Down
14 changes: 7 additions & 7 deletions lib/imagereader/diskcopyimagereader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,13 @@ class DiskCopyImageReader : public ImageReader
}
}

image.setGeometry({
.numTracks = numCylinders,
.numSides = numHeads,
.numSectors = 12,
.sectorSize = 512 + 12,
.irregular = true
});
Geometry g;
g.numTracks = numCylinders;
g.numSides = numHeads;
g.numSectors = 12;
g.sectorSize = 512 + 12;
g.irregular = true;
image.setGeometry(g);
return image;
}
};
Expand Down
12 changes: 6 additions & 6 deletions lib/imagereader/imdimagereader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,12 @@ class IMDImageReader : public ImageReader
}
//Write format detected in IMD image to screen to help user set the right write parameters

image.setGeometry({
.numTracks = header.track,
.numSides = header.Head + 1U,
.numSectors = header.numSectors,
.sectorSize = sectorSize
});
Geometry g;
g.numTracks = header.track;
g.numSides = header.Head + 1U;
g.numSectors = header.numSectors;
g.sectorSize = sectorSize;
image.setGeometry(g);

size_t headSize = header.numSectors * sectorSize;
size_t trackSize = headSize * (header.Head + 1);
Expand Down
12 changes: 6 additions & 6 deletions lib/imagereader/nsiimagereader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,12 @@ class NsiImageReader : public ImageReader
}
}

image.setGeometry({
.numTracks = numCylinders,
.numSides = numHeads,
.numSectors = numSectors,
.sectorSize = sectorSize
});
Geometry g;
g.numTracks = numCylinders;
g.numSides = numHeads;
g.numSectors = numSectors;
g.sectorSize = sectorSize;
image.setGeometry(g);
return image;
}
};
Expand Down
78 changes: 42 additions & 36 deletions lib/usb/fluxengineusb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -120,37 +120,39 @@ class FluxEngineUsb : public USB
public:
int getVersion()
{
struct any_frame f = { .f = {.type = F_FRAME_GET_VERSION_CMD, .size = sizeof(f)} };
struct any_frame f;
f.f.type = F_FRAME_GET_VERSION_CMD;
f.f.size = sizeof(f);
usb_cmd_send(&f, f.f.size);
auto r = await_reply<struct version_frame>(F_FRAME_GET_VERSION_REPLY);
return r->version;
}

void seek(int track)
{
struct seek_frame f = {
.f = { .type = F_FRAME_SEEK_CMD, .size = sizeof(f) },
.track = (uint8_t) track
};
struct seek_frame f;
f.f.type = F_FRAME_SEEK_CMD;
f.f.size = sizeof(f);
f.track = (uint8_t) track;
usb_cmd_send(&f, f.f.size);
await_reply<struct any_frame>(F_FRAME_SEEK_REPLY);
}

void recalibrate()
{
struct any_frame f = {
.f = { .type = F_FRAME_RECALIBRATE_CMD, .size = sizeof(f) },
};
struct any_frame f;
f.f.type = F_FRAME_RECALIBRATE_CMD;
f.f.size = sizeof(f);
usb_cmd_send(&f, f.f.size);
await_reply<struct any_frame>(F_FRAME_RECALIBRATE_REPLY);
}

nanoseconds_t getRotationalPeriod(int hardSectorCount)
{
struct measurespeed_frame f = {
.f = {.type = F_FRAME_MEASURE_SPEED_CMD, .size = sizeof(f)},
.hard_sector_count = (uint8_t) hardSectorCount,
};
struct measurespeed_frame f;
f.f.type = F_FRAME_MEASURE_SPEED_CMD;
f.f.size = sizeof(f);
f.hard_sector_count = (uint8_t) hardSectorCount;
usb_cmd_send(&f, f.f.size);

auto r = await_reply<struct speed_frame>(F_FRAME_MEASURE_SPEED_REPLY);
Expand All @@ -159,7 +161,9 @@ class FluxEngineUsb : public USB

void testBulkWrite()
{
struct any_frame f = { .f = {.type = F_FRAME_BULK_WRITE_TEST_CMD, .size = sizeof(f)} };
struct any_frame f;
f.f.type = F_FRAME_BULK_WRITE_TEST_CMD;
f.f.size = sizeof(f);
usb_cmd_send(&f, f.f.size);

/* These must match the device. */
Expand Down Expand Up @@ -198,7 +202,9 @@ class FluxEngineUsb : public USB

void testBulkRead()
{
struct any_frame f = { .f = {.type = F_FRAME_BULK_READ_TEST_CMD, .size = sizeof(f)} };
struct any_frame f;
f.f.type = F_FRAME_BULK_READ_TEST_CMD;
f.f.size = sizeof(f);
usb_cmd_send(&f, f.f.size);

/* These must match the device. */
Expand Down Expand Up @@ -234,11 +240,11 @@ class FluxEngineUsb : public USB
Bytes read(int side, bool synced, nanoseconds_t readTime,
nanoseconds_t hardSectorThreshold)
{
struct read_frame f = {
.f = { .type = F_FRAME_READ_CMD, .size = sizeof(f) },
.side = (uint8_t) side,
.synced = (uint8_t) synced,
};
struct read_frame f;
f.f.type = F_FRAME_READ_CMD;
f.f.size = sizeof(f);
f.side = (uint8_t) side;
f.synced = (uint8_t) synced;
f.hardsec_threshold_ms = (hardSectorThreshold + 5e5) / 1e6; /* round to nearest ms */
uint16_t milliseconds = readTime / 1e6;
((uint8_t*)&f.milliseconds)[0] = milliseconds;
Expand All @@ -260,10 +266,10 @@ class FluxEngineUsb : public USB
unsigned safelen = bytes.size() & ~(FRAME_SIZE-1);
Bytes safeBytes = bytes.slice(0, safelen);

struct write_frame f = {
.f = { .type = F_FRAME_WRITE_CMD, .size = sizeof(f) },
.side = (uint8_t) side,
};
struct write_frame f;
f.f.type = F_FRAME_WRITE_CMD;
f.f.size = sizeof(f);
f.side = (uint8_t) side;
f.hardsec_threshold_ms = (hardSectorThreshold + 5e5) / 1e6; /* round to nearest ms */
((uint8_t*)&f.bytes_to_write)[0] = safelen;
((uint8_t*)&f.bytes_to_write)[1] = safelen >> 8;
Expand All @@ -278,10 +284,10 @@ class FluxEngineUsb : public USB

void erase(int side, nanoseconds_t hardSectorThreshold)
{
struct erase_frame f = {
.f = { .type = F_FRAME_ERASE_CMD, .size = sizeof(f) },
.side = (uint8_t) side,
};
struct erase_frame f;
f.f.type = F_FRAME_ERASE_CMD;
f.f.size = sizeof(f);
f.side = (uint8_t) side;
f.hardsec_threshold_ms = (hardSectorThreshold + 5e5) / 1e6; /* round to nearest ms */
usb_cmd_send(&f, f.f.size);

Expand All @@ -290,21 +296,21 @@ class FluxEngineUsb : public USB

void setDrive(int drive, bool high_density, int index_mode)
{
struct set_drive_frame f = {
.f = { .type = F_FRAME_SET_DRIVE_CMD, .size = sizeof(f) },
.drive = (uint8_t) drive,
.high_density = high_density,
.index_mode = (uint8_t) index_mode
};
struct set_drive_frame f;
f.f.type = F_FRAME_SET_DRIVE_CMD;
f.f.size = sizeof(f);
f.drive = (uint8_t) drive;
f.high_density = high_density;
f.index_mode = (uint8_t) index_mode;
usb_cmd_send(&f, f.f.size);
await_reply<struct any_frame>(F_FRAME_SET_DRIVE_REPLY);
}

void measureVoltages(struct voltages_frame* voltages)
{
struct any_frame f = {
{ .type = F_FRAME_MEASURE_VOLTAGES_CMD, .size = sizeof(f) },
};
struct any_frame f;
f.f.type = F_FRAME_MEASURE_VOLTAGES_CMD;
f.f.size = sizeof(f);
usb_cmd_send(&f, f.f.size);

auto convert_voltages_from_usb = [&](const struct voltages& vin, struct voltages& vout)
Expand Down
2 changes: 2 additions & 0 deletions mkninja.sh
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ FORMATS="\
ibm360_525 \
ibm720 \
ibm720_525 \
kaypro2 \
mac400 \
mac800 \
micropolis \
Expand Down Expand Up @@ -523,6 +524,7 @@ encodedecodetest ibm180_525
encodedecodetest ibm360_525
encodedecodetest ibm720
encodedecodetest ibm720_525
encodedecodetest kaypro2
encodedecodetest tids990
encodedecodetest commodore1581
encodedecodetest commodore1541 scripts/commodore1541_test.textpb
Expand Down
73 changes: 73 additions & 0 deletions src/formats/kaypro2.textpb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
comment: 'Kaypro II 5.25" 40-track 10-sector SSDD'

image_reader {
filename: "kaypro2.img"
img {
trackdata {
sector_size: 512
sector_range {
start_sector: 0
sector_count: 10
}
}
tracks: 40
sides: 1
physical_step: 1
}
}

image_writer {
filename: "kaypro2.img"
img {
trackdata {
sector_size: 512
sector_range {
start_sector: 0
sector_count: 10
}
}
tracks: 40
sides: 1
physical_step: 1
}
}

encoder {
ibm {
trackdata {
emit_iam: false
track_length_ms: 167
clock_rate_khz: 300
sectors {
sector: 0
sector: 1
sector: 2
sector: 3
sector: 4
sector: 5
sector: 6
sector: 7
sector: 8
sector: 9
}
gap0: 80
gap2: 22
gap3: 44
}
}
}

decoder {
ibm {}
}

cylinders {
start: 0
end: 39
}

heads {
start: 0
end: 0
}