Compare commits

..

9 Commits

Author SHA1 Message Date
David Given
e0256adf77 Merge pull request #83 from davidgiven/write
Write code refactoring.
2019-08-06 22:24:40 +02:00
David Given
5748f017dd Refactor the write code to make it easier to add new encoders. 2019-08-06 22:17:58 +02:00
David Given
973f4c2c2d Skeleton work to factor out the encoder logic. 2019-08-03 22:30:30 +02:00
David Given
8e1774c69f Show the clock rate in kHz as well, because that's more useful. 2019-07-12 23:09:50 +02:00
David Given
56a36072f7 Sampler state machine cleanup; more debugging tools for the logic analyser. 2019-07-12 21:09:53 +02:00
David Given
8755d108ed Sanity check Mac sectors --- reject anything with an out-of-bounds sector ID. 2019-07-11 23:16:02 +02:00
David Given
ea40cd73d1 Merge pull request #78 from davidgiven/mx
Bugfixing and documentation for MX disks.
2019-07-11 22:02:24 +02:00
David Given
0e28899b72 Add the page on the MX disk format. Mac disks are now unicorns. 2019-07-11 21:34:01 +02:00
David Given
eee30db981 Honour the logical track numbering in MX disks (allows reading 40-track disks). 2019-07-11 21:03:54 +02:00
21 changed files with 256 additions and 102 deletions

View File

@@ -2310,13 +2310,13 @@
<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="DEBUG_PINS" persistent="">
<Hidden v="True" />
<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="DEBUG_PINS_aliases.h" persistent="Generated_Source\PSoC5\DEBUG_PINS_aliases.h">
<Hidden v="True" />
<Hidden v="False" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="HEADER;;;;" />
<PropertyDeltas />
@@ -3249,6 +3249,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="CAPTURE_CONTROL" 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="CAPTURE_CONTROL.h" persistent="Generated_Source\PSoC5\CAPTURE_CONTROL.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="CAPTURE_CONTROL.c" persistent="Generated_Source\PSoC5\CAPTURE_CONTROL.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="CAPTURE_CONTROL_PM.c" persistent="Generated_Source\PSoC5\CAPTURE_CONTROL_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

Binary file not shown.

View File

@@ -306,6 +306,7 @@ static void cmd_read(struct read_frame* f)
dma_underrun = false;
int count = 0;
SAMPLER_CONTROL_Write(0); /* !reset */
CAPTURE_CONTROL_Write(1);
CyDmaChSetInitialTd(dma_channel, td[dma_writing_to_td]);
CyDmaClearPendingDrq(dma_channel);
CyDmaChEnable(dma_channel, 1);
@@ -364,7 +365,8 @@ static void cmd_read(struct read_frame* f)
}
dma_reading_from_td = NEXT_BUFFER(dma_reading_from_td);
}
abort:
abort:;
CAPTURE_CONTROL_Write(0);
CyDmaChSetRequest(dma_channel, CY_DMA_CPU_TERM_CHAIN);
while (CyDmaChGetRequest(dma_channel))
;

View File

@@ -89,7 +89,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 |
| [Macintosh 800kB](doc/disk-macintosh.md) | 🦖 | | and probably the 400kB too |
| [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 }
@@ -105,6 +105,7 @@ at least, check the CRC so what data's there is probably good.
|:-----------------------------------------|:-----:|:------:|-------|
| [AES Superplus / No Problem](doc/disk-aeslanier.md) | 🦖 | | hard sectors! |
| [Durango F85](doc/disk-durangof85.md) | 🦖 | | 5.25" |
| [DVK MX](doc/disk-mx.md) | 🦖 | | Soviet PDP-11 clone |
| [Victor 9000](doc/disk-victor9k.md) | 🦖 | | 8-inch |
| [Zilog MCZ](doc/disk-zilogmcz.md) | 🦖 | | 8-inch _and_ hard sectors |
{: .datatable }
@@ -189,7 +190,7 @@ Jonathan Müller (`foonathan <https://github.com/foonathan>`) with
contributions from many other people. It is licensed under the terms of the
BSD license. Please see the contents of the directory for the full text.
As an exception, `dep/fnmatchemu` contains parts of the OpenBSD C library
As an exception, `dep/emu` contains parts of the OpenBSD C library
code, Todd Miller and William A. Rowe (and probably others). It is licensed
under the terms of the 3-clause BSD license. Please see the contents of the
directory for the full text. It's been lightly modified by me.

