Brother disks are now fully decoded and stitched together into images. Hurray!

This commit is contained in:
David Given
2018-10-27 02:15:01 +02:00
parent dde018e281
commit 0eecb0985d
6 changed files with 120 additions and 12 deletions

View File

@@ -8,10 +8,26 @@ uint16_t crc16(uint16_t poly, const uint8_t* start, const uint8_t* end)
while (start != end)
{
crc ^= *start++ << 8;
for (int i=0; i < 8; i++)
for (int i=0; i<8; i++)
crc = (crc & 0x8000) ? ((crc<<1)^poly) : (crc<<1);
}
return crc;
}
/* Thanks to user202729 on StackOverflow for miraculously reverse engineering
* this. */
uint32_t crcbrother(const uint8_t* start, const uint8_t* end)
{
uint32_t crc = *start++;
while (start != end)
{
for (int i=0; i<8; i++)
crc = (crc & 0x800000) ? ((crc<<1)^BROTHER_POLY) : (crc<<1);
crc ^= *start++;
}
return crc & 0xFFFFFF;
}

View File

@@ -2,8 +2,10 @@
#define CRC_H
#define CCITT_POLY 0x1021
#define BROTHER_POLY 0x000201
extern uint16_t crc16(uint16_t poly, const uint8_t* start, const uint8_t* end);
extern uint32_t crcbrother(const uint8_t* start, const uint8_t* end);
#endif

View File

@@ -1,6 +1,7 @@
#include "globals.h"
#include "decoders.h"
#include "image.h"
#include "crc.h"
#include <string.h>
std::vector<std::unique_ptr<Sector>> parseRecordsToSectorsBrother(const std::vector<std::vector<uint8_t>>& records)
@@ -20,19 +21,22 @@ std::vector<std::unique_ptr<Sector>> parseRecordsToSectorsBrother(const std::vec
nextTrack = record[1];
nextSector = record[2];
hasHeader = true;
/* TODO: check CRC! */
break;
case BROTHER_DATA_RECORD & 0xff:
{
if (record.size() < (BROTHER_DATA_RECORD_PAYLOAD+1))
goto garbage;
/* TODO: check CRC! */
if (!hasHeader)
goto garbage;
uint32_t realCrc = crcbrother(&record[1], &record[257]);
uint32_t wantCrc = (record[257]<<16) | (record[258]<<8) | record[259];
int status = (realCrc == wantCrc) ? Sector::OK : Sector::BAD_CHECKSUM;
std::vector<uint8_t> sectordata(BROTHER_DATA_RECORD_PAYLOAD);
memcpy(&sectordata[0], &record[1], BROTHER_DATA_RECORD_PAYLOAD);
auto sector = std::unique_ptr<Sector>(new Sector(Sector::OK, nextTrack, 0, nextSector, sectordata));
auto sector = std::unique_ptr<Sector>(new Sector(status, nextTrack, 0, nextSector, sectordata));
sectors.push_back(std::move(sector));
hasHeader = false;
break;

View File

@@ -79,6 +79,16 @@ void Flag::parseFlags(int argc, const char* argv[])
}
void BoolFlag::set(const std::string& value)
{
if ((value == "true") || (value == "y"))
_value = true;
else if ((value == "false") || (value == "n"))
_value = false;
else
Error() << "can't parse '" << value << "'; try 'true' or 'false'";
}
static void doHelp()
{
std::cout << "FluxEngine options:" << std::endl;
@@ -104,4 +114,4 @@ static void doHelp()
static ActionFlag helpFlag = ActionFlag(
{ "--help", "-h" },
"Shows the help.",
doHelp);
doHelp);

View File

@@ -15,7 +15,7 @@ public:
virtual bool hasArgument() const = 0;
virtual const std::string defaultValue() const = 0;
virtual void set(const std::string value) = 0;
virtual void set(const std::string& value) = 0;
private:
const std::vector<std::string> _names;
@@ -33,7 +33,7 @@ public:
bool hasArgument() const { return false; }
const std::string defaultValue() const { return ""; }
void set(const std::string value) { _callback(); }
void set(const std::string& value) { _callback(); }
private:
const std::function<void(void)> _callback;
@@ -50,7 +50,7 @@ public:
bool hasArgument() const { return false; }
const std::string defaultValue() const { return "false"; }
void set(const std::string value) { _value = true; }
void set(const std::string& value) { _value = true; }
private:
bool _value = false;
@@ -86,7 +86,7 @@ public:
{}
const std::string defaultValue() const { return _defaultValue; }
void set(const std::string value) { _value = value; }
void set(const std::string& value) { _value = value; }
};
class IntFlag : public ValueFlag<int>
@@ -98,7 +98,7 @@ public:
{}
const std::string defaultValue() const { return std::to_string(_defaultValue); }
void set(const std::string value) { _value = std::stoi(value); }
void set(const std::string& value) { _value = std::stoi(value); }
};
class DoubleFlag : public ValueFlag<double>
@@ -110,7 +110,19 @@ public:
{}
const std::string defaultValue() const { return std::to_string(_defaultValue); }
void set(const std::string value) { _value = std::stod(value); }
void set(const std::string& value) { _value = std::stod(value); }
};
class BoolFlag : public ValueFlag<double>
{
public:
BoolFlag(const std::vector<std::string>& names, const std::string helptext,
bool defaultValue = false):
ValueFlag(names, helptext, defaultValue)
{}
const std::string defaultValue() const { return _defaultValue ? "true" : "false"; }
void set(const std::string& value);
};
#endif

