mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Add the skeleton of the Brother GCR decoder.
This commit is contained in:
1
Makefile
1
Makefile
@@ -12,6 +12,7 @@ SRCS = \
|
||||
cmd_read.c \
|
||||
cmd_write.c \
|
||||
cmd_mfmdecode.c \
|
||||
cmd_brotherdecode.c \
|
||||
cmd_testpattern.c \
|
||||
cmd_fluxdump.c \
|
||||
cmd_calibrate.c \
|
||||
|
||||
212
cmd_brotherdecode.c
Normal file
212
cmd_brotherdecode.c
Normal file
@@ -0,0 +1,212 @@
|
||||
#include "globals.h"
|
||||
#include "sql.h"
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CLOCK_LOCK_BOOST 6 /* arbitrary */
|
||||
#define CLOCK_LOCK_DECAY 1 /* arbitrary */
|
||||
#define CLOCK_DETECTOR_AMPLITUDE_THRESHOLD 60 /* arbi4rary */
|
||||
#define CLOCK_ERROR_BOUNDS 0.25
|
||||
|
||||
#define IAM 0xFC /* start-of-track record */
|
||||
#define IAM_LEN 4
|
||||
#define IDAM 0xFE /* sector header */
|
||||
#define IDAM_LEN 10
|
||||
#define DAM1 0xF8 /* sector data (type 1) */
|
||||
#define DAM2 0xFB /* sector data (type 2) */
|
||||
#define DAM_LEN 6 /* plus user data */
|
||||
/* Length of a DAM record is determined by the previous sector header. */
|
||||
|
||||
static const char* inputfilename = NULL;
|
||||
static const char* outputfilename = NULL;
|
||||
static bool verbose = false;
|
||||
static sqlite3* indb;
|
||||
static sqlite3* outdb;
|
||||
|
||||
static int cursor;
|
||||
static nanoseconds_t elapsed_time;
|
||||
static uint8_t outputbuffer[20*1024];
|
||||
static int outputbufferpos;
|
||||
static uint8_t outputfifo = 0;
|
||||
static int bitcount = 0;
|
||||
static bool phase = false;
|
||||
|
||||
static void syntax_error(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"syntax: fluxclient mfmdecode <options>:\n"
|
||||
" -i <filename> input filename (.flux)\n"
|
||||
" -o <filename> output filename (.rec)\n"
|
||||
" -v verbose decoding\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static char* const* parse_options(char* const* argv)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
switch (getopt(countargs(argv), argv, "+i:o:v"))
|
||||
{
|
||||
case -1:
|
||||
return argv + optind - 1;
|
||||
|
||||
case 'i':
|
||||
inputfilename = optarg;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
outputfilename = optarg;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
syntax_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void close_files(void)
|
||||
{
|
||||
if (indb)
|
||||
sqlite3_close(indb);
|
||||
if (outdb)
|
||||
sqlite3_close(outdb);
|
||||
}
|
||||
|
||||
static void open_files(void)
|
||||
{
|
||||
indb = sql_open(inputfilename, SQLITE_OPEN_READONLY);
|
||||
outdb = sql_open(outputfilename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
|
||||
sql_prepare_record(outdb);
|
||||
atexit(close_files);
|
||||
}
|
||||
|
||||
static void write_bit(bool bit)
|
||||
{
|
||||
outputfifo = (outputfifo << 1) | bit;
|
||||
bitcount++;
|
||||
if (bitcount == 8)
|
||||
{
|
||||
outputbuffer[outputbufferpos++] = outputfifo;
|
||||
bitcount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void log_record(void)
|
||||
{
|
||||
if (verbose)
|
||||
printf("\n % 8.3fms [0x%05x] ",
|
||||
(double)elapsed_time / 1e6, cursor);
|
||||
else
|
||||
putchar('.');
|
||||
}
|
||||
|
||||
static void decode_track_cb(int track, int side, const struct fluxmap* fluxmap)
|
||||
{
|
||||
printf("Track %02d side %d: ", track, side);
|
||||
|
||||
nanoseconds_t clock_period = fluxmap_guess_clock(fluxmap);
|
||||
printf("% 4.1fus ", (double)clock_period/(double)1000);
|
||||
|
||||
struct encoding_buffer* decoded = fluxmap_decode(fluxmap, clock_period);
|
||||
|
||||
for (int i=0; i<decoded->length_pulses; i++)
|
||||
putchar(decoded->bitmap[i] ? 'X' : '.');
|
||||
|
||||
#if 0
|
||||
cursor = 0;
|
||||
uint64_t inputfifo = 0;
|
||||
bool reading = false;
|
||||
int record = 0;
|
||||
|
||||
while (cursor < decoded->length_pulses)
|
||||
{
|
||||
elapsed_time = cursor * decoded->pulselength_ns;
|
||||
bool bit = decoded->bitmap[cursor++];
|
||||
inputfifo = (inputfifo << 1) | bit;
|
||||
|
||||
/*
|
||||
* The IAM record, which is the first one on the disk (and is optional), uses
|
||||
* a distorted 0xC2 0xC2 0xC2 marker to identify it. Unfortunately, if this is
|
||||
* shifted out of phase, it becomes a legal encoding, so if we're looking at
|
||||
* real data we can't honour this.
|
||||
*
|
||||
* 0xC2 is:
|
||||
* data: 1 1 0 0 0 0 1 0
|
||||
* mfm: 01 01 00 10 10 10 01 00 = 0x5254
|
||||
* special: 01 01 00 10 00 10 01 00 = 0x5224
|
||||
* ^^^^
|
||||
* shifted: 10 10 01 00 01 00 10 0. = legal, and might happen in real data
|
||||
*
|
||||
* Therefore, when we've read the marker, the input fifo will contain
|
||||
* 0xXXXX522252225222.
|
||||
*
|
||||
* All other records use 0xA1 as a marker:
|
||||
*
|
||||
* 0xA1 is:
|
||||
* data: 1 0 1 0 0 0 0 1
|
||||
* mfm: 01 00 01 00 10 10 10 01 = 0x44A9
|
||||
* special: 01 00 01 00 10 00 10 01 = 0x4489
|
||||
* ^^^^^
|
||||
* shifted: 10 00 10 01 00 01 00 1
|
||||
*
|
||||
* When this is shifted out of phase, we get an illegal encoding (you
|
||||
* can't do 10 00). So, if we ever see 0x448944894489 in the input
|
||||
* fifo, we know we've landed at the beginning of a new record.
|
||||
*/
|
||||
|
||||
uint64_t masked = inputfifo & 0xFFFFFFFFFFFFLL;
|
||||
if ((!reading && (masked == 0x522452245224LL)) || (masked == 0x448944894489LL))
|
||||
{
|
||||
log_record();
|
||||
|
||||
if (reading)
|
||||
sql_write_record(outdb, track, side, record++, outputbuffer, outputbufferpos);
|
||||
|
||||
if (!reading)
|
||||
memcpy(outputbuffer, "\xc2\xc2\xc2", 3);
|
||||
else
|
||||
memcpy(outputbuffer, "\xa1\xa1\xa1", 3);
|
||||
|
||||
reading = true;
|
||||
outputbufferpos = 3;
|
||||
bitcount = 0;
|
||||
phase = 0;
|
||||
}
|
||||
else if (reading)
|
||||
{
|
||||
if (phase)
|
||||
write_bit(bit);
|
||||
phase = !phase;
|
||||
}
|
||||
}
|
||||
|
||||
if (reading)
|
||||
sql_write_record(outdb, track, side, record++, outputbuffer, outputbufferpos);
|
||||
|
||||
if (verbose)
|
||||
printf("\n ");
|
||||
printf(" = %d records\n", record);
|
||||
#endif
|
||||
}
|
||||
|
||||
void cmd_brotherdecode(char* const* argv)
|
||||
{
|
||||
argv = parse_options(argv);
|
||||
if (countargs(argv) != 1)
|
||||
syntax_error();
|
||||
if (!inputfilename)
|
||||
error("you must supply a filename to read from");
|
||||
if (!outputfilename)
|
||||
error("you must supply a filename to write to");
|
||||
|
||||
open_files();
|
||||
sql_stmt(outdb, "BEGIN");
|
||||
sql_stmt(outdb, "DELETE FROM records");
|
||||
sql_for_all_flux_data(indb, decode_track_cb);
|
||||
sql_stmt(outdb, "COMMIT");
|
||||
}
|
||||
@@ -6,7 +6,6 @@ static const char* input_filename = NULL;
|
||||
static const char* output_filename = NULL;
|
||||
static int track = 0;
|
||||
static int side = 0;
|
||||
static int resolution_ns = NS_PER_TICK;
|
||||
static sqlite3* db;
|
||||
|
||||
static void syntax_error(void)
|
||||
@@ -18,7 +17,6 @@ static void syntax_error(void)
|
||||
" -t <track> track to dump\n"
|
||||
" -0 dump side 0\n"
|
||||
" -1 dump side 1\n"
|
||||
" -r <resolution> time per sample in ns (default: one tick)\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
@@ -27,7 +25,7 @@ static char* const* parse_options(char* const* argv)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
switch (getopt(countargs(argv), argv, "+i:o:t:01r:L"))
|
||||
switch (getopt(countargs(argv), argv, "+i:o:t:01:L"))
|
||||
{
|
||||
case -1:
|
||||
return argv + optind - 1;
|
||||
@@ -50,10 +48,6 @@ static char* const* parse_options(char* const* argv)
|
||||
|
||||
case '1':
|
||||
side = 1;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
resolution_ns = atoi(optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -82,8 +76,6 @@ void cmd_fluxdump(char* const* argv)
|
||||
error("you must supply a filename to read from");
|
||||
if (!output_filename)
|
||||
error("you must supply a filename to write to");
|
||||
if (resolution_ns < NS_PER_TICK)
|
||||
error("resolution too fine (minimum: %dns)", NS_PER_TICK);
|
||||
|
||||
open_file();
|
||||
struct fluxmap* fluxmap = sql_read_flux(db, track, side);
|
||||
@@ -91,21 +83,20 @@ void cmd_fluxdump(char* const* argv)
|
||||
error("no data for that track in the file");
|
||||
|
||||
printf("Length: %d ms\n", fluxmap->length_us / 1000);
|
||||
int length_r = fluxmap->length_us * 1000 / resolution_ns;
|
||||
printf("Output size: %d bytes\n", length_r);
|
||||
int length_ticks = fluxmap->length_us * TICKS_PER_US;
|
||||
printf("Output size: %d bytes\n", length_ticks);
|
||||
|
||||
uint8_t* buffer = calloc(1, length_r);
|
||||
int cursor_ns = 0;
|
||||
uint8_t* buffer = calloc(1, length_ticks);
|
||||
int cursor_ticks = 0;
|
||||
for (int i=0; i<fluxmap->bytes; i++)
|
||||
{
|
||||
uint8_t t = fluxmap->intervals[i];
|
||||
cursor_ns += t * NS_PER_TICK / resolution_ns;
|
||||
if (cursor_ns < length_r)
|
||||
buffer[cursor_ns] = 0x7f;
|
||||
cursor_ticks += fluxmap->intervals[i];
|
||||
if (cursor_ticks < length_ticks)
|
||||
buffer[cursor_ticks] = 0x7f;
|
||||
}
|
||||
|
||||
FILE* fp = fopen(output_filename, "wb");
|
||||
fwrite(buffer, length_r, 1, fp);
|
||||
fwrite(buffer, length_ticks, 1, fp);
|
||||
fclose(fp);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ extern void cmd_usbbench(char* const* argv);
|
||||
extern void cmd_read(char* const* argv);
|
||||
extern void cmd_write(char* const* argv);
|
||||
extern void cmd_mfmdecode(char* const* argv);
|
||||
extern void cmd_brotherdecode(char* const* argv);
|
||||
extern void cmd_testpattern(char* const* argv);
|
||||
extern void cmd_fluxdump(char* const* argv);
|
||||
extern void cmd_calibrate(char* const* argv);
|
||||
|
||||
2
main.c
2
main.c
@@ -76,6 +76,8 @@ int main(int argc, char* const* argv)
|
||||
cmd_write(argv);
|
||||
else if (strcmp(argv[0], "mfmdecode") == 0)
|
||||
cmd_mfmdecode(argv);
|
||||
else if (strcmp(argv[0], "brotherdecode") == 0)
|
||||
cmd_brotherdecode(argv);
|
||||
else if (strcmp(argv[0], "testpattern") == 0)
|
||||
cmd_testpattern(argv);
|
||||
else if (strcmp(argv[0], "fluxdump") == 0)
|
||||
|
||||
@@ -34,6 +34,7 @@ enum
|
||||
};
|
||||
|
||||
#define NS_PER_TICK ((double)1000000000 / (double)TICK_FREQUENCY)
|
||||
#define US_PER_TICK ((double)1000000 / (double)TICK_FREQUENCY)
|
||||
|
||||
enum
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user