diff --git a/arch/northstar/decoder.cc b/arch/northstar/decoder.cc index ffc99faf..fb3af347 100644 --- a/arch/northstar/decoder.cc +++ b/arch/northstar/decoder.cc @@ -88,16 +88,6 @@ class NorthstarDecoder : public AbstractDecoder 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 @@ class NorthstarDecoder : public AbstractDecoder 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 @@ class NorthstarDecoder : public AbstractDecoder 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) { diff --git a/arch/northstar/encoder.cc b/arch/northstar/encoder.cc index 4172ba72..4be506cf 100644 --- a/arch/northstar/encoder.cc +++ b/arch/northstar/encoder.cc @@ -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& bits, unsigned& cursor, const std::shared_ptr& sector) +static void write_sector(std::vector& bits, + unsigned& cursor, + const std::shared_ptr& sector) { - int preambleSize = 0; - int encodedSectorSize = 0; - int gapFillSize = 0; - int preHeaderGapFillSize = 0; - - 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; - } - - int fullSectorSize = preambleSize + encodedSectorSize; - auto fullSector = std::make_shared>(); - fullSector->reserve(fullSectorSize); - - /* sector gap after index pulse */ - for (int i = 0; i < preHeaderGapFillSize; i++) - fullSector->push_back(GAP1_FILL_BYTE); - - /* sector preamble */ - for (int i = 0; i < preambleSize; i++) - fullSector->push_back(0); - - 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); - - if (sector->logicalSector != 9) { - /* sector postamble */ - for (int i = 0; i < gapFillSize; i++) - fullSector->push_back(GAP2_FILL_BYTE); - - 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); - } - - bool lastBit = false; - - if (doubleDensity == true) { - encodeMfm(bits, cursor, fullSector, lastBit); - } - else { - encodeFm(bits, cursor, fullSector); - } + int preambleSize = 0; + int encodedSectorSize = 0; + int preHeaderGapFillSize = 0; + + 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; + 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; + preHeaderGapFillSize = PRE_HEADER_GAP_FILL_SIZE_DD; + doubleDensity = true; + break; + + default: + Error() << "unsupported sector size --- you must pick 256 or 512"; + break; + } + + int fullSectorSize = preambleSize + encodedSectorSize; + auto fullSector = std::make_shared>(); + fullSector->reserve(fullSectorSize); + + /* sector gap after index pulse */ + for (int i = 0; i < preHeaderGapFillSize; i++) + fullSector->push_back(GAP1_FILL_BYTE); + + /* sector preamble */ + for (int i = 0; i < preambleSize; i++) + fullSector->push_back(0); + + 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); + + 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()) - {} - - std::vector> collectSectors(int physicalTrack, int physicalSide, const Image& image) override - { - std::vector> 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); - } - } - - return sectors; - } - - std::unique_ptr encode(int physicalTrack, int physicalSide, - const std::vector>& sectors, const Image& image) override - { - int bitsPerRevolution = 100000; - double clockRateUs = 4.00; - - if ((physicalTrack < 0) || (physicalTrack >= 35) || sectors.empty()) - return std::unique_ptr(); - - const auto& sector = *sectors.begin(); - if (sector->data.size() == NORTHSTAR_PAYLOAD_SIZE_SD) { - bitsPerRevolution /= 2; // FM - } else { - clockRateUs /= 2.00; - } - - std::vector bits(bitsPerRevolution); - unsigned cursor = 0; - - for (const auto& sectorData : sectors) - write_sector(bits, cursor, sectorData); - - if (cursor > bits.size()) - Error() << "track data overrun"; - - std::unique_ptr fluxmap(new Fluxmap); - fluxmap->appendBits(bits, clockRateUs * 1e3); - return fluxmap; - } + NorthstarEncoder(const EncoderProto& config): + AbstractEncoder(config), + _config(config.northstar()) + { + } + + std::vector> collectSectors( + int physicalTrack, int physicalSide, const Image& image) override + { + std::vector> 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); + } + } + + return sectors; + } + + std::unique_ptr encode(int physicalTrack, + int physicalSide, + const std::vector>& sectors, + const Image& image) override + { + int bitsPerRevolution = 100000; + double clockRateUs = 4.00; + + if ((physicalTrack < 0) || (physicalTrack >= 35) || sectors.empty()) + return std::unique_ptr(); + + const auto& sector = *sectors.begin(); + if (sector->data.size() == NORTHSTAR_PAYLOAD_SIZE_SD) + bitsPerRevolution /= 2; // FM + else + clockRateUs /= 2.00; + + auto fluxmap = std::make_unique(); + bool first = true; + for (const auto& sectorData : sectors) + { + if (!first) + fluxmap->appendIndex(); + first = false; + + std::vector bits(bitsPerRevolution); + unsigned cursor = 0; + write_sector(bits, cursor, sectorData); + fluxmap->appendBits(bits, clockRateUs * 1e3); + } + +// if (fluxmap->duration() > 200e6) +// Error() << "track data overrun"; + + return fluxmap; + } private: - const NorthstarEncoderProto& _config; + const NorthstarEncoderProto& _config; }; -std::unique_ptr createNorthstarEncoder(const EncoderProto& config) +std::unique_ptr createNorthstarEncoder( + const EncoderProto& config) { - return std::unique_ptr(new NorthstarEncoder(config)); + return std::unique_ptr(new NorthstarEncoder(config)); } - diff --git a/lib/encoders/encoders.cc b/lib/encoders/encoders.cc index e2094581..932ddee6 100644 --- a/lib/encoders/encoders.cc +++ b/lib/encoders/encoders.cc @@ -56,4 +56,3 @@ Fluxmap& Fluxmap::appendBits(const std::vector& bits, nanoseconds_t clock) return *this; } - diff --git a/lib/fluxmap.h b/lib/fluxmap.h index fb389b01..6b781c23 100644 --- a/lib/fluxmap.h +++ b/lib/fluxmap.h @@ -17,41 +17,60 @@ class Fluxmap 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 Bytes& bytes) + { + appendBytes(bytes); + } + + nanoseconds_t duration() const + { + return _duration; + } - Fluxmap(const std::string& s) - { - appendBytes((const uint8_t*) s.c_str(), s.size()); - } + unsigned ticks() const + { + return _ticks; + } - Fluxmap(const Bytes bytes): - _bytes(bytes) - {} + size_t bytes() const + { + return _bytes.size(); + } - 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 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 @@ class Fluxmap return appendBytes(&byte, 1); } - Fluxmap& appendBits(const std::vector& bits, nanoseconds_t clock); + Fluxmap& appendBits(const std::vector& bits, nanoseconds_t clock); void precompensate(int threshold_ticks, int amount_ticks); std::vector> split() const; std::unique_ptr rescale(double scale) const; private: - uint8_t& findLastByte(); + uint8_t& findLastByte(); private: nanoseconds_t _duration = 0; diff --git a/mkninja.sh b/mkninja.sh index a947d61b..02f41cd6 100644 --- a/mkninja.sh +++ b/mkninja.sh @@ -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 diff --git a/scripts/northstar87_test.textpb b/scripts/northstar87_test.textpb new file mode 100644 index 00000000..b6a0c5ad --- /dev/null +++ b/scripts/northstar87_test.textpb @@ -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 + } + } + } +} + +