daily_automated

This commit is contained in:
topicchi
2023-03-17 11:40:49 +00:00
parent bfad73864c
commit 252ecca9cf
901 changed files with 399824 additions and 0 deletions

View File

@@ -0,0 +1,377 @@
# ArduinoFDC
![ArduinoFDC Setup](images/setup.jpg)
ArduinoFDC is a sketch that implements a floppy disk controller. It works with Arduino Uno, Leonardo, Nano, Pro Mini, Micro and Mega.
ArduinoFDC consists of three parts:
1. A [library](#library-functions) providing low-level functions to allow reading and writing disks at the
sector level as well as low-level formatting disks.
2. Integration of ChaN's brilliant [FatFS](http://elm-chan.org/fsw/ff/00index_e.html)
library to provide file-level functions for reading and writing files and directories
in a FAT (MS-DOS) file system and a high-level format function to initialize a FAT file system.
3. An example sketch implementing [ArduDOS](#ardudos), a (very) small DOS environment for browsing
a FAT file system as well as a [low-level disk monitor](#low-level-disk-monitor) to access sector data on the disk,
including the ability to transfer whole disks or single files via the XModem protocol.
ArduinoFDC works with double density (DD) as well as high density (HD)
disk drives. It can read, write and format 5.25" DD (360KB), 5.25" HD (1.2MB), 3.5" DD (720KB)
and 3.5" HD (1.44MB) disks.
## Wiring:
The table below shows how to wire the Arduino pins to the 34-pin IDC
connector on the floppy drive cable.
The pin numbers are defined at the top of the ArduinoFDC.cpp file. Some of them can
easily be changed whereas others are hard-coded in the controller code. Refer to
the comments at the top of the ArduinoFDC.cpp file if you want to use different
pin assignments.
Floppy Cable | Uno/Mini/Nano | Leonardo/Micro | Mega | Notes | Function
-----------------|---------------|-----------------|--------|--------|---------------
2 | 13 | 13/16 | 42 | 3,4,5 | Density select
8 | 7 | 8 | 47 | | Index
10 | 4 | 5 | 51 | 1,3 | Motor Enable A
12 | A1 | A1 | 40 | 1,3,4 | Drive Select B
14 | 5 | 6 | 50 | 1,3 | Drive Select A
16 | A0 | A0 | 41 | 1,3,4 | Motor Enable B
18 | 3 | 3 | 52 | 3 | Head Step Direction
20 | 2 | 2 | 53 | 3 | Head Step Pulse
22 | 9 | 9 | 46 | | Write Data
24 | 10 | 10 | 45 | | Write Gate
26 | 11 | 11/14 | 44 | 3 | Track 0
28 | 12 | 12/15 | 43 | 3,4 | Write Protect
30 | 8 | 4 | 48 | 2 | Read Data
32 | 6 | 7 | 49 | 3 | Side Select
1,3,5,...,31,33 | GND | GND | GND | 6 | Signal Ground
**Note 1:**
The pin numbers for the SELECT/MOTOR signals assume you are wiring to
the controller end of a floppy drive cable. If you are wiring directly
to the floppy drive, the A/B pins will be reversed (search the web
for "Floppy drive twist" for more information).
**Note 2:**
It is **highly** recommended (but not entirely necessary) to add a 1k
pull-up resistor to +5V to this signal. The Arduino's built-in pull-up
resistors are very weak (20-50k) and may not pull the signal up quickly enough.
Without the resistor you may encounter read errors (bad CRC, header not found),
especially when reading HD disks. Whether it works without the resistor will
depend on your specific drive, drive cable, connections and Arduino.
**Note 3:**
This signal can easily be moved to a different pin on the Arduino by
changing the corresponding `#define PIN_XXX ...` statement at the top
of ArduinoFDC.cpp
**Note 4:**
This signal is not essential for the functionality of the controller.
The corresponding pin can be freed by commenting out the `#define PIN_XXX ...`
statement at the top of ArduinoFDC.cpp
**Note 5:**
See section "DENSITY control signal" below.
**Note 6:**
You should be able to just pick one of the GND pins. However, some cables/drives
do not actually connect all of these to ground. If your setup does not work
it may be worth trying a different GND pin.
## Supported disk/drive types
To properly read/write data, the library must be configured for the drive/disk
combination that is being used. The drive type can be passed into the `begin` functions
or set afterwards by calling the `setDriveType` function. Supported types are:
* **ArduinoFDC::DT_5_DD**: Double-density disk in a 5.25" double-density drive
* **ArduinoFDC::DT_5_DDonHD**: Double-density disk in a 5.25" high-density drive
* **ArduinoFDC::DT_5_HD**: High-density disk in a 5.25" high-density drive
* **ArduinoFDC::DT_3_DD**: Double-density disk in a 3.5" double- or high-density drive
* **ArduinoFDC::DT_3_HD**: High-density disk in a 3.5" high-density drive
## DENSITY control signal
The function of the DENSITY control signal line between the controller and the
floppy drive is not well defined and varies between drives. Furthermore most drives
can be configured by jumpers (also called "straps"). You may want to consult the
documentation for your drive for details.
In their default configuration most 3.5" drives do not use this signal. The drive
itself determines the type of disk (DD or HD) by the presence of a hole in the disk
(on the opposite edge from the "write protect" hole). The controller must be configured
separately for the correct type (DD or HD), otherwise reading/writing will fail.
For 5.25" HD drives this signal is generally an input from the controller to the drive.
If the signal is LOW then low density mode is selected, otherwise high density is used.
However, for some drives the opposite is true. Many drives can be configured via jumpers
to select the expected levals.
The controller can be configured what to do with this signal by calling the "setDensityPinMode"
function. The following modes are supported:
* **ArduinoFDC::DP_DISCONNECT**: This configures the DENSITY pin as INPUT. It does not actually read the pin.
* **ArduinoFDC::DP_OUTPUT_LOW_FOR_HD**: This configures the DENSITY pin as an OUTPUT and sets it LOW if the disk type is HD.
* **ArduinoFDC::DP_OUTPUT_LOW_FOR_DD**: This configures the DENSITY pin as an OUTPUT and sets it LOW if the disk type is DD.
By default, the mode is set to DP_DISCONNECT for 3.5" drives and DP_OUTPUT_LOW_FOR_DD for 5.25" drives.
Another way to handle the DENSITY signal is to comment out the `#define PIN_DENSITY` line
at the top of ArduinoFDC.cpp and hard-wire the DENSITY signal from the disk drive cable
to the proper level (or leave it disconnected).
## Library functions:
To use the low-level disk access library functions (listed below), copy ArduinoFDC.h and ArduinoFDC.cpp
into your Arduino sketch directory and add `#include "ArduinoFDC.h"` to your sketch.
To use the FAT file system functions, additionally copy ff.h, ff.c, ffconf.h, diskio.h and diskio.cpp.
Then add `#include "ff.h"` and `#include "ArduinoFDC.h"` to your sketch. For documentation of the FatFS
functions refer to the [FatFS documentation](http://elm-chan.org/fsw/ff/00index_e.html).
#### `void ArduinoFDC.begin(driveAtype, driveBtype)`
Initializes the Arduino pins used by the controller. For possible drive types see
the "[Supported disk/drive types](#supported-diskdrive-types)" section above. If left out both types default to
ArduinoFDC::DT_3_HD.
#### `void ArduinoFDC.end()`
Releases the pins initialized by ArduinoFDC.begin()
#### `bool ArduinoFDC.selectDrive(byte drive)`
Selects drive A (0) or B (1) to be used for subsequent calls to
readSector/writeSector/formatDisk. Calling `begin()` selects drive A.
Returns 'false' if trying to select drive 1 when the corresponding control
pins are commented out in ArduinoFDC.cpp
#### `byte ArduinoFDC.selectedDrive()`
Returns which drive is currently selected, A (0) or B (1).
#### `void ArduinoFDC.setDriveType(driveType)`
Sets the disk/drive type for the currently selected drive. For possible drive types see
the "[Supported disk/drive types](#supported-diskdrive-types)" section above.
#### `byte ArduinoFDC.getDriveType(driveType)`
Returns the drive type of the currently selected drive.
#### `void ArduinoFDC.setDensityPinMode(mode)`
Sets the function of the DENSITY pin for the currently selected drive.
See section "[Density control signal](#density-control-signal)" above.
#### `byte ArduinoFDC.numTracks()`
Returns the number of tracks for the drive type of the currently selected drive.
#### `byte ArduinoFDC.numSectors()`
Returns the number of sectors per track for the drive type of the currently selected drive.
#### `bool ArduinoFDC.haveDisk()`
Returns true if a disk is in the drive. This is done by looking for the index
hole. If the drive motor is not currently running this haveDisk() will temporarily
turn it on.
#### `bool ArduinoFDC.isWriteProtected()`
Returns true if the disk is write protected. If no disk is in the drive then
the result may be either true or false. If the WRITE PROTECT signal is not connected
then the result is always false.
#### `void ArduinoFDC.motorOn()`
Turns the disk drive motor on.
The `readSector`/`writeSector`/`formatDisk` functions will turn the motor on **and** back off
automatically if it is not already running. Note that turning on the motor also includes
a one second delay to allow it to spin up. If you are reading/writing multiple sectors
you may want to use the `motorOn` and `motorOff` functions to manually turn the motor on
and off.
#### `void ArduinoFDC.motorOff()`
Turns the disk drive motor off.
#### `bool ArduinoFDC.motorRunning()`
Returns *true* if the disk drive motor is currently running and *false* if not.
#### `byte ArduinoFDC.readSector(byte track, byte side, byte sector, byte *buffer)`
Reads data from a sector from the flopy disk. Always reads a full sector (512 bytes).
* The "track" parameter must be in range 0..(numTracks()-1)
* The "side" parameter must either be 0 or 1
* The "sector" paramter must be in range 1..numSectors()
* The "buffer" parameter must be a pointer to a byte array of size (at least) 516 bytes.
The function returns 0 if reading succeeded. Otherwise an error code is returned
(see [Troubleshooting](#troubleshooting) section below)
**IMPORTANT:** On successful return, the sector data that was read will be in buffer[1..512] (**NOT** buffer[0..511])
#### `byte ArduinoFDC.writeSector(byte track, byte side, byte sector, byte *buffer, bool verify)`
Writes data to a sector on the floppy disk. Always writes a full sector (512 bytes).
* The "track" parameter must be in range 0..(numTracks()-1)
* The "side" parameter must either be 0 or 1
* The "sector" paramter must be in range 1..numSectors()
* The "buffer" parameter must be a pointer to a byte array of size (at least) 516 bytes.
* If the "verify" parameter is *true*, the data written will be read back and compared to what was written.
If a difference is detected then the function will return *false*.
If the "verify" parameter is *false* then no verification is done. The function may still return *false*
if the proper sector location on disk can not be found before writing.
The function returns 0 if writing succeeded. Otherwise an error code is returned
(see [Troubleshooting](#troubleshooting) section below)
**IMPORTANT:** The sector data to be written must be in buffer[1..512] (**NOT** buffer[0..511])
#### `bool ArduinoFDC.formatDisk(byte *buffer, byte from_track=0, byte to_track=255)`
Formats a floppy disk according to the format specified by the "setDriveType()" function.
A subset of tracks can be formatted by specifying the from_track and to_track parameters.
A buffer of size at least 144 bytes is needed to store temporary data during formatting.
The buffer is passed in as an argument to allow re-using other buffers in your sketch.
If you do not have a buffer to be re-used, just declare `byte buffer[144]` before calling formatDisk().
This function does **not** set up any file system on the disk. It only sets up the
low-level sector structure that allows reading and writing of sectors (and fills all
sector data with 0xF6 bytes).
The function returns 0 if formatting succeeded. Otherwise an error code is returned
(see [Troubleshooting](#troubleshooting) section below). Note that no verification of the formatted disk
is performed. The only possible error conditions are missing track 0 or index hole signals.
You can use the `readSector`function to verify that data can be read properly
after formatting.
## ArduDOS
ArduDOS is a minimal DOS that allows the user to browse the file system
on the disk and read/write files. The basic functionality is modeled on MS-DOS
with some exceptions:
1. All commands operate **only** on the currently selected drive. If two drives are
connected then use "b:" or "a:" to switch drives.
2. The working directory is **always** the top-level directory of the disk. No "cd"
command is available to change the directory. Therefore, all paths given as
arguments to commands must be relative to the top-level directory.
3. Disk changes are **not** automatically detected. After changing a disk, re-select
the current drive (e.g. "a:") to notify ArduDOS of the change.
ArduDOS is easy to access from either Arduio's serial monitor or any other
serial terminal. Set the monitor or terminal's baud rate to 115200 before connecting.
The following commands are available:
* `dir [directory]` <br/>
Show the listing of the specified directory (default is root directory).
* `type filename` <br/>
Type out the specified file to the screen (best for text files).
* `dump filename` <br/>
Dump the specified file to the screen in hexadecimal notation (best for binary files).
* `write filename` <br/>
Receive text line-by-line from the user and write it to the specified file.
Enter an empty line to finish.
* `del filename` <br/>
Delete the specified file.
* `mkdir dirname` <br/>
Create the specified directory.
* `rmdir dirname` <br/>
Remove the specified directory.
* `disktype 0/1/2/3/4` <br/>
Set the drive type of the current drive, where 0/1/2/3/4 stands for the drive type
as listed (in the same order) in section "[Supported disk/drive types](#supported-diskdrive-types)" above.
* `format [/q]` <br/>
Low-level format a disk and initialize a FAT file system. If `/q` argument is given,
performs a quick format, i.e. only resets the file system without low-level format.
* `monitor` <br/>
Enter the low-level disk monitor (see the "[Low-level disk monitor](#low-level-disk-monitor)" section below).
* `send filename` (only available if `#define USE_XMODEM` is enabled at the top of ArduinoFDC.ino)<br/>
Send the specified file via XModem protocol. See the "[XModem](#xmodem)" section below for more details.
* `receive filename` (only available if `#define USE_XMODEM` is enabled at the top of ArduinoFDC.ino)<br/>
Receive the specified file via XModem protocol. See the "[XModem](#xmodem)" section below for more details.
![ArduDOS session](images/ArduDOS.png)
## Low-level disk monitor
Like ArduDOS, the low-level monitor is easy to use with the Arduino serial monitor.
When using ArduDOS (i.e. `#define USE_ARDUDOS` is enabled at the top of ArduinoFDC.ino),
use the "monitor" command to enter the low-level monitor.
If ArduDOS is not enabled then the sketch drops directly into the disk monitor mode.
Set Arduino's serial monitor to 115200 baud to connect.
When running, the monitor will show a command prompt. Enter your command in the
serial monitor's input line and press *Enter* to execute the command.
The following commands are supported:
* `r track, sector[,side]` <br/>
Read the sector specified by track/sector/side, copy its contents to an internal
buffer and show the buffer content. If the *side* parameter is left out it defaults
to zero.
* `w track, sector[,side]` <br/>
Write the current buffer contents to the sector specified by track/sector/side
and verify the data after writing. Shows "Ok" or "Error" status after execution.
If the *side* parameter is left out it defaults to zero.
* `f` <br/>
Low-level format the disk. No file system is initialized, all sectors are filled
with 0xF6. To format and/or add a file system use the "format" command in ArduDOS
(see ArduDOS section above).
* `b` <br/>
Show the current buffer content
* `B [n]` <br/>
Fill the buffer with value *n*. If *n* is left out then fill the buffer with
bytes 0,1,2,...255,0,1,2,...255.
* `m [0/1]` <br/>
Turn the motor of the currently selected drive off/on. If the *0/1* parameter is left out
then the current motor status is shown.
* `r` <br/>
Read ALL sectors on the disk and show status Ok/Error for each one.
* `w [0/1]` <br/>
Write the current buffer content to ALL sectors on the disk. If the *0/1* parameter
is 1 then verify every sector after writing it (significantly slower).
If the *0/1* parameter is left out it defaults to 0.
* `s [0/1]` <br/>
Select drive A (0) or B (1). If the *0/1* parameter is left out then the currently
selected drive is shown.
* `t 0/1/2/3/4` <br/>
Set the drive type of the current drive, where 0/1/2/3/4 stands for the drive type
as listed (in the same order) in section "[Supported disk/drive types](#supported-diskdrive-types)" above.
* `S` (only available if `#define USE_XMODEM` is enabled at the top of ArduinoFDC.ino)</br>
Read all sectors of the current disk and transmit them via XModem protocol. See
the "[XModem](#xmodem)" section below for more details.
* `R` (only available if `#define USE_XMODEM` is enabled at the top of ArduinoFDC.ino)</br>
Receive a disk image via XModem and write it to the current disk. See
the "[XModem](#xmodem)" section below for more details.
* `x` (only if the monitor is entered from ArduDOS via the "monitor" command)</br>
Exit the monitor and return to [ArduDOS](#ardudos).
## XModem
Both ArduDOS and the low-level monitor can transmit and receive data via the XModem protocol.
If you want to use this functionality, first un-comment the `#define USE_XMODEM` setting at
the top of file ArduinoFDC.ino and re-upload the sketch.
Use a terminal program that supports XModem to send/receive the data. I recommend TeraTerm.
First start the transfer on the controller then initiate the XModem send/receive function in
the terminal program.
Note that *no error messages* can be displayed during the XModem transfers since the transfer
takes place over the same serial connection as the terminal. If the transfer stops prematurely
and nothing is shown in the terminal, pressing ENTER will get the command prompt back.
## Troubleshooting
The following table lists the error codes returned by the `readSector`, `writeSector`
and `formatDisk` functions including possible causes for each error. Pin numbers refer
to pins on the Arduino UNO.
\# | Code | Meaning | Possible causes
--|-------------|---------|----------------
0 | S_OK | No error, the operation succeeded |
1 | S_NOTINIT | The ArduinoFDC.begin() function has not been called |
2 | S_NOTREADY | No data at all is received from the disk drive | - no disk in drive <br/> - drive does not have power <br/> - pins MOTOR (4/12), SELECT (5/13), READ (8), INDEX (7) or GND not properly connected
3 | S_NOSYNC | Data is received but no sync mark can be found | - disk not formatted or not formatted for the correct density <br/> - GND pin not properly connected
4 | S_NOHEADER | Sync marks are found but either no sector header or no header with the expected track/side/sector markings | - pins STEP (2), STEPDIR (3), SIDE (6) or GND not properly connected <br/> - bad disk or unknown format <br/> - misaligned disk drive<br/> - invalid track, sector or head number given
5 | S_INVALIDID | The data record was not started by a 0xFB byte as expected | - bad disk or unknown format
6 | S_CRC | The sector data checksum is incorrect | - bad disk or unknown format <br/> - pullup resistors too weak (see note 2 in wiring section)
7 | S_NOTRACK0 | When trying to move the read head to track 0, the TRACK0 signal was not seen, even after stepping more than 80 tracks. | - pins STEP (2), STEPDIR (3), SELECT (5/13), TRACK0 (11) or GND not properly connected <br/> - drive does not have power
8 | S_VERIFY | When reading back data that was just written, the data did not match | - pins WRITEGATE (10) or WRITEDATA (9) not properly connected<br/>- disk is write protected and WRITEPROTECT (12) pin is not connected <br/> - bad disk
9 | S_READONLY | Attempting to write to a write-protected disk | - disk is write protected
## Acknowledgements
The ArduDOS functionality would not have been possible without ChaN's brilliant [FatFS](http://elm-chan.org/fsw/ff/00index_e.html) library.
The XModem communication uses the arduino-xmodem code available at https://code.google.com/archive/p/arduino-xmodem.