mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Add stateful decoders, which makes formats like the FB-100 much easier to work
with. Add a generic CRC tool allowing all the parameters to be set (currently unused).
This commit is contained in:
@@ -77,6 +77,13 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Bytes read(unsigned len)
|
||||
{
|
||||
const Bytes bytes = _bytes.slice(pos, len);
|
||||
pos += len;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
uint8_t read_8()
|
||||
{
|
||||
return _bytes[pos++];
|
||||
|
||||
44
lib/crc.cc
44
lib/crc.cc
@@ -2,6 +2,47 @@
|
||||
#include "bytes.h"
|
||||
#include "crc.h"
|
||||
|
||||
template <class T>
|
||||
T reflect(T bin, unsigned width = sizeof(T)*8)
|
||||
{
|
||||
T bout = 0;
|
||||
while (width--)
|
||||
{
|
||||
bout <<= 1;
|
||||
bout |= (bin & 1);
|
||||
bin >>= 1;
|
||||
}
|
||||
return bout;
|
||||
}
|
||||
|
||||
uint64_t generic_crc(const struct crcspec& spec, const Bytes& bytes)
|
||||
{
|
||||
uint64_t crc = spec.init;
|
||||
uint64_t top = 1LL << (spec.width-1);
|
||||
uint64_t mask = (top<<1) - 1;
|
||||
|
||||
for (uint8_t b : bytes)
|
||||
{
|
||||
if (spec.refin)
|
||||
b = reflect(b);
|
||||
|
||||
for (uint8_t i = 0x80; i != 0; i >>= 1)
|
||||
{
|
||||
uint64_t bit = crc & top;
|
||||
crc <<= 1;
|
||||
if (b & i)
|
||||
bit ^= top;
|
||||
if (bit)
|
||||
crc ^= spec.poly;
|
||||
}
|
||||
}
|
||||
|
||||
if (spec.refout)
|
||||
crc = reflect(crc, spec.width);
|
||||
crc ^= spec.xorout;
|
||||
return crc & mask;
|
||||
}
|
||||
|
||||
uint16_t sumBytes(const Bytes& bytes)
|
||||
{
|
||||
ByteReader br(bytes);
|
||||
@@ -36,11 +77,10 @@ uint16_t crc16(uint16_t poly, uint16_t crc, const Bytes& bytes)
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint16_t crc16ref(uint16_t poly, const Bytes& bytes)
|
||||
uint16_t crc16ref(uint16_t poly, uint16_t crc, const Bytes& bytes)
|
||||
{
|
||||
ByteReader br(bytes);
|
||||
|
||||
uint16_t crc = 0xffff;
|
||||
while (!br.eof())
|
||||
{
|
||||
crc ^= br.read_8();
|
||||
|
||||
17
lib/crc.h
17
lib/crc.h
@@ -6,14 +6,29 @@
|
||||
#define MODBUS_POLY_REF 0xa001
|
||||
#define BROTHER_POLY 0x000201
|
||||
|
||||
struct crcspec
|
||||
{
|
||||
unsigned width;
|
||||
uint64_t poly;
|
||||
uint64_t init;
|
||||
uint64_t xorout;
|
||||
bool refin;
|
||||
bool refout;
|
||||
};
|
||||
|
||||
extern uint64_t generic_crc(const struct crcspec& spec, const Bytes& bytes);
|
||||
|
||||
extern uint16_t sumBytes(const Bytes& bytes);
|
||||
extern uint8_t xorBytes(const Bytes& bytes);
|
||||
extern uint16_t crc16(uint16_t poly, uint16_t init, const Bytes& bytes);
|
||||
extern uint16_t crc16ref(uint16_t poly, const Bytes& bytes);
|
||||
extern uint16_t crc16ref(uint16_t poly, uint16_t init, const Bytes& bytes);
|
||||
extern uint32_t crcbrother(const Bytes& bytes);
|
||||
|
||||
static inline uint16_t crc16(uint16_t poly, const Bytes& bytes)
|
||||
{ return crc16(poly, 0xffff, bytes); }
|
||||
|
||||
static inline uint16_t crc16ref(uint16_t poly, const Bytes& bytes)
|
||||
{ return crc16ref(poly, 0xffff, bytes); }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "record.h"
|
||||
#include "protocol.h"
|
||||
#include "rawbits.h"
|
||||
#include "sector.h"
|
||||
#include "fmt/format.h"
|
||||
#include <numeric>
|
||||
|
||||
@@ -32,6 +33,11 @@ static DoubleFlag signalLevelFactor(
|
||||
"Clock detection signal level (min + (max-min)*factor).",
|
||||
0.05);
|
||||
|
||||
void setDecoderManualClockRate(double clockrate_us)
|
||||
{
|
||||
manualClockRate.value = clockrate_us;
|
||||
}
|
||||
|
||||
static const std::string BLOCK_ELEMENTS[] =
|
||||
{ " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" };
|
||||
|
||||
@@ -202,6 +208,13 @@ nanoseconds_t AbstractDecoder::guessClock(Fluxmap& fluxmap) const
|
||||
return fluxmap.guessClock();
|
||||
}
|
||||
|
||||
void AbstractSeparatedDecoder::decodeToSectors(const RawBits& bitmap, unsigned physicalTrack,
|
||||
RawRecordVector& rawrecords, SectorVector& sectors)
|
||||
{
|
||||
rawrecords = extractRecords(bitmap);
|
||||
sectors = decodeToSectors(rawrecords, physicalTrack);
|
||||
}
|
||||
|
||||
RawRecordVector AbstractSoftSectorDecoder::extractRecords(const RawBits& rawbits) const
|
||||
{
|
||||
RawRecordVector records;
|
||||
|
||||
@@ -11,6 +11,8 @@ class RawBits;
|
||||
typedef std::vector<std::unique_ptr<RawRecord>> RawRecordVector;
|
||||
typedef std::vector<std::unique_ptr<Sector>> SectorVector;
|
||||
|
||||
extern void setDecoderManualClockRate(double clockrate_us);
|
||||
|
||||
extern Bytes decodeFmMfm(std::vector<bool>::const_iterator start,
|
||||
std::vector<bool>::const_iterator end);
|
||||
|
||||
@@ -23,12 +25,25 @@ public:
|
||||
virtual ~AbstractDecoder() {}
|
||||
|
||||
virtual nanoseconds_t guessClock(Fluxmap& fluxmap) const;
|
||||
|
||||
virtual void decodeToSectors(const RawBits& bitmap, unsigned physicalTrack,
|
||||
RawRecordVector& rawrecords, SectorVector& sectors) = 0;
|
||||
};
|
||||
|
||||
class AbstractSeparatedDecoder : public AbstractDecoder
|
||||
{
|
||||
public:
|
||||
virtual ~AbstractSeparatedDecoder() {}
|
||||
|
||||
virtual RawRecordVector extractRecords(const RawBits& rawbits) const = 0;
|
||||
virtual SectorVector decodeToSectors(const RawRecordVector& rawrecords,
|
||||
unsigned physicalTrack) = 0;
|
||||
|
||||
void decodeToSectors(const RawBits& bitmap, unsigned physicalTrack,
|
||||
RawRecordVector& rawrecords, SectorVector& sectors);
|
||||
};
|
||||
|
||||
class AbstractSoftSectorDecoder : public AbstractDecoder
|
||||
class AbstractSoftSectorDecoder : public AbstractSeparatedDecoder
|
||||
{
|
||||
public:
|
||||
virtual ~AbstractSoftSectorDecoder() {}
|
||||
@@ -38,12 +53,16 @@ public:
|
||||
virtual int recordMatcher(uint64_t fifo) const = 0;
|
||||
};
|
||||
|
||||
class AbstractHardSectorDecoder : public AbstractDecoder
|
||||
class AbstractHardSectorDecoder : public AbstractSeparatedDecoder
|
||||
{
|
||||
public:
|
||||
virtual ~AbstractHardSectorDecoder() {}
|
||||
|
||||
RawRecordVector extractRecords(const RawBits& bits) const;
|
||||
RawRecordVector extractRecords(const RawBits& rawbits) const;
|
||||
};
|
||||
|
||||
class AbstractStatefulDecoder : public AbstractDecoder
|
||||
{
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,49 +7,67 @@
|
||||
#include "fb100.h"
|
||||
#include "crc.h"
|
||||
#include "bytes.h"
|
||||
#include "rawbits.h"
|
||||
#include "fmt/format.h"
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
SectorVector Fb100Decoder::decodeToSectors(const RawRecordVector& rawRecords, unsigned)
|
||||
static bool search(const RawBits& rawbits, size_t& cursor)
|
||||
{
|
||||
std::vector<std::unique_ptr<Sector>> sectors;
|
||||
unsigned nextSector;
|
||||
unsigned nextTrack;
|
||||
bool headerIsValid = false;
|
||||
uint16_t fifo = 0;
|
||||
|
||||
for (auto& rawrecord : rawRecords)
|
||||
while (cursor < rawbits.size())
|
||||
{
|
||||
const Bytes bytes = decodeFmMfm(rawrecord->data);
|
||||
hexdump(std::cout, bytes);
|
||||
if (bytes.size() < 0x515)
|
||||
continue;
|
||||
fifo = (fifo << 1) | rawbits[cursor++];
|
||||
|
||||
if (fifo == 0xabaa)
|
||||
{
|
||||
cursor -= 16;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t abssector = bytes[2];
|
||||
return false;
|
||||
}
|
||||
|
||||
void Fb100Decoder::decodeToSectors(const RawBits& rawbits, unsigned,
|
||||
RawRecordVector& rawrecords, SectorVector& sectors)
|
||||
{
|
||||
size_t cursor = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!search(rawbits, cursor))
|
||||
break;
|
||||
|
||||
unsigned record_start = cursor;
|
||||
cursor = std::min(cursor + FB100_RECORD_SIZE*16, rawbits.size());
|
||||
std::vector<bool> recordbits(rawbits.begin() + record_start, rawbits.begin() + cursor);
|
||||
|
||||
rawrecords.push_back(
|
||||
std::unique_ptr<RawRecord>(
|
||||
new RawRecord(
|
||||
record_start,
|
||||
recordbits.begin(),
|
||||
recordbits.end())
|
||||
)
|
||||
);
|
||||
|
||||
const Bytes bytes = decodeFmMfm(recordbits).slice(0, FB100_RECORD_SIZE);
|
||||
ByteReader br(bytes);
|
||||
br.seek(1);
|
||||
const Bytes id = br.read(FB100_ID_SIZE);
|
||||
uint16_t wantIdCrc = br.read_be16();
|
||||
const Bytes payload = br.read(FB100_PAYLOAD_SIZE);
|
||||
uint16_t wantPayloadCrc = br.read_be16();
|
||||
|
||||
uint8_t abssector = id[2];
|
||||
uint8_t track = abssector >> 1;
|
||||
uint8_t sectorid = abssector & 1;
|
||||
|
||||
uint16_t wantHeaderCrc = bytes.reader().seek(0x11).read_be16();
|
||||
|
||||
const Bytes payload = bytes.slice(0x13, FB100_SECTOR_SIZE);
|
||||
uint16_t wantPayloadCrc = bytes.reader().seek(0x513).read_be16();
|
||||
// hexdumpForSrp16(std::cout, payload);
|
||||
// std::cout << fmt::format("{:04x}\n", wantPayloadCrc);
|
||||
|
||||
int status = Sector::OK;
|
||||
int status = Sector::BAD_CHECKSUM;
|
||||
auto sector = std::unique_ptr<Sector>(
|
||||
new Sector(status, track, 0, sectorid, payload));
|
||||
sectors.push_back(std::move(sector));
|
||||
}
|
||||
|
||||
return sectors;
|
||||
}
|
||||
|
||||
int Fb100Decoder::recordMatcher(uint64_t fifo) const
|
||||
{
|
||||
uint32_t masked = fifo;
|
||||
if (masked == 0xeaaaaeea)
|
||||
return 22;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +1,20 @@
|
||||
#ifndef FB100_H
|
||||
#define FB100_H
|
||||
|
||||
#define FB100_SECTOR_SIZE 0x500
|
||||
#define FB100_RECORD_SIZE 0x516 /* bytes */
|
||||
#define FB100_ID_SIZE 17
|
||||
#define FB100_PAYLOAD_SIZE 0x500
|
||||
|
||||
class Sector;
|
||||
class Fluxmap;
|
||||
|
||||
class Fb100Decoder : public AbstractSoftSectorDecoder
|
||||
class Fb100Decoder : public AbstractStatefulDecoder
|
||||
{
|
||||
public:
|
||||
virtual ~Fb100Decoder() {}
|
||||
|
||||
SectorVector decodeToSectors(
|
||||
const RawRecordVector& rawRecords, unsigned physicalTrack);
|
||||
int recordMatcher(uint64_t fifo) const;
|
||||
void decodeToSectors(const RawBits& bitmap, unsigned physicalTrack,
|
||||
RawRecordVector& rawrecords, SectorVector& sectors);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -157,11 +157,12 @@ void readDiskCommand(AbstractDecoder& decoder, const std::string& outputFilename
|
||||
const auto& bitmap = fluxmap->decodeToBits(clockPeriod);
|
||||
std::cout << fmt::format("{} bytes encoded; ", bitmap.size()/8) << std::flush;
|
||||
|
||||
auto rawrecords = decoder.extractRecords(bitmap);
|
||||
std::cout << fmt::format("{} records", rawrecords.size()) << std::endl;
|
||||
RawRecordVector rawrecords;
|
||||
SectorVector sectors;
|
||||
decoder.decodeToSectors(bitmap, track->track, rawrecords, sectors);
|
||||
|
||||
auto sectors = decoder.decodeToSectors(rawrecords, track->track);
|
||||
std::cout << " " << sectors.size() << " sectors; ";
|
||||
std::cout << fmt::format("{} records", rawrecords.size()) << std::endl
|
||||
<< " " << sectors.size() << " sectors; ";
|
||||
|
||||
for (auto& sector : sectors)
|
||||
{
|
||||
|
||||
@@ -19,6 +19,7 @@ int main(int argc, const char* argv[])
|
||||
{
|
||||
setReaderDefaultSource(":t=0-79:s=0");
|
||||
setReaderRevolutions(2);
|
||||
setDecoderManualClockRate(4.0);
|
||||
Flag::parseFlags(argc, argv);
|
||||
|
||||
Fb100Decoder decoder;
|
||||
|
||||
Reference in New Issue
Block a user