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_read.c \
|
||||||
cmd_write.c \
|
cmd_write.c \
|
||||||
cmd_mfmdecode.c \
|
cmd_mfmdecode.c \
|
||||||
|
cmd_brotherdecode.c \
|
||||||
cmd_testpattern.c \
|
cmd_testpattern.c \
|
||||||
cmd_fluxdump.c \
|
cmd_fluxdump.c \
|
||||||
cmd_calibrate.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 const char* output_filename = NULL;
|
||||||
static int track = 0;
|
static int track = 0;
|
||||||
static int side = 0;
|
static int side = 0;
|
||||||
static int resolution_ns = NS_PER_TICK;
|
|
||||||
static sqlite3* db;
|
static sqlite3* db;
|
||||||
|
|
||||||
static void syntax_error(void)
|
static void syntax_error(void)
|
||||||
@@ -18,7 +17,6 @@ static void syntax_error(void)
|
|||||||
" -t <track> track to dump\n"
|
" -t <track> track to dump\n"
|
||||||
" -0 dump side 0\n"
|
" -0 dump side 0\n"
|
||||||
" -1 dump side 1\n"
|
" -1 dump side 1\n"
|
||||||
" -r <resolution> time per sample in ns (default: one tick)\n"
|
|
||||||
);
|
);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -27,7 +25,7 @@ static char* const* parse_options(char* const* argv)
|
|||||||
{
|
{
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
switch (getopt(countargs(argv), argv, "+i:o:t:01r:L"))
|
switch (getopt(countargs(argv), argv, "+i:o:t:01:L"))
|
||||||
{
|
{
|
||||||
case -1:
|
case -1:
|
||||||
return argv + optind - 1;
|
return argv + optind - 1;
|
||||||
@@ -50,10 +48,6 @@ static char* const* parse_options(char* const* argv)
|
|||||||
|
|
||||||
case '1':
|
case '1':
|
||||||
side = 1;
|
side = 1;
|
||||||
break;
|
|
||||||
|
|
||||||
case 'r':
|
|
||||||
resolution_ns = atoi(optarg);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -82,8 +76,6 @@ void cmd_fluxdump(char* const* argv)
|
|||||||
error("you must supply a filename to read from");
|
error("you must supply a filename to read from");
|
||||||
if (!output_filename)
|
if (!output_filename)
|
||||||
error("you must supply a filename to write to");
|
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();
|
open_file();
|
||||||
struct fluxmap* fluxmap = sql_read_flux(db, track, side);
|
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");
|
error("no data for that track in the file");
|
||||||
|
|
||||||
printf("Length: %d ms\n", fluxmap->length_us / 1000);
|
printf("Length: %d ms\n", fluxmap->length_us / 1000);
|
||||||
int length_r = fluxmap->length_us * 1000 / resolution_ns;
|
int length_ticks = fluxmap->length_us * TICKS_PER_US;
|
||||||
printf("Output size: %d bytes\n", length_r);
|
printf("Output size: %d bytes\n", length_ticks);
|
||||||
|
|
||||||
uint8_t* buffer = calloc(1, length_r);
|
uint8_t* buffer = calloc(1, length_ticks);
|
||||||
int cursor_ns = 0;
|
int cursor_ticks = 0;
|
||||||
for (int i=0; i<fluxmap->bytes; i++)
|
for (int i=0; i<fluxmap->bytes; i++)
|
||||||
{
|
{
|
||||||
uint8_t t = fluxmap->intervals[i];
|
cursor_ticks += fluxmap->intervals[i];
|
||||||
cursor_ns += t * NS_PER_TICK / resolution_ns;
|
if (cursor_ticks < length_ticks)
|
||||||
if (cursor_ns < length_r)
|
buffer[cursor_ticks] = 0x7f;
|
||||||
buffer[cursor_ns] = 0x7f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* fp = fopen(output_filename, "wb");
|
FILE* fp = fopen(output_filename, "wb");
|
||||||
fwrite(buffer, length_r, 1, fp);
|
fwrite(buffer, length_ticks, 1, fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ extern void cmd_usbbench(char* const* argv);
|
|||||||
extern void cmd_read(char* const* argv);
|
extern void cmd_read(char* const* argv);
|
||||||
extern void cmd_write(char* const* argv);
|
extern void cmd_write(char* const* argv);
|
||||||
extern void cmd_mfmdecode(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_testpattern(char* const* argv);
|
||||||
extern void cmd_fluxdump(char* const* argv);
|
extern void cmd_fluxdump(char* const* argv);
|
||||||
extern void cmd_calibrate(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);
|
cmd_write(argv);
|
||||||
else if (strcmp(argv[0], "mfmdecode") == 0)
|
else if (strcmp(argv[0], "mfmdecode") == 0)
|
||||||
cmd_mfmdecode(argv);
|
cmd_mfmdecode(argv);
|
||||||
|
else if (strcmp(argv[0], "brotherdecode") == 0)
|
||||||
|
cmd_brotherdecode(argv);
|
||||||
else if (strcmp(argv[0], "testpattern") == 0)
|
else if (strcmp(argv[0], "testpattern") == 0)
|
||||||
cmd_testpattern(argv);
|
cmd_testpattern(argv);
|
||||||
else if (strcmp(argv[0], "fluxdump") == 0)
|
else if (strcmp(argv[0], "fluxdump") == 0)
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ enum
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define NS_PER_TICK ((double)1000000000 / (double)TICK_FREQUENCY)
|
#define NS_PER_TICK ((double)1000000000 / (double)TICK_FREQUENCY)
|
||||||
|
#define US_PER_TICK ((double)1000000 / (double)TICK_FREQUENCY)
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user