Add support for the 83kB 5.25" Lanier format.

This commit is contained in:
David Given
2025-04-23 23:25:09 +02:00
parent d041b538bb
commit 98a28225d6
7 changed files with 66 additions and 25 deletions

View File

@@ -1,9 +1,19 @@
#ifndef AESLANIER_H
#define AESLANIER_H
/* MFM:
*
* Raw bits:
* 5 5 5 5 5 1 2 2
* 0101 0101 0101 0101 0101 0001 0010 0010
* 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1
* 0 0 0 5
* Decoded bits.
*/
#define AESLANIER_RECORD_SEPARATOR 0x55555122
#define AESLANIER_SECTOR_LENGTH 256
#define AESLANIER_RECORD_SIZE (AESLANIER_SECTOR_LENGTH + 5)
#define AESLANIER_RECORD_SIZE (AESLANIER_SECTOR_LENGTH + 4)
extern std::unique_ptr<Decoder> createAesLanierDecoder(
const DecoderProto& config);

View File

@@ -1,9 +1,19 @@
#ifndef AESLANIER5_H
#define AESLANIER5_H
#define AESLANIER5_RECORD_SEPARATOR 0x55555122
#define AESLANIER5_SECTOR_LENGTH 256
#define AESLANIER5_RECORD_SIZE (AESLANIER5_SECTOR_LENGTH + 5)
/* Format is FM:
*
* a a a a f b e f
* 1010 1010 1010 1010 1111 1011 1110 1111
* 0 0 0 0 0 0 0 0 1 1 0 1 1 0 1 1
* 0 0 d b
*
* However, note that this pattern is _not_ reversed...
*/
#define AESLANIER5_RECORD_SEPARATOR 0xaaaaaaaaaaaafbefLL
#define AESLANIER5_SECTOR_LENGTH 151
#define AESLANIER5_RECORD_SIZE (AESLANIER5_SECTOR_LENGTH + 3)
extern std::unique_ptr<Decoder> createAesLanier5Decoder(
const DecoderProto& config);

View File

@@ -12,7 +12,7 @@
static const FluxPattern SECTOR_PATTERN(32, AESLANIER5_RECORD_SEPARATOR);
/* This is actually M2FM, rather than MFM, but it our MFM/FM decoder copes fine
/* This is actually FM, rather than MFM, but it our MFM/FM decoder copes fine
* with it. */
class AesLanier5Decoder : public Decoder
@@ -29,22 +29,25 @@ public:
{
/* Skip ID mark (we know it's a AESLANIER5_RECORD_SEPARATOR). */
readRawBits(16);
readRawBits(SECTOR_PATTERN.length());
const auto& rawbits = readRawBits(AESLANIER5_RECORD_SIZE * 16);
const auto& bytes =
decodeFmMfm(rawbits).slice(0, AESLANIER5_RECORD_SIZE);
const auto& reversed = bytes.reverseBits();
_sector->logicalTrack = reversed[1];
uint8_t encodedTrack = reversed[0];
uint8_t encodedSector = reversed[1];
_sector->logicalTrack = encodedTrack >> 1;
_sector->logicalSide = 0;
_sector->logicalSector = reversed[2];
_sector->logicalSector = encodedSector;
/* Check header 'checksum' (which seems far too simple to mean much). */
{
uint8_t wanted = reversed[3];
uint8_t got = reversed[1] + reversed[2];
uint8_t wanted = reversed[2];
uint8_t got = reversed[0] + reversed[1];
if (wanted != got)
return;
}
@@ -52,9 +55,19 @@ public:
/* Check data checksum, which also includes the header and is
* significantly better. */
_sector->data = reversed.slice(1, AESLANIER5_SECTOR_LENGTH);
uint16_t wanted = reversed.reader().seek(0x101).read_le16();
uint16_t got = crc16ref(MODBUS_POLY_REF, _sector->data);
_sector->data = reversed.slice(3, AESLANIER5_SECTOR_LENGTH);
uint8_t wanted, got;
ByteReader br(_sector->data);
if ((encodedSector == 0) || (encodedSector == 8))
{
wanted = br.seek(17).read_8() + br.seek(150).read_8();
got = sumBytes(_sector->data.slice(0, 17)) + sumBytes(_sector->data.slice(18, 132));
}
else
{
wanted = br.seek(150).read_8();
got = sumBytes(_sector->data.slice(0, AESLANIER5_SECTOR_LENGTH-1));
}
_sector->status = (wanted == got) ? Sector::OK : Sector::BAD_CHECKSUM;
}
};

View File

@@ -32,15 +32,15 @@ based on what looks right. If anyone knows _anything_ about these disks,
## Options
- Format variants:
- `8" format`: use the format found on 8" disks
- `5.25" format`: use the format found on 5.25" disks
- `8`: use the format found on 8" disks
- `5`: use the format found on 5.25" disks
## Examples
To read:
- `fluxengine read aeslanier --8" format -s drive:0 -o aeslanier.img`
- `fluxengine read aeslanier --5.25" format -s drive:0 -o aeslanier.img`
- `fluxengine read aeslanier --8 -s drive:0 -o aeslanier.img`
- `fluxengine read aeslanier --5 -s drive:0 -o aeslanier.img`
## References

View File

@@ -33,6 +33,11 @@ public:
bool matches(const unsigned* intervals, FluxMatch& match) const override;
unsigned length() const
{
return _bits;
}
unsigned intervals() const override
{
return _intervals.size();

View File

@@ -14,6 +14,8 @@ of nearly £50,000 in 2018!).
processing software off twin 5.25" drive units, but apparently other software
was available.
**Note:** the following is wrong and needs to be updated.
The disk format is exceptionally weird. They used 77 track, 32 sector, single-sided
_hard_ sectored disks, where there were multiple index holes,
indicating to the hardware where the sectors start. The encoding scheme
@@ -50,7 +52,7 @@ option_group {
comment: "$formats"
option {
name: '8" format'
name: '8'
comment: 'use the format found on 8" disks'
set_by_default: true
@@ -75,8 +77,8 @@ option_group {
}
option {
name: '5.25" format'
comment: 'use the format found on 5.25" disks'
name: '83'
comment: '83kB 5.25" 35-track 16-sector SSSD'
config {
decoder {

View File

@@ -246,12 +246,13 @@ void FluxViewerControl::OnPaint(wxPaintEvent&)
dc.SetTextForeground(*wxBLACK);
for (auto& sector : trackdata->sectors)
{
nanoseconds_t sr = sector->dataEndTime;
if (!sr)
sr = sector->headerEndTime;
nanoseconds_t tl = sector->headerStartTime;
nanoseconds_t tr = sector->dataEndTime;
if (!tl && !sector->headerEndTime)
tl = sector->dataStartTime;
int sp = sector->headerStartTime / _nanosecondsPerPixel;
int sw = (sr - sector->headerStartTime) / _nanosecondsPerPixel;
int sp = tl / _nanosecondsPerPixel;
int sw = (tr - tl) / _nanosecondsPerPixel;
wxRect rect = {x + sp, t1y - ch2, sw, ch};
bool hovered = rect.Contains(_mouseX, _mouseY);