aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/lib/adafruit_floppy/src/Adafruit_MFM_Floppy.cpp
blob: 6128a2015584d0b7a31fc09bdd459a385dc07e9d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#include <Adafruit_Floppy.h>

extern uint32_t T2_5, T3_5;

/**************************************************************************/
/*!
    @brief  Instantiate an MFM-formatted floppy
    @param  floppy An Adafruit_Floppy object that has the pins defined
    @param  format What kind of format we will be parsing out - we DO NOT
   autodetect!
*/
/**************************************************************************/
Adafruit_MFM_Floppy::Adafruit_MFM_Floppy(Adafruit_Floppy *floppy,
                                         adafruit_floppy_disk_t format) {
  _floppy = floppy;
  _format = format;

  // different formats have different 'hardcoded' sectors and tracks
  if (_format == IBMPC1440K) {
    _sectors_per_track = MFM_IBMPC1440K_SECTORS_PER_TRACK;
    _tracks_per_side = FLOPPY_IBMPC_HD_TRACKS;
    T2_5 = T2_5_IBMPC_HD;
    T3_5 = T3_5_IBMPC_HD;
  } else if (_format == IBMPC360K) {
    _sectors_per_track = MFM_IBMPC360K_SECTORS_PER_TRACK;
    _tracks_per_side = FLOPPY_IBMPC_DD_TRACKS;
    T2_5 = T2_5_IBMPC_DD;
    T3_5 = T3_5_IBMPC_DD;
  }
}

/**************************************************************************/
/*!
    @brief  Initialize and spin up the floppy drive
    @returns True if we were able to spin up and detect an index track
*/
/**************************************************************************/
bool Adafruit_MFM_Floppy::begin(void) {
  if (!_floppy)
    return false;
  _floppy->begin();

  // now's the time to tweak settings
  if (_format == IBMPC360K) {
    _floppy->step_delay_us = 65000UL; // lets make it max 65ms not 10ms?
    _floppy->settle_delay_ms = 50;    // 50ms not 15
  }

  _floppy->select(true);

  return _floppy->spin_motor(true);
}

/**************************************************************************/
/*!
    @brief  Spin down and deselect the motor and drive
    @returns True always
*/
/**************************************************************************/
bool Adafruit_MFM_Floppy::end(void) {
  _floppy->spin_motor(false);
  _floppy->select(false);
  return true;
}

/**************************************************************************/
/*!
    @brief   Quick calculator for expected max capacity
    @returns Size of the drive in bytes
*/
/**************************************************************************/
uint32_t Adafruit_MFM_Floppy::size(void) {
  return (uint32_t)_tracks_per_side * FLOPPY_HEADS * _sectors_per_track *
         MFM_BYTES_PER_SECTOR;
}

/**************************************************************************/
/*!
    @brief  Read one track's worth of data and MFM decode it
    @param  track track number, 0 to whatever is the  max tracks for the given
    @param  head which side to read, false for side 1, true for side 2
    format during instantiation (e.g. 40 for DD, 80 for HD)
    @returns Number of sectors captured, or -1 if we couldn't seek
*/
/**************************************************************************/
int32_t Adafruit_MFM_Floppy::readTrack(uint8_t track, bool head) {

  // Serial.printf("\tSeeking track %d head %d...", track, head);
  if (!_floppy->goto_track(track)) {
    // Serial.println("failed to seek to track");
    return -1;
  }
  _floppy->side(head);
  // Serial.println("done!");
  uint32_t captured_sectors =
      _floppy->read_track_mfm(track_data, _sectors_per_track, track_validity);
  /*
    Serial.print("Captured %d sectors", captured_sectors);

    Serial.print("Validity: ");
    for(size_t i=0; i<MFM_SECTORS_PER_TRACK; i++) {
      Serial.print(track_validity[i] ? "V" : "?");
    }
  */
  return captured_sectors;
}

//--------------------------------------------------------------------+
// SdFat BaseBlockDriver API
// A block is 512 bytes
//--------------------------------------------------------------------+

/**************************************************************************/
/*!
    @brief  Read a 512 byte block of data, may used cached data
    @param  block Block number, will be split into head and track based on
    expected formatting
    @param  dst Destination buffer
    @returns True on success
*/
/**************************************************************************/
bool Adafruit_MFM_Floppy::readBlock(uint32_t block, uint8_t *dst) {
  uint8_t track = block / (FLOPPY_HEADS * _sectors_per_track);
  uint8_t head = (block / _sectors_per_track) % FLOPPY_HEADS;
  uint8_t subsector = block % _sectors_per_track;

  // Serial.printf("\tRead request block %d\n", block);
  if ((track * FLOPPY_HEADS + head) != _last_track_read) {
    // oof it is not cached!

    if (readTrack(track, head) == -1) {
      return false;
    }

    _last_track_read = track * FLOPPY_HEADS + head;
  }

  if (!track_validity[subsector]) {
    // Serial.println("subsector invalid");
    return false;
  }
  // Serial.println("OK!");
  memcpy(dst, track_data + (subsector * MFM_BYTES_PER_SECTOR),
         MFM_BYTES_PER_SECTOR);

  return true;
}

/**************************************************************************/
/*!
    @brief  Read multiple 512 byte block of data, may used cached data
    @param  block Starting block number, will be split into head and track based
   on expected formatting
    @param  dst Destination buffer
    @param  nb Number of blocks to read
    @returns True on success
*/
/**************************************************************************/
bool Adafruit_MFM_Floppy::readBlocks(uint32_t block, uint8_t *dst, size_t nb) {
  // read each block one by one
  for (size_t blocknum = 0; blocknum < nb; blocknum++) {
    if (!readBlock(block + blocknum, dst + (blocknum * MFM_BYTES_PER_SECTOR)))
      return false;
  }
  return true;
}

/**************************************************************************/
/*!
    @brief  Write a 512 byte block of data NOT IMPLEMENTED YET
    @param  block Block number, will be split into head and track based on
    expected formatting
    @param  src Source buffer
    @returns True on success, false if failed or unimplemented
*/
/**************************************************************************/
bool Adafruit_MFM_Floppy::writeBlock(uint32_t block, const uint8_t *src) {
  Serial.printf("Writing block %d\n", block);
  (void *)src;
  return false;
}

/**************************************************************************/
/*!
    @brief  Write multiple 512 byte blocks of data NOT IMPLEMENTED YET
    @param  block Starting lock number, will be split into head and track based
   on expected formatting
    @param  src Source buffer
    @param  nb Number of consecutive blocks to write
    @returns True on success, false if failed or unimplemented
*/
/**************************************************************************/
bool Adafruit_MFM_Floppy::writeBlocks(uint32_t block, const uint8_t *src,
                                      size_t nb) {
  Serial.printf("Writing %d blocks %d\n", nb, block);
  (void *)src;
  return false;
}

/**************************************************************************/
/*!
    @brief  Sync written blocks NOT IMPLEMENTED YET
    @returns True on success, false if failed or unimplemented
*/
/**************************************************************************/
bool Adafruit_MFM_Floppy::syncBlocks() { return false; }