mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Brother disks are now fully decoded and stitched together into images. Hurray!
This commit is contained in:
18
lib/crc.cc
18
lib/crc.cc
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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(§ordata[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;
|
||||
|
||||
12
lib/flags.cc
12
lib/flags.cc
@@ -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);
|
||||
|
||||
24
lib/flags.h
24
lib/flags.h
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user