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:
David Given
2019-04-12 00:13:56 +02:00
parent 9c6fe1bafa
commit 84076674fd
9 changed files with 161 additions and 46 deletions

View File

@@ -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++];

View File

@@ -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();

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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;