mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-24 11:11:02 -07:00
Compare commits
2 Commits
dcae381973
...
aeslanier
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98a28225d6 | ||
|
|
d041b538bb |
@@ -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);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
syntax = "proto2";
|
||||
|
||||
message AesLanierDecoderProto {}
|
||||
message AesLanier5DecoderProto {}
|
||||
|
||||
|
||||
21
arch/aeslanier5/aeslanier5.h
Normal file
21
arch/aeslanier5/aeslanier5.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef AESLANIER5_H
|
||||
#define AESLANIER5_H
|
||||
|
||||
/* 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);
|
||||
|
||||
#endif
|
||||
4
arch/aeslanier5/aeslanier5.proto
Normal file
4
arch/aeslanier5/aeslanier5.proto
Normal file
@@ -0,0 +1,4 @@
|
||||
syntax = "proto2";
|
||||
|
||||
message AesLanierDecoderProto {}
|
||||
|
||||
78
arch/aeslanier5/decoder.cc
Normal file
78
arch/aeslanier5/decoder.cc
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "lib/core/globals.h"
|
||||
#include "lib/decoders/decoders.h"
|
||||
#include "aeslanier5.h"
|
||||
#include "lib/core/crc.h"
|
||||
#include "lib/data/fluxmap.h"
|
||||
#include "lib/data/fluxmapreader.h"
|
||||
#include "lib/data/fluxpattern.h"
|
||||
#include "lib/data/sector.h"
|
||||
#include "lib/core/bytes.h"
|
||||
#include "fmt/format.h"
|
||||
#include <string.h>
|
||||
|
||||
static const FluxPattern SECTOR_PATTERN(32, AESLANIER5_RECORD_SEPARATOR);
|
||||
|
||||
/* This is actually FM, rather than MFM, but it our MFM/FM decoder copes fine
|
||||
* with it. */
|
||||
|
||||
class AesLanier5Decoder : public Decoder
|
||||
{
|
||||
public:
|
||||
AesLanier5Decoder(const DecoderProto& config): Decoder(config) {}
|
||||
|
||||
nanoseconds_t advanceToNextRecord() override
|
||||
{
|
||||
return seekToPattern(SECTOR_PATTERN);
|
||||
}
|
||||
|
||||
void decodeSectorRecord() override
|
||||
{
|
||||
/* Skip ID mark (we know it's a AESLANIER5_RECORD_SEPARATOR). */
|
||||
|
||||
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();
|
||||
|
||||
uint8_t encodedTrack = reversed[0];
|
||||
uint8_t encodedSector = reversed[1];
|
||||
|
||||
_sector->logicalTrack = encodedTrack >> 1;
|
||||
_sector->logicalSide = 0;
|
||||
_sector->logicalSector = encodedSector;
|
||||
|
||||
/* Check header 'checksum' (which seems far too simple to mean much). */
|
||||
|
||||
{
|
||||
uint8_t wanted = reversed[2];
|
||||
uint8_t got = reversed[0] + reversed[1];
|
||||
if (wanted != got)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check data checksum, which also includes the header and is
|
||||
* significantly better. */
|
||||
|
||||
_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;
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<Decoder> createAesLanier5Decoder(const DecoderProto& config)
|
||||
{
|
||||
return std::unique_ptr<Decoder>(new AesLanier5Decoder(config));
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "lib/config/config.h"
|
||||
#include "arch/agat/agat.h"
|
||||
#include "arch/aeslanier/aeslanier.h"
|
||||
#include "arch/aeslanier5/aeslanier5.h"
|
||||
#include "arch/amiga/amiga.h"
|
||||
#include "arch/apple2/apple2.h"
|
||||
#include "arch/brother/brother.h"
|
||||
@@ -70,6 +71,7 @@ std::unique_ptr<Decoder> Arch::createDecoder(const DecoderProto& config)
|
||||
decoders = {
|
||||
{DecoderProto::kAgat, createAgatDecoder },
|
||||
{DecoderProto::kAeslanier, createAesLanierDecoder },
|
||||
{DecoderProto::kAeslanier5, createAesLanier5Decoder },
|
||||
{DecoderProto::kAmiga, createAmigaDecoder },
|
||||
{DecoderProto::kApple2, createApple2Decoder },
|
||||
{DecoderProto::kBrother, createBrotherDecoder },
|
||||
|
||||
@@ -5,6 +5,7 @@ proto(
|
||||
name="proto",
|
||||
srcs=[
|
||||
"./aeslanier/aeslanier.proto",
|
||||
"./aeslanier5/aeslanier5.proto",
|
||||
"./agat/agat.proto",
|
||||
"./amiga/amiga.proto",
|
||||
"./apple2/apple2.proto",
|
||||
@@ -36,6 +37,7 @@ cxxlibrary(
|
||||
srcs=[
|
||||
"./arch.cc",
|
||||
"./aeslanier/decoder.cc",
|
||||
"./aeslanier5/decoder.cc",
|
||||
"./agat/agat.cc",
|
||||
"./agat/decoder.cc",
|
||||
"./agat/encoder.cc",
|
||||
@@ -83,6 +85,7 @@ cxxlibrary(
|
||||
"arch/f85/f85.h": "./f85/f85.h",
|
||||
"arch/mx/mx.h": "./mx/mx.h",
|
||||
"arch/aeslanier/aeslanier.h": "./aeslanier/aeslanier.h",
|
||||
"arch/aeslanier5/aeslanier5.h": "./aeslanier5/aeslanier5.h",
|
||||
"arch/northstar/northstar.h": "./northstar/northstar.h",
|
||||
"arch/brother/data_gcr.h": "./brother/data_gcr.h",
|
||||
"arch/brother/brother.h": "./brother/brother.h",
|
||||
|
||||
@@ -31,13 +31,16 @@ based on what looks right. If anyone knows _anything_ about these disks,
|
||||
|
||||
## Options
|
||||
|
||||
(no options)
|
||||
- Format variants:
|
||||
- `8`: use the format found on 8" disks
|
||||
- `5`: use the format found on 5.25" disks
|
||||
|
||||
## Examples
|
||||
|
||||
To read:
|
||||
|
||||
- `fluxengine read aeslanier -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -2,6 +2,7 @@ syntax = "proto2";
|
||||
|
||||
import "arch/agat/agat.proto";
|
||||
import "arch/aeslanier/aeslanier.proto";
|
||||
import "arch/aeslanier5/aeslanier5.proto";
|
||||
import "arch/amiga/amiga.proto";
|
||||
import "arch/apple2/apple2.proto";
|
||||
import "arch/brother/brother.proto";
|
||||
@@ -22,7 +23,7 @@ import "arch/zilogmcz/zilogmcz.proto";
|
||||
import "lib/fluxsink/fluxsink.proto";
|
||||
import "lib/config/common.proto";
|
||||
|
||||
//NEXT: 33
|
||||
//NEXT: 34
|
||||
message DecoderProto {
|
||||
optional double pulse_debounce_threshold = 1 [default = 0.30,
|
||||
(help) = "ignore pulses with intervals shorter than this, in fractions of a clock"];
|
||||
@@ -37,6 +38,7 @@ message DecoderProto {
|
||||
|
||||
oneof format {
|
||||
AesLanierDecoderProto aeslanier = 7;
|
||||
AesLanier5DecoderProto aeslanier5 = 33;
|
||||
AgatDecoderProto agat = 28;
|
||||
AmigaDecoderProto amiga = 8;
|
||||
Apple2DecoderProto apple2 = 13;
|
||||
|
||||
@@ -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
|
||||
@@ -46,21 +48,56 @@ image_writer {
|
||||
type: IMAGETYPE_IMG
|
||||
}
|
||||
|
||||
decoder {
|
||||
aeslanier {}
|
||||
}
|
||||
option_group {
|
||||
comment: "$formats"
|
||||
|
||||
layout {
|
||||
format_type: FORMATTYPE_80TRACK
|
||||
tracks: 77
|
||||
sides: 1
|
||||
layoutdata {
|
||||
sector_size: 256
|
||||
physical {
|
||||
start_sector: 0
|
||||
count: 32
|
||||
option {
|
||||
name: '8'
|
||||
comment: 'use the format found on 8" disks'
|
||||
set_by_default: true
|
||||
|
||||
config {
|
||||
decoder {
|
||||
aeslanier {}
|
||||
}
|
||||
|
||||
layout {
|
||||
format_type: FORMATTYPE_80TRACK
|
||||
tracks: 77
|
||||
sides: 1
|
||||
layoutdata {
|
||||
sector_size: 256
|
||||
physical {
|
||||
start_sector: 0
|
||||
count: 32
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
option {
|
||||
name: '83'
|
||||
comment: '83kB 5.25" 35-track 16-sector SSSD'
|
||||
|
||||
config {
|
||||
decoder {
|
||||
aeslanier5 {}
|
||||
}
|
||||
|
||||
layout {
|
||||
format_type: FORMATTYPE_40TRACK
|
||||
tracks: 35
|
||||
sides: 1
|
||||
layoutdata {
|
||||
sector_size: 150
|
||||
physical {
|
||||
start_sector: 0
|
||||
count: 16
|
||||
skew: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user