Keep track of disk sides (#87)
Disk side information was being dropped and thus not displayable in the UI. This plumbs the value through various formats and adds some light testing. Also fixes an issue where URL encoded hashes were not properly interpreted.
This commit is contained in:
parent
52f9c3e99e
commit
2daef8040f
|
@ -165,7 +165,7 @@ const PHASE_DELTA = [
|
|||
export interface Callbacks {
|
||||
driveLight: (drive: DriveNumber, on: boolean) => void;
|
||||
dirty: (drive: DriveNumber, dirty: boolean) => void;
|
||||
label: (drive: DriveNumber, name: string) => void;
|
||||
label: (drive: DriveNumber, name?: string, side?: string) => void;
|
||||
}
|
||||
|
||||
/** Common information for Nibble and WOZ disks. */
|
||||
|
@ -177,6 +177,8 @@ interface BaseDrive {
|
|||
volume: byte,
|
||||
/** Displayed disk name */
|
||||
name: string,
|
||||
/** (Optional) Disk side (Front/Back, A/B) */
|
||||
side?: string,
|
||||
/** Quarter track position of read/write head. */
|
||||
track: byte,
|
||||
/** Position of the head on the track. */
|
||||
|
@ -222,6 +224,7 @@ interface DriveState {
|
|||
encoding: typeof ENCODING_BITSTREAM | typeof ENCODING_NIBBLE
|
||||
volume: byte,
|
||||
name: string,
|
||||
side?: string,
|
||||
tracks: memory[],
|
||||
track: byte,
|
||||
head: byte,
|
||||
|
@ -247,6 +250,7 @@ function getDriveState(drive: Drive): DriveState {
|
|||
encoding: drive.encoding,
|
||||
volume: drive.volume,
|
||||
name: drive.name,
|
||||
side: drive.side,
|
||||
tracks: [],
|
||||
track: drive.track,
|
||||
head: drive.head,
|
||||
|
@ -279,6 +283,7 @@ function setDriveState(state: DriveState) {
|
|||
encoding: ENCODING_NIBBLE,
|
||||
volume: state.volume,
|
||||
name: state.name,
|
||||
side: state.side,
|
||||
tracks: [],
|
||||
track: state.track,
|
||||
head: state.head,
|
||||
|
@ -295,6 +300,7 @@ function setDriveState(state: DriveState) {
|
|||
encoding: ENCODING_BITSTREAM,
|
||||
volume: state.volume,
|
||||
name: state.name,
|
||||
side: state.side,
|
||||
track: state.track,
|
||||
head: state.head,
|
||||
phase: state.phase,
|
||||
|
@ -752,9 +758,10 @@ export default class DiskII implements Card {
|
|||
for (const d of DRIVE_NUMBERS) {
|
||||
const idx = d - 1;
|
||||
this.drives[idx] = setDriveState(state.drives[idx]);
|
||||
this.callbacks.label(d, state.drives[idx].name);
|
||||
const { name, side, dirty } = state.drives[idx];
|
||||
this.callbacks.label(d, name, side);
|
||||
this.callbacks.driveLight(d, this.on);
|
||||
this.callbacks.dirty(d, this.drives[idx].dirty);
|
||||
this.callbacks.dirty(d, dirty);
|
||||
}
|
||||
this.cur = this.drives[this.drive - 1];
|
||||
}
|
||||
|
@ -800,7 +807,7 @@ export default class DiskII implements Card {
|
|||
const cur = this.drives[drive - 1];
|
||||
Object.assign(cur, disk);
|
||||
this.updateDirty(drive, false);
|
||||
this.callbacks.label(drive, disk.name);
|
||||
this.callbacks.label(drive, disk.name, disk.side);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -858,9 +865,10 @@ export default class DiskII implements Card {
|
|||
const disk = createDisk(fmt, options);
|
||||
if (disk) {
|
||||
const cur = this.drives[drive - 1];
|
||||
const { name, side } = cur;
|
||||
Object.assign(cur, disk);
|
||||
this.updateDirty(drive, true);
|
||||
this.callbacks.label(drive, name);
|
||||
this.callbacks.label(drive, name, side);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -880,8 +888,9 @@ export default class DiskII implements Card {
|
|||
if (disk) {
|
||||
const cur = this.drives[drive - 1];
|
||||
Object.assign(cur, disk);
|
||||
const { name, side } = cur;
|
||||
this.updateDirty(drive, true);
|
||||
this.callbacks.label(drive, disk.name);
|
||||
this.callbacks.label(drive, name, side);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -46,6 +46,7 @@ export function createDiskFromJsonDisk(disk: JSONDisk): FloppyDisk | null {
|
|||
const fmt = disk.type;
|
||||
const readOnly = disk.readOnly;
|
||||
const name = disk.name;
|
||||
const side = disk.disk;
|
||||
|
||||
if (includes(NIBBLE_FORMATS, fmt)) {
|
||||
let trackData: memory[][];
|
||||
|
@ -53,11 +54,11 @@ export function createDiskFromJsonDisk(disk: JSONDisk): FloppyDisk | null {
|
|||
trackData = [];
|
||||
for (let t = 0; t < disk.data.length; t++) {
|
||||
trackData[t] = [];
|
||||
if (fmt == 'nib') {
|
||||
trackData[t][0] = base64_decode(disk.data[t] as string);
|
||||
if (disk.type === 'nib') {
|
||||
trackData[t][0] = base64_decode(disk.data[t]);
|
||||
} else {
|
||||
for (let s = 0; s < disk.data[t].length; s++) {
|
||||
trackData[t][s] = base64_decode(disk.data[t][s] as string);
|
||||
trackData[t][s] = base64_decode(disk.data[t][s]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,6 +72,7 @@ export function createDiskFromJsonDisk(disk: JSONDisk): FloppyDisk | null {
|
|||
volume,
|
||||
readOnly,
|
||||
name,
|
||||
side,
|
||||
data: trackData
|
||||
} as DiskOptions;
|
||||
|
||||
|
|
|
@ -18,11 +18,12 @@ import { NibbleDisk, DiskOptions, ENCODING_NIBBLE } from './types';
|
|||
* @returns A nibblized disk
|
||||
*/
|
||||
export default function createDiskFromDOS13(options: DiskOptions) {
|
||||
const { data, name, rawData, volume, readOnly } = options;
|
||||
const { data, name, side, rawData, volume, readOnly } = options;
|
||||
const disk: NibbleDisk = {
|
||||
format: 'd13',
|
||||
encoding: ENCODING_NIBBLE,
|
||||
name,
|
||||
side,
|
||||
volume,
|
||||
readOnly,
|
||||
tracks: []
|
||||
|
|
|
@ -20,11 +20,12 @@ import { NibbleDisk, DiskOptions, ENCODING_NIBBLE } from './types';
|
|||
* @returns A nibblized disk
|
||||
*/
|
||||
export default function createDiskFromDOS(options: DiskOptions): NibbleDisk {
|
||||
const { data, name, rawData, volume, readOnly } = options;
|
||||
const { data, name, side, rawData, volume, readOnly } = options;
|
||||
const disk: NibbleDisk = {
|
||||
format: 'dsk',
|
||||
encoding: ENCODING_NIBBLE,
|
||||
name,
|
||||
side,
|
||||
volume,
|
||||
readOnly,
|
||||
tracks: [],
|
||||
|
|
|
@ -18,11 +18,12 @@ import { memory } from '../types';
|
|||
* @returns A nibblized disk
|
||||
*/
|
||||
export default function createDiskFromNibble(options: DiskOptions): NibbleDisk {
|
||||
const { data, name, rawData, volume, readOnly } = options;
|
||||
const { data, name, side, rawData, volume, readOnly } = options;
|
||||
const disk: NibbleDisk = {
|
||||
format: 'nib',
|
||||
encoding: ENCODING_NIBBLE,
|
||||
name,
|
||||
side,
|
||||
volume: volume || 254,
|
||||
readOnly: readOnly || false,
|
||||
tracks: []
|
||||
|
|
|
@ -20,11 +20,12 @@ import { NibbleDisk, DiskOptions, ENCODING_NIBBLE } from './types';
|
|||
* @returns A nibblized disk
|
||||
*/
|
||||
export default function createDiskFromProDOS(options: DiskOptions) {
|
||||
const { data, name, rawData, volume, readOnly } = options;
|
||||
const { data, name, side, rawData, volume, readOnly } = options;
|
||||
const disk: NibbleDisk = {
|
||||
format: 'nib',
|
||||
encoding: ENCODING_NIBBLE,
|
||||
name,
|
||||
side,
|
||||
volume: volume || 254,
|
||||
tracks: [],
|
||||
readOnly: readOnly || false,
|
||||
|
|
|
@ -21,6 +21,7 @@ export type DriveNumber = MemberOf<typeof DRIVE_NUMBERS>;
|
|||
|
||||
export interface DiskOptions {
|
||||
name: string
|
||||
side?: string
|
||||
volume: byte
|
||||
readOnly: boolean
|
||||
data?: memory[][]
|
||||
|
@ -35,6 +36,7 @@ export interface DiskOptions {
|
|||
|
||||
export interface Disk {
|
||||
name: string
|
||||
side?: string
|
||||
readOnly: boolean
|
||||
}
|
||||
|
||||
|
@ -97,19 +99,29 @@ export type DiskFormat = MemberOf<typeof DISK_FORMATS>;
|
|||
export class JSONDiskBase {
|
||||
type: DiskFormat
|
||||
name: string
|
||||
disk?: number
|
||||
disk?: string
|
||||
category?: string
|
||||
writeProtected?: boolean
|
||||
volume: byte
|
||||
readOnly: boolean
|
||||
volume?: byte
|
||||
readOnly?: boolean
|
||||
gamepad?: GamepadConfiguration
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON Disk format with base64 encoded tracks
|
||||
* JSON Disk format with base64 encoded tracks with sectors
|
||||
*/
|
||||
|
||||
export interface Base64JSONDisk extends JSONDiskBase {
|
||||
type: Exclude<DiskFormat, 'nib'>
|
||||
encoding: 'base64'
|
||||
data: string[][]
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON Disk format with base64 encoded nibblized tracks
|
||||
*/
|
||||
|
||||
export interface Base64JSONNibbleDisk extends JSONDiskBase {
|
||||
type: 'nib'
|
||||
encoding: 'base64'
|
||||
data: string[]
|
||||
}
|
||||
|
@ -119,6 +131,7 @@ export interface Base64JSONDisk extends JSONDiskBase {
|
|||
*/
|
||||
|
||||
export interface BinaryJSONDisk extends JSONDiskBase {
|
||||
type: DiskFormat
|
||||
encoding: 'binary'
|
||||
data: memory[][]
|
||||
}
|
||||
|
@ -127,7 +140,7 @@ export interface BinaryJSONDisk extends JSONDiskBase {
|
|||
* General JSON Disk format
|
||||
*/
|
||||
|
||||
export type JSONDisk = Base64JSONDisk | BinaryJSONDisk;
|
||||
export type JSONDisk = Base64JSONDisk | Base64JSONNibbleDisk | BinaryJSONDisk;
|
||||
|
||||
/**
|
||||
* Process Disk message payloads for worker
|
||||
|
|
|
@ -297,13 +297,16 @@ export default function createDiskFromWoz(options: DiskOptions): WozDisk {
|
|||
|
||||
debug(chunks);
|
||||
|
||||
const { meta, tmap, trks } = chunks;
|
||||
|
||||
const disk: WozDisk = {
|
||||
encoding: ENCODING_BITSTREAM,
|
||||
trackMap: chunks.tmap?.trackMap || [],
|
||||
tracks: chunks.trks?.tracks || [],
|
||||
rawTracks: chunks.trks?.rawTracks || [],
|
||||
trackMap: tmap?.trackMap || [],
|
||||
tracks: trks?.tracks || [],
|
||||
rawTracks: trks?.rawTracks || [],
|
||||
readOnly: true, //chunks.info.writeProtected === 1;
|
||||
name: chunks.meta?.values['title'] || options.name
|
||||
name: meta?.values['title'] || options.name,
|
||||
side: meta?.values['side_name'] || meta?.values['side'],
|
||||
};
|
||||
|
||||
return disk;
|
||||
|
|
|
@ -844,7 +844,8 @@ function gup(name: string) {
|
|||
/** Returns the URL fragment. */
|
||||
function hup() {
|
||||
const regex = new RegExp('#(.*)');
|
||||
const results = regex.exec(window.location.hash);
|
||||
const hash = decodeURIComponent(window.location.hash);
|
||||
const results = regex.exec(hash);
|
||||
if (!results)
|
||||
return '';
|
||||
else
|
||||
|
|
|
@ -14,11 +14,11 @@ export default class DriveLights implements Callbacks {
|
|||
// document.querySelector('#disksave' + drive).disabled = !dirty;
|
||||
}
|
||||
|
||||
public label(drive: DriveNumber, label?: string) {
|
||||
public label(drive: DriveNumber, label?: string, side?: string) {
|
||||
const labelElement =
|
||||
document.querySelector('#disk-label' + drive)! as HTMLElement;
|
||||
if (label) {
|
||||
labelElement.innerText = label;
|
||||
labelElement.innerText = label + (side ? ` - ${side}` : '');
|
||||
}
|
||||
return labelElement.innerText;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import { createDiskFromJsonDisk } from 'js/formats/create_disk';
|
||||
import { testDisk } from './testdata/json';
|
||||
|
||||
describe('createDiskFromJsonDisk', () => {
|
||||
it('parses a JSON disk', () => {
|
||||
const disk = createDiskFromJsonDisk(testDisk);
|
||||
expect(disk).toEqual({
|
||||
encoding: 'nibble',
|
||||
format: 'dsk',
|
||||
name: 'Test Disk',
|
||||
readOnly: undefined,
|
||||
side: 'Front',
|
||||
volume: 254,
|
||||
tracks: expect.any(Array)
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,22 @@
|
|||
import { base64_encode } from 'js/base64';
|
||||
import { JSONDisk } from 'js/formats/types';
|
||||
|
||||
export const testDisk: JSONDisk = {
|
||||
name: 'Test Disk',
|
||||
disk: 'Front',
|
||||
category: 'Test',
|
||||
type: 'dsk',
|
||||
encoding: 'base64',
|
||||
data: []
|
||||
};
|
||||
|
||||
const sector = new Uint8Array(256);
|
||||
sector.fill(0);
|
||||
|
||||
for (let idx = 0; idx < 35; idx++) {
|
||||
const track: string[] = [];
|
||||
for (let jdx = 0; jdx < 16; jdx++) {
|
||||
track.push(base64_encode(sector));
|
||||
}
|
||||
testDisk.data.push(track);
|
||||
}
|
|
@ -108,8 +108,8 @@ const mockTRKS2 = [
|
|||
* META structures
|
||||
*/
|
||||
|
||||
const mockMETA1 = 'title\tMock Woz 1';
|
||||
const mockMETA2 = 'title\tMock Woz 2';
|
||||
const mockMETA1 = 'title\tMock Woz 1\t';
|
||||
const mockMETA2 = 'title\tMock Woz 2\nside_name\tB';
|
||||
|
||||
/**
|
||||
* Woz Version 1
|
||||
|
|
|
@ -61,6 +61,7 @@ describe('woz', () => {
|
|||
const disk = createDiskFromWoz(options) as WozDisk;
|
||||
expect(disk).toEqual({
|
||||
name: 'Mock Woz 2',
|
||||
side: 'B',
|
||||
readOnly: true,
|
||||
encoding: ENCODING_BITSTREAM,
|
||||
trackMap: mockTMAP,
|
||||
|
|
Loading…
Reference in New Issue