mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-24 11:11:02 -07:00
Compare commits
1 Commits
5b7f9d84f9
...
hardsector
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f634988356 |
@@ -88,16 +88,6 @@ public:
|
||||
now = tell().ns();
|
||||
}
|
||||
|
||||
/* Discard a possible partial sector at the end of the track.
|
||||
* This partial sector could be mistaken for a conflicted sector, if
|
||||
* whatever data read happens to match the checksum of 0, which is
|
||||
* rare, but has been observed on some disks.
|
||||
*/
|
||||
if (now > (getFluxmapDuration() - 21e6)) {
|
||||
seekToIndexMark();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int msSinceIndex = std::round(now / 1e6);
|
||||
|
||||
/* Note that the seekToPattern ignores the sector pulses, so if
|
||||
@@ -108,11 +98,6 @@ public:
|
||||
nanoseconds_t clock = seekToPattern(ANY_SECTOR_PATTERN);
|
||||
_sector->headerStartTime = tell().ns();
|
||||
|
||||
/* Discard a possible partial sector. */
|
||||
if (_sector->headerStartTime > (getFluxmapDuration() - 21e6)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sectorFoundTimeRaw = std::round(_sector->headerStartTime / 1e6);
|
||||
int sectorFoundTime;
|
||||
|
||||
@@ -132,7 +117,16 @@ public:
|
||||
|
||||
void decodeSectorRecord() override
|
||||
{
|
||||
nanoseconds_t before = tell().ns();
|
||||
uint64_t id = toBytes(readRawBits(64)).reader().read_be64();
|
||||
nanoseconds_t after = tell().ns();
|
||||
|
||||
/* Discard any sectors which span the end of a revolution. This can sometimes
|
||||
* cause spurious bad sectors which can trigger conflicts. */
|
||||
|
||||
if (int(before / 200e9) != int(after / 200e9))
|
||||
return;
|
||||
|
||||
unsigned recordSize, payloadSize, headerSize;
|
||||
|
||||
if (id == MFM_ID) {
|
||||
|
||||
@@ -12,155 +12,165 @@
|
||||
#define GAP_FILL_SIZE_DD 62
|
||||
#define PRE_HEADER_GAP_FILL_SIZE_DD 16
|
||||
|
||||
#define GAP1_FILL_BYTE (0x4F)
|
||||
#define GAP2_FILL_BYTE (0x4F)
|
||||
#define GAP1_FILL_BYTE (0x4F)
|
||||
#define GAP2_FILL_BYTE (0x4F)
|
||||
|
||||
#define TOTAL_SECTOR_BYTES ()
|
||||
|
||||
static void write_sector(std::vector<bool>& bits, unsigned& cursor, const std::shared_ptr<const Sector>& sector)
|
||||
static void write_sector(std::vector<bool>& bits,
|
||||
unsigned& cursor,
|
||||
const std::shared_ptr<const Sector>& sector)
|
||||
{
|
||||
int preambleSize = 0;
|
||||
int encodedSectorSize = 0;
|
||||
int gapFillSize = 0;
|
||||
int preHeaderGapFillSize = 0;
|
||||
int preambleSize = 0;
|
||||
int encodedSectorSize = 0;
|
||||
int preHeaderGapFillSize = 0;
|
||||
|
||||
bool doubleDensity;
|
||||
bool doubleDensity;
|
||||
|
||||
switch (sector->data.size()) {
|
||||
case NORTHSTAR_PAYLOAD_SIZE_SD:
|
||||
preambleSize = NORTHSTAR_PREAMBLE_SIZE_SD;
|
||||
encodedSectorSize = PRE_HEADER_GAP_FILL_SIZE_SD + NORTHSTAR_ENCODED_SECTOR_SIZE_SD + GAP_FILL_SIZE_SD;
|
||||
gapFillSize = GAP_FILL_SIZE_SD;
|
||||
preHeaderGapFillSize = PRE_HEADER_GAP_FILL_SIZE_SD;
|
||||
doubleDensity = false;
|
||||
break;
|
||||
case NORTHSTAR_PAYLOAD_SIZE_DD:
|
||||
preambleSize = NORTHSTAR_PREAMBLE_SIZE_DD;
|
||||
encodedSectorSize = PRE_HEADER_GAP_FILL_SIZE_DD + NORTHSTAR_ENCODED_SECTOR_SIZE_DD + GAP_FILL_SIZE_DD;
|
||||
gapFillSize = GAP_FILL_SIZE_DD;
|
||||
preHeaderGapFillSize = PRE_HEADER_GAP_FILL_SIZE_DD;
|
||||
doubleDensity = true;
|
||||
break;
|
||||
default:
|
||||
Error() << "unsupported sector size --- you must pick 256 or 512";
|
||||
break;
|
||||
}
|
||||
switch (sector->data.size())
|
||||
{
|
||||
case NORTHSTAR_PAYLOAD_SIZE_SD:
|
||||
preambleSize = NORTHSTAR_PREAMBLE_SIZE_SD;
|
||||
encodedSectorSize = PRE_HEADER_GAP_FILL_SIZE_SD +
|
||||
NORTHSTAR_ENCODED_SECTOR_SIZE_SD;
|
||||
preHeaderGapFillSize = PRE_HEADER_GAP_FILL_SIZE_SD;
|
||||
doubleDensity = false;
|
||||
break;
|
||||
|
||||
int fullSectorSize = preambleSize + encodedSectorSize;
|
||||
auto fullSector = std::make_shared<std::vector<uint8_t>>();
|
||||
fullSector->reserve(fullSectorSize);
|
||||
case NORTHSTAR_PAYLOAD_SIZE_DD:
|
||||
preambleSize = NORTHSTAR_PREAMBLE_SIZE_DD;
|
||||
encodedSectorSize = PRE_HEADER_GAP_FILL_SIZE_DD +
|
||||
NORTHSTAR_ENCODED_SECTOR_SIZE_DD;
|
||||
preHeaderGapFillSize = PRE_HEADER_GAP_FILL_SIZE_DD;
|
||||
doubleDensity = true;
|
||||
break;
|
||||
|
||||
/* sector gap after index pulse */
|
||||
for (int i = 0; i < preHeaderGapFillSize; i++)
|
||||
fullSector->push_back(GAP1_FILL_BYTE);
|
||||
default:
|
||||
Error() << "unsupported sector size --- you must pick 256 or 512";
|
||||
break;
|
||||
}
|
||||
|
||||
/* sector preamble */
|
||||
for (int i = 0; i < preambleSize; i++)
|
||||
fullSector->push_back(0);
|
||||
int fullSectorSize = preambleSize + encodedSectorSize;
|
||||
auto fullSector = std::make_shared<std::vector<uint8_t>>();
|
||||
fullSector->reserve(fullSectorSize);
|
||||
|
||||
Bytes sectorData;
|
||||
if (sector->data.size() == encodedSectorSize)
|
||||
sectorData = sector->data;
|
||||
else {
|
||||
ByteWriter writer(sectorData);
|
||||
writer.write_8(0xFB); /* sync character */
|
||||
if (doubleDensity == true) {
|
||||
writer.write_8(0xFB); /* Double-density has two sync characters */
|
||||
}
|
||||
writer += sector->data;
|
||||
if (doubleDensity == true) {
|
||||
writer.write_8(northstarChecksum(sectorData.slice(2)));
|
||||
} else {
|
||||
writer.write_8(northstarChecksum(sectorData.slice(1)));
|
||||
}
|
||||
}
|
||||
for (uint8_t b : sectorData)
|
||||
fullSector->push_back(b);
|
||||
/* sector gap after index pulse */
|
||||
for (int i = 0; i < preHeaderGapFillSize; i++)
|
||||
fullSector->push_back(GAP1_FILL_BYTE);
|
||||
|
||||
if (sector->logicalSector != 9) {
|
||||
/* sector postamble */
|
||||
for (int i = 0; i < gapFillSize; i++)
|
||||
fullSector->push_back(GAP2_FILL_BYTE);
|
||||
/* sector preamble */
|
||||
for (int i = 0; i < preambleSize; i++)
|
||||
fullSector->push_back(0);
|
||||
|
||||
if (fullSector->size() != fullSectorSize)
|
||||
Error() << "sector mismatched length (" << sector->data.size() << ") expected: " << fullSector->size() << " got " << fullSectorSize;
|
||||
} else {
|
||||
/* sector postamble */
|
||||
for (int i = 0; i < gapFillSize; i++)
|
||||
fullSector->push_back(GAP2_FILL_BYTE);
|
||||
}
|
||||
Bytes sectorData;
|
||||
if (sector->data.size() == encodedSectorSize)
|
||||
sectorData = sector->data;
|
||||
else
|
||||
{
|
||||
ByteWriter writer(sectorData);
|
||||
writer.write_8(0xFB); /* sync character */
|
||||
if (doubleDensity == true)
|
||||
writer.write_8(0xFB); /* Double-density has two sync characters */
|
||||
|
||||
bool lastBit = false;
|
||||
writer += sector->data;
|
||||
if (doubleDensity == true)
|
||||
writer.write_8(northstarChecksum(sectorData.slice(2)));
|
||||
else
|
||||
writer.write_8(northstarChecksum(sectorData.slice(1)));
|
||||
}
|
||||
for (uint8_t b : sectorData)
|
||||
fullSector->push_back(b);
|
||||
|
||||
if (doubleDensity == true) {
|
||||
encodeMfm(bits, cursor, fullSector, lastBit);
|
||||
}
|
||||
else {
|
||||
encodeFm(bits, cursor, fullSector);
|
||||
}
|
||||
if (fullSector->size() != fullSectorSize)
|
||||
Error() << "sector mismatched length (" << sector->data.size()
|
||||
<< ") expected: " << fullSector->size() << " got "
|
||||
<< fullSectorSize;
|
||||
|
||||
/* A few bytes of sector postamble just so the blank skip area doesn't start
|
||||
* immediately after the data. */
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
fullSector->push_back(GAP2_FILL_BYTE);
|
||||
|
||||
bool lastBit = false;
|
||||
|
||||
if (doubleDensity == true)
|
||||
encodeMfm(bits, cursor, fullSector, lastBit);
|
||||
else
|
||||
encodeFm(bits, cursor, fullSector);
|
||||
}
|
||||
|
||||
class NorthstarEncoder : public AbstractEncoder
|
||||
{
|
||||
public:
|
||||
NorthstarEncoder(const EncoderProto& config):
|
||||
AbstractEncoder(config),
|
||||
_config(config.northstar())
|
||||
{}
|
||||
NorthstarEncoder(const EncoderProto& config):
|
||||
AbstractEncoder(config),
|
||||
_config(config.northstar())
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<const Sector>> collectSectors(int physicalTrack, int physicalSide, const Image& image) override
|
||||
{
|
||||
std::vector<std::shared_ptr<const Sector>> sectors;
|
||||
std::vector<std::shared_ptr<const Sector>> collectSectors(
|
||||
int physicalTrack, int physicalSide, const Image& image) override
|
||||
{
|
||||
std::vector<std::shared_ptr<const Sector>> sectors;
|
||||
|
||||
if ((physicalTrack >= 0) && (physicalTrack < 35))
|
||||
{
|
||||
for (int sectorId = 0; sectorId < 10; sectorId++)
|
||||
{
|
||||
const auto& sector = image.get(physicalTrack, physicalSide, sectorId);
|
||||
if (sector)
|
||||
sectors.push_back(sector);
|
||||
}
|
||||
}
|
||||
if ((physicalTrack >= 0) && (physicalTrack < 35))
|
||||
{
|
||||
for (int sectorId = 0; sectorId < 10; sectorId++)
|
||||
{
|
||||
const auto& sector =
|
||||
image.get(physicalTrack, physicalSide, sectorId);
|
||||
if (sector)
|
||||
sectors.push_back(sector);
|
||||
}
|
||||
}
|
||||
|
||||
return sectors;
|
||||
}
|
||||
return sectors;
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide,
|
||||
const std::vector<std::shared_ptr<const Sector>>& sectors, const Image& image) override
|
||||
{
|
||||
int bitsPerRevolution = 100000;
|
||||
double clockRateUs = 4.00;
|
||||
std::unique_ptr<Fluxmap> encode(int physicalTrack,
|
||||
int physicalSide,
|
||||
const std::vector<std::shared_ptr<const Sector>>& sectors,
|
||||
const Image& image) override
|
||||
{
|
||||
int bitsPerRevolution = 100000;
|
||||
double clockRateUs = 4.00;
|
||||
|
||||
if ((physicalTrack < 0) || (physicalTrack >= 35) || sectors.empty())
|
||||
return std::unique_ptr<Fluxmap>();
|
||||
if ((physicalTrack < 0) || (physicalTrack >= 35) || sectors.empty())
|
||||
return std::unique_ptr<Fluxmap>();
|
||||
|
||||
const auto& sector = *sectors.begin();
|
||||
if (sector->data.size() == NORTHSTAR_PAYLOAD_SIZE_SD) {
|
||||
bitsPerRevolution /= 2; // FM
|
||||
} else {
|
||||
clockRateUs /= 2.00;
|
||||
}
|
||||
const auto& sector = *sectors.begin();
|
||||
if (sector->data.size() == NORTHSTAR_PAYLOAD_SIZE_SD)
|
||||
bitsPerRevolution /= 2; // FM
|
||||
else
|
||||
clockRateUs /= 2.00;
|
||||
|
||||
std::vector<bool> bits(bitsPerRevolution);
|
||||
unsigned cursor = 0;
|
||||
auto fluxmap = std::make_unique<Fluxmap>();
|
||||
bool first = true;
|
||||
for (const auto& sectorData : sectors)
|
||||
{
|
||||
if (!first)
|
||||
fluxmap->appendIndex();
|
||||
first = false;
|
||||
|
||||
for (const auto& sectorData : sectors)
|
||||
write_sector(bits, cursor, sectorData);
|
||||
std::vector<bool> bits(bitsPerRevolution);
|
||||
unsigned cursor = 0;
|
||||
write_sector(bits, cursor, sectorData);
|
||||
fluxmap->appendBits(bits, clockRateUs * 1e3);
|
||||
}
|
||||
|
||||
if (cursor > bits.size())
|
||||
Error() << "track data overrun";
|
||||
// if (fluxmap->duration() > 200e6)
|
||||
// Error() << "track data overrun";
|
||||
|
||||
std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
|
||||
fluxmap->appendBits(bits, clockRateUs * 1e3);
|
||||
return fluxmap;
|
||||
}
|
||||
return fluxmap;
|
||||
}
|
||||
|
||||
private:
|
||||
const NorthstarEncoderProto& _config;
|
||||
const NorthstarEncoderProto& _config;
|
||||
};
|
||||
|
||||
std::unique_ptr<AbstractEncoder> createNorthstarEncoder(const EncoderProto& config)
|
||||
std::unique_ptr<AbstractEncoder> createNorthstarEncoder(
|
||||
const EncoderProto& config)
|
||||
{
|
||||
return std::unique_ptr<AbstractEncoder>(new NorthstarEncoder(config));
|
||||
return std::unique_ptr<AbstractEncoder>(new NorthstarEncoder(config));
|
||||
}
|
||||
|
||||
|
||||
@@ -56,4 +56,3 @@ Fluxmap& Fluxmap::appendBits(const std::vector<bool>& bits, nanoseconds_t clock)
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,41 +17,60 @@ public:
|
||||
unsigned zeroes = 0;
|
||||
|
||||
nanoseconds_t ns() const
|
||||
{ return ticks * NS_PER_TICK; }
|
||||
{
|
||||
return ticks * NS_PER_TICK;
|
||||
}
|
||||
|
||||
operator std::string () {
|
||||
operator std::string()
|
||||
{
|
||||
return fmt::format("[b:{}, t:{}, z:{}]", bytes, ticks, zeroes);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
Fluxmap() {}
|
||||
Fluxmap() {}
|
||||
|
||||
Fluxmap(const std::string& s)
|
||||
{
|
||||
appendBytes((const uint8_t*) s.c_str(), s.size());
|
||||
}
|
||||
Fluxmap(const std::string& s)
|
||||
{
|
||||
appendBytes((const uint8_t*)s.c_str(), s.size());
|
||||
}
|
||||
|
||||
Fluxmap(const Bytes bytes):
|
||||
_bytes(bytes)
|
||||
{}
|
||||
Fluxmap(const Bytes& bytes)
|
||||
{
|
||||
appendBytes(bytes);
|
||||
}
|
||||
|
||||
nanoseconds_t duration() const { return _duration; }
|
||||
unsigned ticks() const { return _ticks; }
|
||||
size_t bytes() const { return _bytes.size(); }
|
||||
const Bytes& rawBytes() const { return _bytes; }
|
||||
nanoseconds_t duration() const
|
||||
{
|
||||
return _duration;
|
||||
}
|
||||
|
||||
unsigned ticks() const
|
||||
{
|
||||
return _ticks;
|
||||
}
|
||||
|
||||
size_t bytes() const
|
||||
{
|
||||
return _bytes.size();
|
||||
}
|
||||
|
||||
const Bytes& rawBytes() const
|
||||
{
|
||||
return _bytes;
|
||||
}
|
||||
|
||||
const uint8_t* ptr() const
|
||||
{
|
||||
if (!_bytes.empty())
|
||||
return &_bytes[0];
|
||||
return NULL;
|
||||
}
|
||||
{
|
||||
if (!_bytes.empty())
|
||||
return &_bytes[0];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Fluxmap& appendInterval(uint32_t ticks);
|
||||
Fluxmap& appendPulse();
|
||||
Fluxmap& appendIndex();
|
||||
Fluxmap& appendDesync();
|
||||
Fluxmap& appendDesync();
|
||||
|
||||
Fluxmap& appendBytes(const Bytes& bytes);
|
||||
Fluxmap& appendBytes(const uint8_t* ptr, size_t len);
|
||||
@@ -61,14 +80,14 @@ public:
|
||||
return appendBytes(&byte, 1);
|
||||
}
|
||||
|
||||
Fluxmap& appendBits(const std::vector<bool>& bits, nanoseconds_t clock);
|
||||
Fluxmap& appendBits(const std::vector<bool>& bits, nanoseconds_t clock);
|
||||
|
||||
void precompensate(int threshold_ticks, int amount_ticks);
|
||||
std::vector<std::unique_ptr<const Fluxmap>> split() const;
|
||||
std::unique_ptr<const Fluxmap> rescale(double scale) const;
|
||||
|
||||
private:
|
||||
uint8_t& findLastByte();
|
||||
uint8_t& findLastByte();
|
||||
|
||||
private:
|
||||
nanoseconds_t _duration = 0;
|
||||
|
||||
@@ -322,10 +322,10 @@ encodedecodetest() {
|
||||
echo " format=$format"
|
||||
echo " configs=$*"
|
||||
echo " fluxx=flux"
|
||||
echo "build $OBJDIR/$format.encodedecode.scp.stamp : encodedecode | fluxengine$EXTENSION scripts/encodedecodetest.sh $*"
|
||||
echo " format=$format"
|
||||
echo " configs=$*"
|
||||
echo " fluxx=scp"
|
||||
#echo "build $OBJDIR/$format.encodedecode.scp.stamp : encodedecode | fluxengine$EXTENSION scripts/encodedecodetest.sh $*"
|
||||
#echo " format=$format"
|
||||
#echo " configs=$*"
|
||||
#echo " fluxx=scp"
|
||||
}
|
||||
|
||||
buildlibrary libagg.a \
|
||||
@@ -677,6 +677,7 @@ encodedecodetest rx50
|
||||
encodedecodetest tids990
|
||||
encodedecodetest victor9k_ss
|
||||
encodedecodetest victor9k_ds
|
||||
encodedecodetest northstar87 scripts/northstar87_test.textpb
|
||||
|
||||
# vim: sw=4 ts=4 et
|
||||
|
||||
|
||||
29
scripts/northstar87_test.textpb
Normal file
29
scripts/northstar87_test.textpb
Normal file
@@ -0,0 +1,29 @@
|
||||
image_reader {
|
||||
img {
|
||||
tracks: 35
|
||||
sides: 1
|
||||
trackdata {
|
||||
sector_size: 256
|
||||
sector_range {
|
||||
start_sector: 0
|
||||
sector_count: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
image_writer {
|
||||
img {
|
||||
tracks: 35
|
||||
sides: 1
|
||||
trackdata {
|
||||
sector_size: 256
|
||||
sector_range {
|
||||
start_sector: 0
|
||||
sector_count: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user