Skip to content

Commit

Permalink
Merge pull request #29 from jepler/redo-mfm-add-decoding
Browse files Browse the repository at this point in the history
redesign MFM decoding & add encoding
  • Loading branch information
jepler authored Mar 7, 2024
2 parents 267e3e0 + fbfee32 commit a5a1e19
Show file tree
Hide file tree
Showing 15 changed files with 849 additions and 264 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: MIT

/mfm
/html
/ci
/doxygen
/examples/*/build
/html
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "doxygen-awesome-css"]
path = doxygen-awesome-css
url = https://github.com/jothepro/doxygen-awesome-css.git
[submodule "host_src/greaseweazle"]
path = host_src/greaseweazle
url = https://github.com/keirf/greaseweazle.git
34 changes: 6 additions & 28 deletions examples/04_msd_test/04_msd_test.ino
Original file line number Diff line number Diff line change
Expand Up @@ -119,31 +119,8 @@ void loop() {
int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize)
{
Serial.printf("read call back block %d size %d\n", lba, bufsize);

uint8_t track = lba / (2 * mfm_floppy.sectors_per_track());
uint8_t head = (lba / mfm_floppy.sectors_per_track()) % 2;
uint8_t subsector = lba % mfm_floppy.sectors_per_track();

uint8_t retries = 5;

for (int retry = 0; retry < retries; retry++) {
if (((track * 2 + head) == last_track_read) && mfm_floppy.track_validity[subsector]) {
// aah we've got it and its valid!
Serial.println("OK!");
memcpy(buffer, mfm_floppy.track_data + (subsector * SECTOR_SIZE), SECTOR_SIZE);
return SECTOR_SIZE;
}
// ok so either its not valid, or we didn't read this track yet...
int32_t tracks_read = mfm_floppy.readTrack(track, head);
if (tracks_read < 0) {
Serial.println("Failed to seek to track");
return 0;
}
last_track_read = track * 2 + head;
// we'll go again on the next round
}
Serial.println("subsector invalid CRC :(");
return 0;
auto result = mfm_floppy.readSectors(lba, reinterpret_cast<uint8_t*>(buffer), bufsize / MFM_BYTES_PER_SECTOR);
return result ? bufsize : -1;
}

// Callback invoked when received WRITE10 command.
Expand All @@ -152,14 +129,15 @@ int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize)
int32_t msc_write_callback (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
{
Serial.printf("write call back block %d size %d\n", lba, bufsize);
// we dont actually write yet
return bufsize;
auto result = mfm_floppy.writeSectors(lba, buffer, bufsize / MFM_BYTES_PER_SECTOR);
return result ? bufsize : -1;
}

// Callback invoked when WRITE10 command is completed (status received and accepted by host).
// used to flush any pending cache.
void msc_flush_callback (void)
{
Serial.println("flush\n");
mfm_floppy.syncDevice();
// nothing to do
}
}
139 changes: 139 additions & 0 deletions examples/05_mfm_write_test/05_mfm_write_test.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#include <Adafruit_Floppy.h>

#if defined(ADAFRUIT_FEATHER_M4_EXPRESS)
#define DENSITY_PIN A1 // IDC 2
#define INDEX_PIN A5 // IDC 8
#define SELECT_PIN A0 // IDC 12
#define MOTOR_PIN A2 // IDC 16
#define DIR_PIN A3 // IDC 18
#define STEP_PIN A4 // IDC 20
#define WRDATA_PIN 13 // IDC 22
#define WRGATE_PIN 12 // IDC 24
#define TRK0_PIN 10 // IDC 26
#define PROT_PIN 11 // IDC 28
#define READ_PIN 9 // IDC 30
#define SIDE_PIN 6 // IDC 32
#define READY_PIN 5 // IDC 34
#elif defined(ARDUINO_ADAFRUIT_FEATHER_RP2040)
#define DENSITY_PIN A1 // IDC 2
#define INDEX_PIN 25 // IDC 8
#define SELECT_PIN A0 // IDC 12
#define MOTOR_PIN A2 // IDC 16
#define DIR_PIN A3 // IDC 18
#define STEP_PIN 24 // IDC 20
#define WRDATA_PIN 13 // IDC 22
#define WRGATE_PIN 12 // IDC 24
#define TRK0_PIN 10 // IDC 26
#define PROT_PIN 11 // IDC 28
#define READ_PIN 9 // IDC 30
#define SIDE_PIN 8 // IDC 32
#define READY_PIN 7 // IDC 34
#ifndef USE_TINYUSB
#error "Please set Adafruit TinyUSB under Tools > USB Stack"
#endif
#elif defined(ARDUINO_RASPBERRY_PI_PICO)
#define DENSITY_PIN 2 // IDC 2
#define INDEX_PIN 3 // IDC 8
#define SELECT_PIN 4 // IDC 12
#define MOTOR_PIN 5 // IDC 16
#define DIR_PIN 6 // IDC 18
#define STEP_PIN 7 // IDC 20
#define WRDATA_PIN 8 // IDC 22 (not used during read)
#define WRGATE_PIN 9 // IDC 24 (not used during read)
#define TRK0_PIN 10 // IDC 26
#define PROT_PIN 11 // IDC 28
#define READ_PIN 12 // IDC 30
#define SIDE_PIN 13 // IDC 32
#define READY_PIN 14 // IDC 34
#ifndef USE_TINYUSB
#error "Please set Adafruit TinyUSB under Tools > USB Stack"
#endif
#elif defined(ARDUINO_ADAFRUIT_FLOPPSY_RP2040)
// Yay built in pin definitions!
#else
#error "Please set up pin definitions!"
#endif


Adafruit_Floppy floppy(DENSITY_PIN, INDEX_PIN, SELECT_PIN,
MOTOR_PIN, DIR_PIN, STEP_PIN,
WRDATA_PIN, WRGATE_PIN, TRK0_PIN,
PROT_PIN, READ_PIN, SIDE_PIN, READY_PIN);

// You can select IBMPC1440K or IBMPC360K (check adafruit_floppy_disk_t options!)
Adafruit_MFM_Floppy mfm_floppy(&floppy, IBMPC1440K);


uint32_t time_stamp = 0;

void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
while (!Serial) delay(100);

#if defined(FLOPPY_DIRECTION_PIN)
pinMode(FLOPPY_DIRECTION_PIN, OUTPUT);
digitalWrite(FLOPPY_DIRECTION_PIN, HIGH);
#endif

delay(500); // wait for serial to open
Serial.println("its time for a nice floppy transfer!");

floppy.debug_serial = &Serial;

if (! mfm_floppy.begin()) {
Serial.println("Failed to spin up motor & find index pulse");
while (1) yield();
}
}

void hexdump(size_t offset, const uint8_t *data, size_t n) {
for (size_t i = 0; i < n; i += 16) {
size_t addr = offset + i;
Serial.printf("%08x", addr);
for (size_t j = 0; j < 16; j++) {
if(i+j > n) Serial.printf(" ");else
Serial.printf(" %02x", mfm_floppy.track_data[addr + j]);
}
Serial.print(" | ");
for (size_t j = 0; j < 16; j++) {
if(i+j > n) break;
uint8_t d = mfm_floppy.track_data[addr + j];
if (! isprint(d)) {
d = ' ';
}
Serial.write(d);
}
Serial.print("\n");
}
}

uint8_t track = 0;
bool head = 0;
int i = 0;
void loop() {
int32_t captured_sectors;

uint8_t sector[512];
int lba = (i++ % 2 == 0) ? 0 : 18;
if (!mfm_floppy.readSector(lba, sector)) {
Serial.println("Failed to read sector");
return;
}

hexdump(lba * 512, sector, 512);

memset(sector, 0, 512);
snprintf(reinterpret_cast<char*>(sector), sizeof(sector), "Hello from iteration %zd of Adafruit Floppy MFM writing\n", i);

if (!mfm_floppy.writeSector(lba, sector)) {
Serial.println("Failed to write sectorn");
return;
}
if (!mfm_floppy.syncDevice()) {
Serial.println("Failed to sync device");
return;
}

delay(1000);
}
5 changes: 5 additions & 0 deletions host_src/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
test_flux.h
main
flux[01]
check[01]
decode[01]
16 changes: 16 additions & 0 deletions host_src/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
PYTHON3 = env PYTHONPATH=greaseweazle/scripts python3

.PHONY: check
check: main check_flux.py
./main
$(PYTHON3) check_flux.py flux0 > decode0
$(PYTHON3) check_flux.py flux1 > decode1

main: main.c ../src/mfm_impl.h Makefile test_flux.h
gcc -iquote ../src -Wall -Werror -ggdb3 -Og -o $@ $<

test_flux.h: make_flux.py greaseweazle/scripts/greaseweazle/version.py
$(PYTHON3) $< $@

greaseweazle/scripts/greaseweazle/version.py:
$(MAKE) -C greaseweazle
29 changes: 29 additions & 0 deletions host_src/check_flux.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import sys
from greaseweazle.track import MasterTrack
from greaseweazle.codec.ibm.mfm import IBM_MFM
from bitarray import bitarray

with open(sys.argv[1]) as flux1:
content = bitarray("".join(c for c in flux1.read() if c in "01"))

nominal_bitrate = 1_000_000

master = MasterTrack(content[:200_000], 0.2)
print(master.flux().list[:25])
track = IBM_MFM(0,0)
track.time_per_rev = 0.2
track.clock = 1e-6


track.decode_raw(master)
print(sys.argv[1], track.summary_string(), file=sys.stderr)
print(sys.argv[1], track.summary_string())
print("".join("E."[sec.crc == 0] for sec in track.sectors))
for i in track.iams:
print(i)
for s in track.sectors:
print(s)

if n := track.nr_missing():
print(f"{n} missing sector(s)", file=sys.stderr)
raise SystemExit(1)
1 change: 1 addition & 0 deletions host_src/greaseweazle
Submodule greaseweazle added at f155a3
91 changes: 91 additions & 0 deletions host_src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#define DEBUG_PRINTF(...) printf(__VA_ARGS__)
#include "mfm_impl.h"

uint8_t flux[] = {
#include "test_flux.h"
};

enum { sector_count = 18 };

uint8_t track_buf[sector_count * mfm_io_block_size];
uint8_t validity[sector_count];

mfm_io_t io = {
.T1_nom = 2,
.T2_max = 5,
.T3_max = 7,
.pulses = flux,
.n_pulses = sizeof(flux),
.sectors = track_buf,
.sector_validity = validity,
.n_sectors = sizeof(track_buf) / mfm_io_block_size,
};

static void flux_bins(mfm_io_t *io) {
io->pos = 0;
int bins[3] = {};
while (!mfm_io_eof(io)) {
bins[mfm_io_read_symbol(io)]++;
}
printf("Flux bins: %d %d %d\n", bins[0], bins[1], bins[2]);
}

static void dump_flux(const char *filename, mfm_io_t *io) {
FILE *f = fopen(filename, "w");
io->pos = 0;
uint32_t state = 0;
while (!mfm_io_eof(io)) {
int s = mfm_io_read_symbol(io);
state = ((state << 2) | s) & mfm_io_triple_mark_mask;
fprintf(f, "10");
if (s > mfm_io_pulse_10) {
fprintf(f, "0");
}
if (s > mfm_io_pulse_100) {
fprintf(f, "0");
}
if (state == mfm_io_triple_mark_magic) {
DEBUG_PRINTF("triple mark @%zd\n", io->pos);
fprintf(f, "\n");
}
}
#if 0
for(size_t i=0; i<io->num_pulses; i++) {
fprintf(f, "%d\n", io->pulses[i]);
}
#endif
fclose(f);
}

int main() {
flux_bins(&io);
printf("Decoded %zd sectors\n", decode_track_mfm(&io));

dump_flux("flux0", &io);

memset(flux, 0, sizeof(flux));

#if 0
for (size_t i = 0; i < sizeof(track_buf); i++)
track_buf[i] = i & 0xff;
#endif

printf("Create new flux data\n");
(void)encode_track_mfm;
encode_track_mfm(&io);
dump_flux("flux1", &io);

memset(track_buf, 0, sizeof(track_buf));

io.n_valid = 0;
memset(validity, 0, sizeof(validity));
flux_bins(&io);
size_t decoded = decode_track_mfm(&io);
printf("Decoded %zd sectors\n", decoded);

return decoded != 18;
}
13 changes: 13 additions & 0 deletions host_src/make_flux.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import sys
from greaseweazle.codec.ibm.mfm import IBM_MFM_1440

track = IBM_MFM_1440(0, 0)
track.set_img_track(b'adaf00' + b'\0' * 512 * 18)
track.decode_raw(track)
print(track.summary_string())
flux = track.flux().flux_for_writeout()
print(flux.list[:25],len(flux.list))
with open(sys.argv[1], "wt") as f:
for i, fi in enumerate(flux.list):
print(f"{fi*2},", end="\n" if i % 16 == 15 else " ", file=f)
print(file=f)
Loading

0 comments on commit a5a1e19

Please sign in to comment.