diff options
author | Raghuram Subramani <raghus2247@gmail.com> | 2022-06-19 19:47:51 +0530 |
---|---|---|
committer | Raghuram Subramani <raghus2247@gmail.com> | 2022-06-19 19:47:51 +0530 |
commit | 4fd287655a72b9aea14cdac715ad5b90ed082ed2 (patch) | |
tree | 65d393bc0e699dd12d05b29ba568e04cea666207 /circuitpython/lib/adafruit_floppy/examples | |
parent | 0150f70ce9c39e9e6dd878766c0620c85e47bed0 (diff) |
add circuitpython code
Diffstat (limited to 'circuitpython/lib/adafruit_floppy/examples')
5 files changed, 1095 insertions, 0 deletions
diff --git a/circuitpython/lib/adafruit_floppy/examples/fat_test/fat_test.ino b/circuitpython/lib/adafruit_floppy/examples/fat_test/fat_test.ino new file mode 100644 index 0000000..f9ff9ff --- /dev/null +++ b/circuitpython/lib/adafruit_floppy/examples/fat_test/fat_test.ino @@ -0,0 +1,157 @@ +/* + * Print size, modify date/time, and name for all files in root. + */ + +/********************************************************************* + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! +*********************************************************************/ + +#include <SPI.h> +#include "SdFat.h" +#include <Adafruit_Floppy.h> + +// If using SAMD51, turn on TINYUSB USB stack +#if defined(ADAFRUIT_FEATHER_M4_EXPRESS) + #define DENSITY_PIN A0 // IDC 2 + #define INDEX_PIN A1 // IDC 8 + #define SELECT_PIN A2 // IDC 12 + #define MOTOR_PIN A3 // IDC 16 + #define DIR_PIN A4 // IDC 18 + #define STEP_PIN A5 // IDC 20 + #define WRDATA_PIN 13 // IDC 22 (not used during read) + #define WRGATE_PIN 12 // IDC 24 (not used during read) + #define TRK0_PIN 11 // IDC 26 + #define PROT_PIN 10 // IDC 28 + #define READ_PIN 9 // IDC 30 + #define SIDE_PIN 6 // IDC 32 + #define READY_PIN 5 // IDC 34 +#if F_CPU != 180000000L + #warning "please set CPU speed to 180MHz overclock" +#endif +#elif defined (ARDUINO_ADAFRUIT_FEATHER_RP2040) + #define DENSITY_PIN A0 // IDC 2 + #define INDEX_PIN A1 // IDC 8 + #define SELECT_PIN A2 // IDC 12 + #define MOTOR_PIN A3 // IDC 16 + #define DIR_PIN 24 // IDC 18 + #define STEP_PIN 25 // IDC 20 + #define WRDATA_PIN 13 // IDC 22 (not used during read) + #define WRGATE_PIN 12 // IDC 24 (not used during read) + #define TRK0_PIN 11 // IDC 26 + #define PROT_PIN 10 // IDC 28 + #define READ_PIN 9 // IDC 30 + #define SIDE_PIN 8 // IDC 32 + #define READY_PIN 7 // IDC 34 +#if F_CPU != 200000000L + #warning "please set CPU speed to 200MHz overclock" +#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 +#if F_CPU != 200000000L + #warning "please set CPU speed to 200MHz overclock" +#endif +#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); +Adafruit_MFM_Floppy mfm_floppy(&floppy); + +// file system object from SdFat +FatFileSystem fatfs; + +FatFile root; +FatFile file; + +//------------------------------------------------------------------------------ +void setup() { + Serial.begin(115200); + + // Wait for USB Serial + while (!Serial) { + SysCall::yield(); + } + + Serial.println("Floppy FAT directory listing demo"); + + // Init floppy drive - must spin up and find index + if (! mfm_floppy.begin()) { + Serial.println("Floppy didn't initialize - check wiring and diskette!"); + } + + // Init file system on the flash + fatfs.begin(&mfm_floppy); + + if (!root.open("/")) { + Serial.println("open root failed"); + } + // Open next file in root. + // Warning, openNext starts at the current directory position + // so a rewind of the directory may be required. + while (file.openNext(&root, O_RDONLY)) { + file.printFileSize(&Serial); + Serial.write(' '); + file.printModifyDateTime(&Serial); + Serial.write(' '); + file.printName(&Serial); + if (file.isDir()) { + // Indicate a directory. + Serial.write('/'); + } + Serial.println(); + file.close(); + } + + if (root.getError()) { + Serial.println("openNext failed"); + } else { + Serial.println("Done!"); + } +} +//------------------------------------------------------------------------------ +void loop() { + Serial.print("Read a file? >"); + String filename; + do { + filename = Serial.readStringUntil('\n'); + filename.trim(); + } while (filename.length() == 0); + + Serial.print("Reading file name: "); + Serial.println(filename); + + // Open the file for reading and check that it was successfully opened. + // The FILE_READ mode will open the file for reading. + File dataFile = fatfs.open(filename, FILE_READ); + if (!dataFile) { + Serial.println("Failed to open data file! Does it exist?"); + return; + } + // File was opened, now print out data character by character until at the + // end of the file. + Serial.println("Opened file, printing contents below:"); + while (dataFile.available()) { + // Use the read function to read the next character. + // You can alternatively use other functions like readUntil, readString, etc. + // See the fatfs_full_usage example for more details. + char c = dataFile.read(); + Serial.print(c); + } +} diff --git a/circuitpython/lib/adafruit_floppy/examples/floppy_capture_track_test/floppy_capture_track_test.ino b/circuitpython/lib/adafruit_floppy/examples/floppy_capture_track_test/floppy_capture_track_test.ino new file mode 100644 index 0000000..2861b0c --- /dev/null +++ b/circuitpython/lib/adafruit_floppy/examples/floppy_capture_track_test/floppy_capture_track_test.ino @@ -0,0 +1,112 @@ +#include <Adafruit_Floppy.h> + +// If using SAMD51, turn on TINYUSB USB stack +#if defined(ADAFRUIT_FEATHER_M4_EXPRESS) + #define DENSITY_PIN A0 // IDC 2 + #define INDEX_PIN A1 // IDC 8 + #define SELECT_PIN A2 // IDC 12 + #define MOTOR_PIN A3 // IDC 16 + #define DIR_PIN A4 // IDC 18 + #define STEP_PIN A5 // IDC 20 + #define WRDATA_PIN 13 // IDC 22 (not used during read) + #define WRGATE_PIN 12 // IDC 24 (not used during read) + #define TRK0_PIN 11 // IDC 26 + #define PROT_PIN 10 // IDC 28 + #define READ_PIN 9 // IDC 30 + #define SIDE_PIN 6 // IDC 32 + #define READY_PIN 5 // IDC 34 +#if F_CPU != 180000000L + #warning "please set CPU speed to 180MHz overclock" +#endif +#elif defined (ARDUINO_ADAFRUIT_FEATHER_RP2040) + #define DENSITY_PIN A0 // IDC 2 + #define INDEX_PIN A1 // IDC 8 + #define SELECT_PIN A2 // IDC 12 + #define MOTOR_PIN A3 // IDC 16 + #define DIR_PIN 24 // IDC 18 + #define STEP_PIN 25 // IDC 20 + #define WRDATA_PIN 13 // IDC 22 (not used during read) + #define WRGATE_PIN 12 // IDC 24 (not used during read) + #define TRK0_PIN 11 // IDC 26 + #define PROT_PIN 10 // IDC 28 + #define READ_PIN 9 // IDC 30 + #define SIDE_PIN 6 // IDC 32 + #define READY_PIN 5 // IDC 34 +#if F_CPU != 200000000L + #warning "please set CPU speed to 200MHz overclock" +#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 +#if F_CPU != 200000000L + #warning "please set CPU speed to 200MHz overclock" +#endif +#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); + +// WARNING! there are 150K max flux pulses per track! +uint8_t flux_transitions[MAX_FLUX_PULSE_PER_TRACK]; + +uint32_t time_stamp = 0; + + +void setup() { + Serial.begin(115200); + while (!Serial) delay(100); + + Serial.println("its time for a nice floppy transfer!"); + floppy.debug_serial = &Serial; + floppy.begin(); + + floppy.select(true); + if (! floppy.spin_motor(true)) { + Serial.println("Failed to spin up motor & find index pulse"); + while (1) yield(); + } + + Serial.print("Seeking track..."); + if (! floppy.goto_track(0)) { + Serial.println("Failed to seek to track"); + while (1) yield(); + } + Serial.println("done!"); +} + +void loop() { + uint32_t captured_flux = floppy.capture_track(flux_transitions, sizeof(flux_transitions)); + + Serial.print("Captured "); + Serial.print(captured_flux); + Serial.println(" flux transitions"); + + //floppy.print_pulses(flux_transitions, captured_flux); + floppy.print_pulse_bins(flux_transitions, captured_flux, 255); + + if ((millis() - time_stamp) > 1000) { + Serial.print("Ready? "); + Serial.println(digitalRead(READY_PIN) ? "No" : "Yes"); + Serial.print("Write Protected? "); + Serial.println(digitalRead(PROT_PIN) ? "No" : "Yes"); + Serial.print("Track 0? "); + Serial.println(digitalRead(TRK0_PIN) ? "No" : "Yes"); + time_stamp = millis(); + } + yield(); +} diff --git a/circuitpython/lib/adafruit_floppy/examples/greaseweazle/greaseweazle.ino b/circuitpython/lib/adafruit_floppy/examples/greaseweazle/greaseweazle.ino new file mode 100644 index 0000000..5ed7a4b --- /dev/null +++ b/circuitpython/lib/adafruit_floppy/examples/greaseweazle/greaseweazle.ino @@ -0,0 +1,525 @@ +#include <Adafruit_Floppy.h> + +#if defined(ADAFRUIT_FEATHER_M4_EXPRESS) + #define DENSITY_PIN A0 // IDC 2 + #define INDEX_PIN A1 // IDC 8 + #define SELECT_PIN A2 // IDC 12 + #define MOTOR_PIN A3 // IDC 16 + #define DIR_PIN A4 // IDC 18 + #define STEP_PIN A5 // IDC 20 + #define WRDATA_PIN 13 // IDC 22 + #define WRGATE_PIN 12 // IDC 24 + #define TRK0_PIN 11 // IDC 26 + #define PROT_PIN 10 // IDC 28 + #define READ_PIN 9 // IDC 30 + #define SIDE_PIN 6 // IDC 32 + #define READY_PIN 5 // IDC 34 +#if F_CPU != 180000000L + #warning "please set CPU speed to 180MHz overclock" +#endif + #define GW_SAMPLEFREQ (F_CPU * 11/90) // samd51 is sample rate of 22MHz at 180MHz OC +#elif defined (ARDUINO_ADAFRUIT_FEATHER_RP2040) + #define DENSITY_PIN A0 // IDC 2 + #define INDEX_PIN A1 // IDC 8 + #define SELECT_PIN A2 // IDC 12 + #define MOTOR_PIN A3 // IDC 16 + #define DIR_PIN 24 // IDC 18 + #define STEP_PIN 25 // IDC 20 + #define WRDATA_PIN 13 // IDC 22 + #define WRGATE_PIN 12 // IDC 24 + #define TRK0_PIN 11 // IDC 26 + #define PROT_PIN 10 // IDC 28 + #define READ_PIN 9 // IDC 30 + #define SIDE_PIN 8 // IDC 32 + #define READY_PIN 7 // IDC 34 +#if F_CPU != 200000000L + #warning "please set CPU speed to 200MHz overclock" +#endif + #define GW_SAMPLEFREQ 26000000UL // 26mhz for rp2040 +#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 +#if F_CPU != 200000000L + #warning "please set CPU speed to 200MHz overclock" +#endif + #define GW_SAMPLEFREQ 26000000UL // 26mhz for rp2040 +#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); + +uint32_t time_stamp = 0; + +uint8_t cmd_buffer[32], reply_buffer[128]; +uint8_t cmd_buff_idx = 0; + +#define GW_FIRMVER_MAJOR 1 +#define GW_FIRMVER_MINOR 0 +#define GW_MAXCMD 21 +#define GW_HW_MODEL 8 // Adafruity +#define GW_HW_SUBMODEL 0 // Adafruit Floppy Generic +#define GW_USB_SPEED 0 // Full Speed + +#define GW_CMD_GETINFO 0 +#define GW_CMD_GETINFO_FIRMWARE 0 +#define GW_CMD_GETINFO_BANDWIDTH 1 +#define GW_CMD_SEEK 2 +#define GW_CMD_HEAD 3 +#define GW_CMD_SETPARAMS 4 +#define GW_CMD_GETPARAMS 5 +#define GW_CMD_GETPARAMS_DELAYS 0 +#define GW_CMD_MOTOR 6 +#define GW_CMD_READFLUX 7 +#define GW_CMD_GETFLUXSTATUS 9 +#define GW_CMD_SELECT 12 +#define GW_CMD_DESELECT 13 +#define GW_CMD_SETBUSTYPE 14 +#define GW_CMD_SETBUSTYPE_IBM 1 +#define GW_CMD_SETBUSTYPE_SHUGART 2 +#define GW_CMD_SETPIN 15 +#define GW_CMD_RESET 16 +#define GW_CMD_SOURCEBYTES 18 +#define GW_CMD_SINKBYTES 19 +#define GW_CMD_GETPIN 20 + +#define GW_ACK_OK (byte)0 +#define GW_ACK_BADCMD 1 +#define GW_ACK_NOINDEX 2 +#define GW_ACK_NOTRACK0 3 +#define GW_ACK_NOUNIT 7 + +uint32_t timestamp = 0; + +void setup() { + Serial.begin(115200); + Serial1.begin(115200); + //while (!Serial) delay(100); + Serial1.println("GrizzlyWizzly"); + + floppy.debug_serial = &Serial1; + floppy.begin(); + timestamp = millis(); +} + +uint8_t get_cmd(uint8_t *buff, uint8_t maxbuff) { + int i=0; + + if (Serial.available() < 2) return 0; + buff[i++] = Serial.read(); + buff[i++] = Serial.read(); + // wait for remaining data + while (Serial.available() < (buff[1] - 2)) { + delay(1); + yield(); + } + for (; i<buff[1]; i++) { + buff[i] = Serial.read(); + } + return i; +} + +uint32_t bandwidth_timer; +float bytes_per_sec; +uint32_t transfered_bytes; +uint32_t captured_pulses; +// WARNING! there are 100K max flux pulses per track! +uint8_t flux_transitions[MAX_FLUX_PULSE_PER_TRACK]; +bool motor_state = false; // we can cache whether the motor is spinning + + +void loop() { + uint8_t cmd_len = get_cmd(cmd_buffer, sizeof(cmd_buffer)); + if (!cmd_len) { + if ((millis() > timestamp) && ((millis()-timestamp) > 3000)) { + Serial1.println("Timed out waiting for command, resetting motor"); + floppy.goto_track(0); + floppy.spin_motor(false); + motor_state = false; + floppy.select(false); + timestamp = millis(); + } + return; + } + timestamp = millis(); + + int i = 0; + uint8_t cmd = cmd_buffer[0]; + memset(reply_buffer, 0, sizeof(reply_buffer)); + reply_buffer[i++] = cmd; // echo back the cmd itself + + Serial1.printf("Got command 0x%02x\n\r", cmd); + + if (cmd == GW_CMD_GETINFO) { + Serial1.println("Get info"); + uint8_t sub_cmd = cmd_buffer[2]; + if (sub_cmd == GW_CMD_GETINFO_FIRMWARE) { + reply_buffer[i++] = GW_ACK_OK; + reply_buffer[i++] = GW_FIRMVER_MAJOR; // 1 byte + reply_buffer[i++] = GW_FIRMVER_MINOR; // 1 byte + reply_buffer[i++] = 1; // is main firm + reply_buffer[i++] = GW_MAXCMD; + reply_buffer[i++] = GW_SAMPLEFREQ & 0xFF; + reply_buffer[i++] = (GW_SAMPLEFREQ >> 8) & 0xFF; + reply_buffer[i++] = (GW_SAMPLEFREQ >> 16) & 0xFF; + reply_buffer[i++] = (GW_SAMPLEFREQ >> 24) & 0xFF; + reply_buffer[i++] = GW_HW_MODEL; + reply_buffer[i++] = GW_HW_SUBMODEL; + reply_buffer[i++] = GW_USB_SPEED; + Serial.write(reply_buffer, 34); + } + else if (sub_cmd == GW_CMD_GETINFO_BANDWIDTH) { + reply_buffer[i++] = GW_ACK_OK; + uint32_t min_bytes = transfered_bytes; + uint32_t max_bytes = transfered_bytes; + uint32_t min_usec = bandwidth_timer * 1000; + uint32_t max_usec = bandwidth_timer * 1000; + // TODO What is this math supposed to be?? + + reply_buffer[i++] = min_bytes & 0xFF; + reply_buffer[i++] = min_bytes >> 8; + reply_buffer[i++] = min_bytes >> 16; + reply_buffer[i++] = min_bytes >> 24; + reply_buffer[i++] = min_usec & 0xFF; + reply_buffer[i++] = min_usec >> 8; + reply_buffer[i++] = min_usec >> 16; + reply_buffer[i++] = min_usec >> 24; + reply_buffer[i++] = max_bytes & 0xFF; + reply_buffer[i++] = max_bytes >> 8; + reply_buffer[i++] = max_bytes >> 16; + reply_buffer[i++] = max_bytes >> 24; + reply_buffer[i++] = max_usec & 0xFF; + reply_buffer[i++] = max_usec >> 8; + reply_buffer[i++] = max_usec >> 16; + reply_buffer[i++] = max_usec >> 24; + + // TODO more? + Serial.write(reply_buffer, 34); + } + } + + else if (cmd == GW_CMD_GETPARAMS) { + Serial1.println("Get params"); + uint8_t sub_cmd = cmd_buffer[2]; + if (sub_cmd == GW_CMD_GETPARAMS_DELAYS) { + reply_buffer[i++] = GW_ACK_OK; + reply_buffer[i++] = floppy.select_delay_us & 0xFF; + reply_buffer[i++] = floppy.select_delay_us >> 8; + reply_buffer[i++] = floppy.step_delay_us & 0xFF; + reply_buffer[i++] = floppy.step_delay_us >> 8; + reply_buffer[i++] = floppy.settle_delay_ms & 0xFF; + reply_buffer[i++] = floppy.settle_delay_ms >> 8; + reply_buffer[i++] = floppy.motor_delay_ms & 0xFF; + reply_buffer[i++] = floppy.motor_delay_ms >> 8; + reply_buffer[i++] = floppy.watchdog_delay_ms & 0xFF; + reply_buffer[i++] = floppy.watchdog_delay_ms >> 8; + Serial.write(reply_buffer, 12); + } + } + + else if (cmd == GW_CMD_RESET) { + Serial1.println("Soft reset"); + floppy.soft_reset(); + reply_buffer[i++] = GW_ACK_OK; + Serial.write(reply_buffer, 2); + } + + else if (cmd == GW_CMD_SETBUSTYPE) { + uint8_t bustype = cmd_buffer[2]; + Serial1.printf("Set bus type %d\n\r", bustype); + // TODO: whats the diff??? + if (bustype == GW_CMD_SETBUSTYPE_IBM) { + reply_buffer[i++] = GW_ACK_OK; + } + else if (bustype == GW_CMD_SETBUSTYPE_SHUGART) { + floppy.bus_type = BUSTYPE_SHUGART; + reply_buffer[i++] = GW_ACK_OK; + } else { + reply_buffer[i++] = GW_ACK_BADCMD; + } + Serial.write(reply_buffer, 2); + } + + else if (cmd == GW_CMD_SEEK) { + uint8_t track = cmd_buffer[2]; + Serial1.printf("Seek track %d\n\r", track); + bool r = floppy.goto_track(track); + if (r) { + reply_buffer[i++] = GW_ACK_OK; + } else { + reply_buffer[i++] = GW_ACK_NOTRACK0; + } + Serial.write(reply_buffer, 2); + } + + else if (cmd == GW_CMD_HEAD) { + uint8_t head = cmd_buffer[2]; + Serial1.printf("Seek head %d\n\r", head); + floppy.side(head); + reply_buffer[i++] = GW_ACK_OK; + Serial.write(reply_buffer, 2); + } + + else if (cmd == GW_CMD_MOTOR) { + uint8_t unit = cmd_buffer[2]; + uint8_t state = cmd_buffer[3]; + Serial1.printf("Turn motor %d %s\n\r", unit, state ? "on" : "off"); + if (motor_state != state) { // we're in the opposite state + if (! floppy.spin_motor(state)) { + reply_buffer[i++] = GW_ACK_NOINDEX; + } else { + reply_buffer[i++] = GW_ACK_OK; + } + motor_state = state; + } else { + // our cached state is correct! + reply_buffer[i++] = GW_ACK_OK; + } + Serial.write(reply_buffer, 2); + } + + else if (cmd == GW_CMD_SELECT) { + uint8_t sub_cmd = cmd_buffer[2]; + Serial1.printf("Select drive %d\n\r", sub_cmd); + if (sub_cmd == 0) { + floppy.select(true); + reply_buffer[i++] = GW_ACK_OK; + } else { + reply_buffer[i++] = GW_ACK_NOUNIT; + } + Serial.write(reply_buffer, 2); + } + + else if (cmd == GW_CMD_DESELECT) { + Serial1.printf("Deselect drive\n\r"); + floppy.select(false); + reply_buffer[i++] = GW_ACK_OK; + Serial.write(reply_buffer, 2); + } + + else if (cmd == GW_CMD_READFLUX) { + uint32_t flux_ticks; + uint16_t revs; + flux_ticks = cmd_buffer[5]; + flux_ticks <<= 8; + flux_ticks |= cmd_buffer[4]; + flux_ticks <<= 8; + flux_ticks |= cmd_buffer[3]; + flux_ticks <<= 8; + flux_ticks |= cmd_buffer[2]; + revs = cmd_buffer[7]; + revs <<= 8; + revs |= cmd_buffer[6]; + revs -= 1; + + if (floppy.track() == -1) { + floppy.goto_track(0); + } + + Serial1.printf("Reading flux0rs on track %d: %u ticks and %d revs\n\r", floppy.track(), flux_ticks, revs); + reply_buffer[i++] = GW_ACK_OK; + Serial.write(reply_buffer, 2); + while (revs--) { + captured_pulses = floppy.capture_track(flux_transitions, sizeof(flux_transitions)); + Serial1.printf("Rev #%d captured %u pulses\n\r", revs, captured_pulses); + //floppy.print_pulse_bins(flux_transitions, captured_pulses, 64, Serial1); + // trim down extra long pulses + for (uint32_t f=0; f<captured_pulses; f++) { + if (flux_transitions[f] > 250) { + flux_transitions[f] = 250; + } + } + // Send the index opcode, which is right at the start of this data xfer + reply_buffer[0] = 0xFF; + reply_buffer[1] = 1; // index opcode + reply_buffer[2] = 0x1; + reply_buffer[3] = 0x1; + reply_buffer[4] = 0x1; + reply_buffer[5] = 0x1; // 0 are special, so we send 1 to == 0 + Serial.write(reply_buffer, 6); + + uint8_t *flux_ptr = flux_transitions; + while (captured_pulses) { + uint32_t to_send = min(captured_pulses, (uint32_t)256); + Serial.write(flux_ptr, to_send); + //Serial1.println(to_send); + flux_ptr += to_send; + captured_pulses -= to_send; + } + } + + // send a final indexop + reply_buffer[0] = 0xFF; + reply_buffer[1] = 1; // index opcode + reply_buffer[2] = 0x1; + reply_buffer[3] = 0x1; + reply_buffer[4] = 0x1; + reply_buffer[5] = 0x1; // 0 are special, so we send 1 to == 0 + Serial.write(reply_buffer, 6); + + // flush input, to account for fluxengine bug + while (Serial.available()) Serial.read(); + Serial.write((byte)0); + } + + else if (cmd == GW_CMD_GETFLUXSTATUS) { + Serial1.println("get flux status"); + reply_buffer[i++] = GW_ACK_OK; + Serial.write(reply_buffer, 2); + } + + + else if (cmd == GW_CMD_SINKBYTES) { + uint32_t numbytes = 0; + uint32_t seed = 0; + numbytes |= cmd_buffer[5]; + numbytes <<= 8; + numbytes |= cmd_buffer[4]; + numbytes <<= 8; + numbytes |= cmd_buffer[3]; + numbytes <<= 8; + numbytes |= cmd_buffer[2]; + Serial1.printf("sink numbytes %d\n\r", numbytes); + + seed |= cmd_buffer[9]; + seed <<= 8; + seed |= cmd_buffer[8]; + seed <<= 8; + seed |= cmd_buffer[7]; + seed <<= 8; + seed |= cmd_buffer[6]; + reply_buffer[i++] = GW_ACK_OK; + Serial.write(reply_buffer, 2); + yield(); + bandwidth_timer = millis(); + transfered_bytes = numbytes; + bytes_per_sec = numbytes; + + while (numbytes != 0) { + uint32_t avail = Serial.available(); + if (avail == 0) { + //Serial1.print("-"); + yield(); + continue; + } + //Serial1.printf("%lu avail, ", avail); + uint32_t to_read = min(numbytes, min((uint32_t)sizeof(reply_buffer), avail)); + //Serial1.printf("%lu to read, ", to_read); + numbytes -= Serial.readBytes((char *)reply_buffer, to_read); + //Serial1.printf("%lu remain\n\r", numbytes); + } + bandwidth_timer = millis() - bandwidth_timer; + bytes_per_sec /= bandwidth_timer; + bytes_per_sec *= 1000; + Serial1.print("Done in "); + Serial1.print(bandwidth_timer); + Serial1.print(" ms, "); + Serial1.print(bytes_per_sec); + Serial1.println(" bytes per sec"); + Serial.write(GW_ACK_OK); + yield(); + } + else if (cmd == GW_CMD_SOURCEBYTES) { + uint32_t numbytes = 0; + uint32_t seed = 0; + numbytes |= cmd_buffer[5]; + numbytes <<= 8; + numbytes |= cmd_buffer[4]; + numbytes <<= 8; + numbytes |= cmd_buffer[3]; + numbytes <<= 8; + numbytes |= cmd_buffer[2]; + Serial1.printf("source numbytes %d\n\r", numbytes); + + seed |= cmd_buffer[9]; + seed <<= 8; + seed |= cmd_buffer[8]; + seed <<= 8; + seed |= cmd_buffer[7]; + seed <<= 8; + seed |= cmd_buffer[6]; + reply_buffer[i++] = GW_ACK_OK; + Serial.write(reply_buffer, 2); + yield(); + bandwidth_timer = millis(); + bytes_per_sec = numbytes; + transfered_bytes = numbytes; + + uint32_t randnum = seed; + while (numbytes != 0) { + uint32_t to_write = min(numbytes, sizeof(reply_buffer)); + // we dont write 'just anything'! + for (uint32_t i=0; i<to_write; i++) { + reply_buffer[i] = randnum; + if (randnum & 0x01) { + randnum = (randnum >> 1) ^ 0x80000062; + } else { + randnum >>= 1; + } + } + numbytes -= Serial.write(reply_buffer, to_write); + } + bandwidth_timer = millis() - bandwidth_timer; + bytes_per_sec /= bandwidth_timer; + bytes_per_sec *= 1000; + Serial1.print("Done in "); + Serial1.print(bandwidth_timer); + Serial1.print(" ms, "); + Serial1.print(bytes_per_sec); + Serial1.println(" bytes per sec"); + } else if (cmd == GW_CMD_GETPIN) { + uint32_t pin = cmd_buffer[2]; + Serial1.printf("getpin %d\n\r", pin); + + switch(pin) { + case 26: + reply_buffer[i++] = GW_ACK_OK; + reply_buffer[i++] = digitalRead(TRK0_PIN); + break; + + default: + // unknown pin, don't pretend we did it right + reply_buffer[i++] = GW_ACK_BADCMD; + reply_buffer[i++] = 0; + } + Serial.write(reply_buffer, i); + } else if (cmd == GW_CMD_SETPIN) { + uint32_t pin = cmd_buffer[2]; + bool value = cmd_buffer[3]; + Serial1.printf("setpin %d to \n\r", pin, value); + + switch(pin) { + case 2: + pinMode(DENSITY_PIN, OUTPUT); + digitalWrite(DENSITY_PIN, value); + reply_buffer[i++] = GW_ACK_OK; + break; + + default: + // unknown pin, don't pretend we did it right + reply_buffer[i++] = GW_ACK_BADCMD; + } + + Serial.write(reply_buffer, i); + + /********** unknown ! ********/ + } else { + reply_buffer[i++] = GW_ACK_BADCMD; + Serial.write(reply_buffer, 2); + } + //Serial1.println("cmd complete!"); +}
\ No newline at end of file diff --git a/circuitpython/lib/adafruit_floppy/examples/mfm_test/mfm_test.ino b/circuitpython/lib/adafruit_floppy/examples/mfm_test/mfm_test.ino new file mode 100644 index 0000000..07206f1 --- /dev/null +++ b/circuitpython/lib/adafruit_floppy/examples/mfm_test/mfm_test.ino @@ -0,0 +1,138 @@ +#include <Adafruit_Floppy.h> + + + +// If using SAMD51, turn on TINYUSB USB stack +#if defined(ADAFRUIT_FEATHER_M4_EXPRESS) + #define DENSITY_PIN A0 // IDC 2 + #define INDEX_PIN A1 // IDC 8 + #define SELECT_PIN A2 // IDC 12 + #define MOTOR_PIN A3 // IDC 16 + #define DIR_PIN A4 // IDC 18 + #define STEP_PIN A5 // IDC 20 + #define WRDATA_PIN 13 // IDC 22 (not used during read) + #define WRGATE_PIN 12 // IDC 24 (not used during read) + #define TRK0_PIN 11 // IDC 26 + #define PROT_PIN 10 // IDC 28 + #define READ_PIN 9 // IDC 30 + #define SIDE_PIN 6 // IDC 32 + #define READY_PIN 5 // IDC 34 +#if F_CPU != 180000000L + #warning "please set CPU speed to 180MHz overclock" +#endif +#elif defined (ARDUINO_ADAFRUIT_FEATHER_RP2040) + #define DENSITY_PIN A0 // IDC 2 + #define INDEX_PIN A1 // IDC 8 + #define SELECT_PIN A2 // IDC 12 + #define MOTOR_PIN A3 // IDC 16 + #define DIR_PIN 24 // IDC 18 + #define STEP_PIN 25 // IDC 20 + #define WRDATA_PIN 13 // IDC 22 (not used during read) + #define WRGATE_PIN 12 // IDC 24 (not used during read) + #define TRK0_PIN 11 // IDC 26 + #define PROT_PIN 10 // IDC 28 + #define READ_PIN 9 // IDC 30 + #define SIDE_PIN 8 // IDC 32 + #define READY_PIN 7 // IDC 34 +#if F_CPU != 200000000L + #warning "please set CPU speed to 200MHz overclock" +#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 +#if F_CPU != 200000000L + #warning "please set CPU speed to 200MHz overclock" +#endif +#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, IBMPC360K); + + +uint32_t time_stamp = 0; + +void setup() { + pinMode(LED_BUILTIN, OUTPUT); + Serial.begin(115200); + while (!Serial) delay(100); + + 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(); + } +} + +uint8_t track = 0; +bool head = 0; +void loop() { + int32_t captured_sectors; + + Serial.printf("Seeking track %d head %d\n", track, head); + captured_sectors = mfm_floppy.readTrack(track, head); + if (captured_sectors < 0) { + Serial.println("Failed to seek to track"); + while (1) yield(); + } + + Serial.printf("Captured %d sectors\n", captured_sectors); + + Serial.print("Validity: "); + for(size_t i=0; i < mfm_floppy.sectors_per_track(); i++) { + Serial.print(mfm_floppy.track_validity[i] ? "V" : "?"); + } + Serial.print("\n"); + for(size_t sector=0; sector < mfm_floppy.sectors_per_track(); sector++) { + if (!mfm_floppy.track_validity[sector]) { + continue; // skip it, not valid + } + for(size_t i=0; i<512; i+=16) { + size_t addr = sector * 512 + i; + Serial.printf("%08x", addr); + for(size_t j=0; j<16; j++) { + Serial.printf(" %02x", mfm_floppy.track_data[addr+j]); + } + Serial.print(" | "); + for(size_t j=0; j<16; j++) { + uint8_t d = mfm_floppy.track_data[addr+j]; + if (! isprint(d)) { + d = ' '; + } + Serial.write(d); + } + Serial.print("\n"); + } + } + + // advance to next track + if (!head) { // we were on side 0 + head = 1; // go to side 1 + } else { // we were on side 1? + track = (track + 1) % mfm_floppy.tracks_per_side(); // next track! + head = 0; // and side 0 + } + + delay(1000); +}
\ No newline at end of file diff --git a/circuitpython/lib/adafruit_floppy/examples/msd_test/msd_test.ino b/circuitpython/lib/adafruit_floppy/examples/msd_test/msd_test.ino new file mode 100644 index 0000000..ab407cd --- /dev/null +++ b/circuitpython/lib/adafruit_floppy/examples/msd_test/msd_test.ino @@ -0,0 +1,163 @@ +// this example makes a lot of assumptions: MFM floppy which is already inserted +// and only reading is supported - no write yet! + +#include <Adafruit_Floppy.h> +#include "Adafruit_TinyUSB.h" + +Adafruit_USBD_MSC usb_msc; + +// If using SAMD51, turn on TINYUSB USB stack +#if defined(ADAFRUIT_FEATHER_M4_EXPRESS) + #define DENSITY_PIN A0 // IDC 2 + #define INDEX_PIN A1 // IDC 8 + #define SELECT_PIN A2 // IDC 12 + #define MOTOR_PIN A3 // IDC 16 + #define DIR_PIN A4 // IDC 18 + #define STEP_PIN A5 // IDC 20 + #define WRDATA_PIN 13 // IDC 22 (not used during read) + #define WRGATE_PIN 12 // IDC 24 (not used during read) + #define TRK0_PIN 11 // IDC 26 + #define PROT_PIN 10 // IDC 28 + #define READ_PIN 9 // IDC 30 + #define SIDE_PIN 6 // IDC 32 + #define READY_PIN 5 // IDC 34 +#if F_CPU != 180000000L + #warning "please set CPU speed to 180MHz overclock" +#endif +#elif defined (ARDUINO_ADAFRUIT_FEATHER_RP2040) + #define DENSITY_PIN A0 // IDC 2 + #define INDEX_PIN A1 // IDC 8 + #define SELECT_PIN A2 // IDC 12 + #define MOTOR_PIN A3 // IDC 16 + #define DIR_PIN 24 // IDC 18 + #define STEP_PIN 25 // IDC 20 + #define WRDATA_PIN 13 // IDC 22 (not used during read) + #define WRGATE_PIN 12 // IDC 24 (not used during read) + #define TRK0_PIN 11 // IDC 26 + #define PROT_PIN 10 // IDC 28 + #define READ_PIN 9 // IDC 30 + #define SIDE_PIN 8 // IDC 32 + #define READY_PIN 7 // IDC 34 +#if F_CPU != 200000000L + #warning "please set CPU speed to 200MHz overclock" +#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 +#if F_CPU != 200000000L + #warning "please set CPU speed to 200MHz overclock" +#endif +#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); + + +constexpr size_t SECTOR_SIZE = 512UL; +int8_t last_track_read = -1; // last cached track + +void setup() { + pinMode(LED_BUILTIN, OUTPUT); + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040) + // Manual begin() is required on core without built-in support for TinyUSB such as + // - mbed rp2040 + TinyUSB_Device_Init(0); +#endif + + // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively + usb_msc.setID("Adafruit", "Floppy Mass Storage", "1.0"); + + // Set disk size + usb_msc.setCapacity(mfm_floppy.sectors_per_track() * mfm_floppy.tracks_per_side() * FLOPPY_HEADS, SECTOR_SIZE); + + // Set callback + usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_callback); + + floppy.debug_serial = &Serial; + floppy.begin(); + // Set Lun ready + usb_msc.setUnitReady(true); + Serial.println("Ready!"); + + usb_msc.begin(); + + if (! mfm_floppy.begin()) { + Serial.println("Failed to spin up motor & find index pulse"); + while (1) yield(); + } +} + +void loop() { + delay(1000); +} + +// Callback invoked when received READ10 command. +// Copy disk's data to buffer (up to bufsize) and +// return number of copied bytes (must be multiple of block size) +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; +} + +// Callback invoked when received WRITE10 command. +// Process data in buffer to disk's storage and +// return number of written bytes (must be multiple of block size) +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; +} + +// 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"); + // nothing to do +}
\ No newline at end of file |