65
doc/disk-mx.md Normal file
View File

@@ -0,0 +1,65 @@
Disk: DVK MX
============
The DVK (in Russian, ДВК, Диалоговый вычислительный комплекс or Dialogue
Computing Complex) was a late 1970s Soviet personal computer, a cut-down
version of the professional SM EVM (СМ ЭВМ, abbreviation of Система Малых ЭВМ
--- literally System of Mini Computers), which _itself_ was an unlicensed
clone of the PDP-11. The MX board was an early floppy drive controller board
for it.
<div style="text-align: center">
<a href="http://www.leningrad.su/museum/show_big.php?n=1006"><img src="dvk3m.jpg" style="max-width: 60%" alt="A Durango F85, held precariously"></a>
</div>
The MX format is interesting in that it has to be read a track at a time. The
format contains the usual ID prologue at the beginning of the track, then
eleven data blocks and checksums, then the epilogue, then it stops. The
actual encoding is normal FM. There were four different disk variants, in all
combinations of single- and double-sided and 40- and 80-tracked; but every
track contained eleven 256-byte sectors.
The format varies subtly depending on whether you're using the 'new' driver
or the 'old' driver. FluxEngine should read both.
A track is:
* 8 x 0x0000 words (FM encoded as 01010101...)
* 1 x 0x00F3 --- start of track
* 1 x 0xnnnn --- track number
* 11 of:
* 128 words (256 bytes) of data
* 16 bit checksum
* **if 'new' format:**
* 3 x 0x83nn --- `n = (track_number<<1) + side_number`
* **if 'old' format:**
* 3 x 0x8301
The checksum is just the unsigned integer sum of all the words in the sector.
Words are all stored little-endian.
Reading discs
-------------
```
fluxengine read mx
```
You should end up with an `mx.img` which will vary in length depending on the format. The default is double-sided 80-track. For the other formats, use:
* single-sided 40-track: `-s :s=0:t=0-79x2`
* double-sided 40-track: `-s :s=0-1:t=0-79x2`
* single-sided 40-track: `-s :s=0:t=0-79`
* double-sided 40-track: `-s :s=0-1:t=0-79`
Useful references
-----------------
- [The Soviet Digital Electronics
Museum](http://www.leningrad.su/museum/main.php) (source of the image
above)
- [a random post on the HxC2001 support
forum](http://torlus.com/floppy/forum/viewtopic.php?t=1384) with lots of
information on the format

BIN
doc/dvk3m.jpg Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

View File

@@ -9,6 +9,9 @@
#define BROTHER_DATA_RECORD_CHECKSUM 3
#define BROTHER_DATA_RECORD_ENCODED_SIZE 415
#define BROTHER_TRACKS_PER_DISK 78
#define BROTHER_SECTORS_PER_TRACK 12
class Sector;
class Fluxmap;
@@ -22,9 +25,15 @@ public:
void decodeDataRecord();
};
extern void writeBrotherSectorHeader(std::vector<bool>& bits, unsigned& cursor,
int track, int sector);
extern void writeBrotherSectorData(std::vector<bool>& bits, unsigned& cursor,
const Bytes& data);
class BrotherEncoder : public AbstractEncoder
{
public:
virtual ~BrotherEncoder() {}
public:
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors);
};
extern FlagGroup brotherEncoderFlags;
#endif

View File

@@ -3,6 +3,7 @@
#include "fluxmap.h"
#include "decoders/fluxmapreader.h"
#include "decoders/decoders.h"
#include "encoders/encoders.h"
#include "record.h"
#include "brother.h"
#include "sector.h"

View File