View File

@@ -5,19 +5,30 @@
#include "decoders.h"
#include "image.h"
#include <fmt/format.h>
#include <fstream>
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
"brother.img");
static SettableFlag dumpRecords(
{ "--dump-records" },
"Dump the parsed records.");
#define SECTOR_COUNT 12
int main(int argc, const char* argv[])
{
Flag::parseFlags(argc, argv);
bool failures = false;
std::ofstream o("records.txt");
std::vector<std::unique_ptr<Sector>> allSectors;
for (auto& track : readTracks())
{
int retries = 5;
retry:
Fluxmap& fluxmap = track->read();
nanoseconds_t clockPeriod = fluxmap.guessClock();
@@ -32,16 +43,69 @@ int main(int argc, const char* argv[])
auto sectors = parseRecordsToSectorsBrother(records);
std::cout << " " << sectors.size() << " sectors; ";
std::vector<std::unique_ptr<Sector>> goodSectors(SECTOR_COUNT);
for (auto& sector : sectors)
{
if (sector->status == Sector::OK)
goodSectors.at(sector->sector) = std::move(sector);
}
bool hasBadSectors = false;
for (int i=0; i<SECTOR_COUNT; i++)
{
if (!goodSectors.at(i))
{
std::cout << std::endl
<< " Failed to read sector " << i << "; ";
hasBadSectors = true;
}
}
if (hasBadSectors)
{
if (retries == 0)
failures = true;
else
{
std::cout << std::endl
<< " " << retries << " retries remaining" << std::endl;
retries--;
track->forceReread();
goto retry;
}
}
int size = 0;
for (auto& sector : sectors)
for (auto& sector : goodSectors)
{
size += sector->data.size();
allSectors.push_back(std::move(sector));
}
std::cout << size << " bytes decoded." << std::endl;
if (dumpRecords)
{
std::cout << "\nRaw records follow:\n\n";
for (auto& record : records)
{
hexdump(std::cout, record);
std::cout << std::endl;
}
}
for (auto& record : records)
{
if ((record.size() >= 260) && (record[0] == 0xdb))
{
for (int i=1; i<260; i++)
o << fmt::format("{:02x}", record[i]);
o << std::endl;
}
}
}
writeSectorsToFile(allSectors, outputFilename);
if (failures)
std::cerr << "Warning: some sectors could not be decoded." << std::endl;
return 0;
}