@@ -1,8 +1,38 @@
#include "globals.h"
#include "record.h"
#include "decoders/decoders.h"
#include "encoders/encoders.h"
#include "brother.h"
#include "crc.h"
#include "sectorset.h"
#include "writer.h"
FlagGroup brotherEncoderFlags;
static DoubleFlag clockRateUs(
{ "--clock-rate" },
"Encoded data clock rate (microseconds).",
3.83);
static DoubleFlag postIndexGapMs(
{ "--post-index-gap" },
"Post-index gap before first sector header (milliseconds).",
1.0);
static DoubleFlag sectorSpacingMs(
{ "--sector-spacing" },
"Time between successive sector headers (milliseconds).",
16.2);
static DoubleFlag postHeaderSpacingMs(
{ "--post-header-spacing" },
"Time between a sector's header and data records (milliseconds).",
0.69);
static StringFlag sectorSkew(
{ "--sector-skew" },
"Order in which to write sectors.",
"05a3816b4927");
static int encode_header_gcr(uint16_t word)
{
@@ -40,7 +70,7 @@ static void write_bits(std::vector<bool>& bits, unsigned& cursor, uint32_t data,
}
}
void writeBrotherSectorHeader(std::vector<bool>& bits, unsigned& cursor,
static void write_sector_header(std::vector<bool>& bits, unsigned& cursor,
int track, int sector)
{
write_bits(bits, cursor, 0xffffffff, 31);
@@ -50,7 +80,7 @@ void writeBrotherSectorHeader(std::vector<bool>& bits, unsigned& cursor,
write_bits(bits, cursor, encode_header_gcr(0x2f), 16);
}
void writeBrotherSectorData(std::vector<bool>& bits, unsigned& cursor, const Bytes& data)
static void write_sector_data(std::vector<bool>& bits, unsigned& cursor, const Bytes& data)
{
write_bits(bits, cursor, 0xffffffff, 32);
write_bits(bits, cursor, BROTHER_DATA_RECORD, 32);
@@ -89,4 +119,49 @@ void writeBrotherSectorData(std::vector<bool>& bits, unsigned& cursor, const Byt
write_byte(0);
}
static int charToInt(char c)
{
if (isdigit(c))
return c - '0';
return 10 + tolower(c) - 'a';
}
std::unique_ptr<Fluxmap> BrotherEncoder::encode(
int physicalTrack, int physicalSide, const SectorSet& allSectors)
{
if ((physicalTrack < 0) || (physicalTrack >= BROTHER_TRACKS_PER_DISK)
|| (physicalSide != 0))
return std::unique_ptr<Fluxmap>();
int bitsPerRevolution = 200000.0 / clockRateUs;
const std::string& skew = sectorSkew.get();
std::vector<bool> bits(bitsPerRevolution);
unsigned cursor = 0;
for (int sectorCount=0; sectorCount<BROTHER_SECTORS_PER_TRACK; sectorCount++)
{
int sectorId = charToInt(skew.at(sectorCount));
double headerMs = postIndexGapMs + sectorCount*sectorSpacingMs;
unsigned headerCursor = headerMs*1e3 / clockRateUs;
double dataMs = headerMs + postHeaderSpacingMs;
unsigned dataCursor = dataMs*1e3 / clockRateUs;
const auto& sectorData = allSectors.get(physicalTrack, 0, sectorId);
fillBitmapTo(bits, cursor, headerCursor, { true, false });
write_sector_header(bits, cursor, physicalTrack, sectorId);
fillBitmapTo(bits, cursor, dataCursor, { true, false });
write_sector_data(bits, cursor, sectorData->data);
}
if (cursor > bits.size())
Error() << "track data overrun";
fillBitmapTo(bits, cursor, bits.size(), { true, false });
// The pre-index gap is not normally reported.
// std::cerr << "pre-index gap " << 200.0 - (double)cursor*clockRateUs/1e3 << std::endl;
std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
fluxmap->appendBits(bits, clockRateUs*1e3);
return fluxmap;
}

View File

18
lib/encoders/encoders.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef ENCODERS_H
#define ENCODERS_H
class Fluxmap;
class SectorSet;
class AbstractEncoder
{
public:
virtual ~AbstractEncoder() {}
public:
virtual std::unique_ptr<Fluxmap> encode(
int physicalTrack, int physicalSide, const SectorSet& allSectors) = 0;
};
#endif

View File

@@ -153,6 +153,9 @@ void MacintoshDecoder::decodeSectorRecord()
uint8_t formatByte = decode_data_gcr(header[3]);
uint8_t wantedsum = decode_data_gcr(header[4]);
if (encodedSector > 11)
return;
_sector->logicalTrack = _track->physicalTrack;
_sector->logicalSide = decode_side(encodedSide);
_sector->logicalSector = encodedSector;

View File

@@ -37,7 +37,7 @@ AbstractDecoder::RecordType MxDecoder::advanceToNextRecord()
const FluxMatcher* matcher = nullptr;
_sector->clock = _clock = _fmr->seekToPattern(ID_PATTERN, matcher);
readRawBits(32); /* skip the ID mark */
readRawBits(32); /* skip the track number */
_logicalTrack = decodeFmMfm(readRawBits(32)).reader().read_be16();
}
else if (_currentSector == 10)
{
@@ -67,7 +67,7 @@ void MxDecoder::decodeSectorRecord()
gotChecksum += br.read_le16();
uint16_t wantChecksum = br.read_le16();
_sector->logicalTrack = _track->physicalTrack;
_sector->logicalTrack = _logicalTrack;
_sector->logicalSide = _track->physicalSide;
_sector->logicalSector = _currentSector;
_sector->data = bytes.slice(0, SECTOR_SIZE);

View File

@@ -15,6 +15,7 @@ public:
private:
nanoseconds_t _clock;
int _currentSector;
int _logicalTrack;
};
#endif

View File

@@ -160,8 +160,9 @@ void readDiskCommand(AbstractDecoder& decoder, const std::string& outputFilename
track->rawrecords.size(),
track->sectors.size());
if (track->sectors.size() > 0)
std::cout << fmt::format("{:.2f}us clock; ",
track->sectors.begin()->clock / 1000.0);
std::cout << fmt::format("{:.2f}us clock ({:.0f}kHz); ",
track->sectors.begin()->clock / 1000.0,
1000000.0 / track->sectors.begin()->clock);
for (auto& sector : track->sectors)
{

View File

@@ -6,9 +6,14 @@
#include "protocol.h"
#include "usb.h"
#include "dataspec.h"
#include "encoders/encoders.h"
#include "fluxsource/fluxsource.h"
#include "fluxsink/fluxsink.h"
#include "fmt/format.h"
#include "record.h"
#include "image.h"
#include "sector.h"
#include "sectorset.h"
FlagGroup writerFlags { &hardwareFluxSourceFlags };
@@ -60,10 +65,12 @@ void writeTracks(
{
if (!outdb)
{
std::cout << "erasing" << std::endl;
std::cout << "erasing\n";
usbSeek(location.track);
usbErase(location.side);
}
else
std::cout << "skipping\n";
}
else
{
@@ -96,3 +103,16 @@ void fillBitmapTo(std::vector<bool>& bitmap,
}
}
void writeDiskCommand(
AbstractEncoder& encoder, const Geometry& geometry, const std::string& inputFilename)
{
SectorSet allSectors;
readSectorsFromFile(allSectors, geometry, inputFilename);
writeTracks(
[&](int track, int side) -> std::unique_ptr<Fluxmap>
{
return encoder.encode(track, side, allSectors);
}
);
}

View File

@@ -6,6 +6,8 @@
extern FlagGroup writerFlags;
class Fluxmap;
class AbstractEncoder;
class Geometry;
extern void setWriterDefaultDest(const std::string& dest);
@@ -15,5 +17,7 @@ extern void fillBitmapTo(std::vector<bool>& bitmap,
unsigned& cursor, unsigned terminateAt,
const std::vector<bool>& pattern);
extern void writeDiskCommand(
AbstractEncoder& encoder, const Geometry& geometry, const std::string& inputFilename);
#endif

View File

@@ -150,7 +150,7 @@ buildlibrary libbackend.a \
lib/decoders/decoders.cc \
lib/decoders/fluxmapreader.cc \
lib/decoders/fmmfm.cc \
lib/encoder.cc \
lib/encoders/encoders.cc \
lib/f85/decoder.cc \
lib/fb100/decoder.cc \
lib/flags.cc \

View File

@@ -3,6 +3,7 @@
#include "reader.h"
#include "fluxmap.h"
#include "decoders/decoders.h"
#include "encoders/encoders.h"
#include "brother/brother.h"
#include "sector.h"
#include "sectorset.h"

View File

@@ -1,108 +1,28 @@
#include "globals.h"
#include "flags.h"
#include "fluxmap.h"
#include "sector.h"
#include "sectorset.h"
#include "decoders/decoders.h"
#include "encoders/encoders.h"
#include "brother/brother.h"
#include "image.h"
#include "writer.h"
#include "fmt/format.h"
#include "image.h"
#include <fstream>
#include <ctype.h>
static FlagGroup flags { &writerFlags };
static FlagGroup flags { &writerFlags, &brotherEncoderFlags };
static StringFlag inputFilename(
{ "--input", "-i" },
"The input image file to read from.",
"brother.img");
static DoubleFlag clockRateUs(
{ "--clock-rate" },
"Encoded data clock rate (microseconds).",
3.83);
static DoubleFlag postIndexGapMs(
{ "--post-index-gap" },
"Post-index gap before first sector header (milliseconds).",
1.0);
static DoubleFlag sectorSpacingMs(
{ "--sector-spacing" },
"Time between successive sector headers (milliseconds).",
16.2);
static DoubleFlag postHeaderSpacingMs(
{ "--post-header-spacing" },
"Time between a sector's header and data records (milliseconds).",
0.69);
static StringFlag sectorSkew(
{ "--sector-skew" },
"Order in which to write sectors.",
"05a3816b4927");
static int charToInt(char c)
{
if (isdigit(c))
return c - '0';
return 10 + tolower(c) - 'a';
}
int mainWriteBrother(int argc, const char* argv[])
{
setWriterDefaultDest(":d=0:t=0-77:s=0");
flags.parseFlags(argc, argv);
SectorSet allSectors;
BrotherEncoder encoder;
Geometry geometry = {78, 1, 12, 256};
readSectorsFromFile(allSectors, geometry, inputFilename);
int bitsPerRevolution = 200000.0 / clockRateUs;
std::cerr << bitsPerRevolution << " bits per 200ms revolution" << std::endl
<< fmt::format("post-index gap: {:.3f}ms\n", (double)postIndexGapMs);
const std::string& skew = sectorSkew;
writeTracks(
[&](int track, int side) -> std::unique_ptr<Fluxmap>
{
if ((track < 0) || (track > 77) || (side != 0))
return std::unique_ptr<Fluxmap>();
std::vector<bool> bits(bitsPerRevolution);
unsigned cursor = 0;
for (int sectorCount=0; sectorCount<geometry.sectors; sectorCount++)
{
int sectorId = charToInt(skew.at(sectorCount));
double headerMs = postIndexGapMs + sectorCount*sectorSpacingMs;
unsigned headerCursor = headerMs*1e3 / clockRateUs;
double dataMs = headerMs + postHeaderSpacingMs;
unsigned dataCursor = dataMs*1e3 / clockRateUs;
auto& sectorData = allSectors.get(track, 0, sectorId);
fillBitmapTo(bits, cursor, headerCursor, { true, false });
writeBrotherSectorHeader(bits, cursor, track, sectorId);
fillBitmapTo(bits, cursor, dataCursor, { true, false });
writeBrotherSectorData(bits, cursor, sectorData->data);
}
if (cursor > bits.size())
Error() << "track data overrun";
fillBitmapTo(bits, cursor, bits.size(), { true, false });
// The pre-index gap is not normally reported.
// std::cerr << "pre-index gap " << 200.0 - (double)cursor*clockRateUs/1e3 << std::endl;
std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
fluxmap->appendBits(bits, clockRateUs*1e3);
return fluxmap;
}
);
writeDiskCommand(encoder, geometry, inputFilename);
return 0;
}