Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use DynamicSyncFinder for KC decoding #54

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions retroload-lib/src/decoding/decoder/kc/KcHalfPeriodProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,25 @@ import {calculateChecksum8, hex8} from '../../../common/Utils.js';
import {BlockStartNotFound, DecodingError, EndOfInput} from '../../DecoderExceptions.js';
import {formatPosition} from '../../../common/Positioning.js';
import {type FrequencyRange, isNot, avg, bitByFrequency} from '../../Frequency.js';
import {SyncFinder} from '../../SyncFinder.js';
import {type KcBlockProvider} from './KcBlockProvider.js';
import {BlockDecodingResult, BlockDecodingResultStatus} from '../BlockDecodingResult.js';
import {DynamicSyncFinder} from '../../DynamicSyncFinder.js';

const fOne: FrequencyRange = [770, 1300];
const fDelimiter: FrequencyRange = [500, 670];
const fZero: FrequencyRange = [1400, 2800];
const minIntroPeriods = 200;

/**
* Decode half periods into blocks.
*/
export class KcHalfPeriodProcessor implements KcBlockProvider {
private readonly syncFinder: SyncFinder;
private readonly syncFinder: DynamicSyncFinder;

private fOne: FrequencyRange = [0, 0];
private fZero: FrequencyRange = [0, 0];
private fDelimiter: FrequencyRange = [0, 0];

public constructor(private readonly halfPeriodProvider: HalfPeriodProvider) {
this.syncFinder = new SyncFinder(this.halfPeriodProvider, fOne, minIntroPeriods);
this.syncFinder = new DynamicSyncFinder(this.halfPeriodProvider, minIntroPeriods, 0.3);
this.updateFrequencies(1050.0);
}

public * blocks(): Generator<BlockDecodingResult> {
Expand All @@ -42,9 +44,11 @@ export class KcHalfPeriodProcessor implements KcBlockProvider {
}

private decodeBlock(): BlockDecodingResult {
if (!this.syncFinder.findSync()) {
const syncResult = this.syncFinder.findSync();
if (!syncResult) {
throw new EndOfInput();
}
this.updateFrequencies(syncResult);
const blockBegin = this.halfPeriodProvider.getPosition();
Logger.debug(`${formatPosition(blockBegin)} Reading block...`);
const block = BufferAccess.create(130);
Expand Down Expand Up @@ -77,7 +81,7 @@ export class KcHalfPeriodProcessor implements KcBlockProvider {
if (!checksumCorrect) {
Logger.error(`${formatPosition(blockEnd)} Warning: Invalid checksum for block ${blockNumber}! Read checksum: ${readChecksum}, Calculated checksum: ${calculatedChecksum}.`);
}
Logger.debug(`${formatPosition(blockEnd)} Finished reading block number 0x${hex8(blockNumber)}`);
Logger.debug(`${formatPosition(blockEnd)} Finished reading block number ${hex8(blockNumber)}`);

// return slice with block number, but not checksum
return new BlockDecodingResult(
Expand All @@ -88,21 +92,27 @@ export class KcHalfPeriodProcessor implements KcBlockProvider {
);
}

private updateFrequencies(fSync: number): void {
this.fZero = [fSync * 1.5, fSync * 4]; // = 2 * fSync
this.fOne = [fSync * 0.75, fSync * 1.5]; // = fSync
this.fDelimiter = [fSync * 0.25, fSync * 0.75]; // 0.5 * fSync
}

private readDelimiter(): void {
// check full oscillation
const oscillationValue = avg(this.halfPeriodProvider.getNext(), this.halfPeriodProvider.getNext());
if (oscillationValue === undefined || isNot(oscillationValue, fDelimiter)) {
throw new DecodingError(`${formatPosition(this.halfPeriodProvider.getPosition())} Unable to find delimiter. Read: ${oscillationValue} Hz Expected: ${fDelimiter[0]} Hz - ${fDelimiter[1]}.`);
if (oscillationValue === undefined || isNot(oscillationValue, this.fDelimiter)) {
throw new DecodingError(`${formatPosition(this.halfPeriodProvider.getPosition())} Unable to find delimiter. Read: ${oscillationValue} Hz Expected: ${this.fDelimiter[0]} Hz - ${this.fDelimiter[1]}.`);
}
}

private readBit(): boolean {
// check full oscillation
const oscillationValue = avg(this.halfPeriodProvider.getNext(), this.halfPeriodProvider.getNext());
const isOne = bitByFrequency(oscillationValue, fZero, fOne);
const isOne = bitByFrequency(oscillationValue, this.fZero, this.fOne);

if (isOne === undefined) {
throw new DecodingError(`${formatPosition(this.halfPeriodProvider.getPosition())} Unable to detect bit. Read: ${oscillationValue} Hz Expected: ${fOne[0]} Hz - ${fOne[1]} Hz or ${fZero[0]} Hz - ${fZero[1]} Hz.`);
throw new DecodingError(`${formatPosition(this.halfPeriodProvider.getPosition())} Unable to detect bit. Read: ${oscillationValue} Hz Expected: ${this.fOne[0]} Hz - ${this.fOne[1]} Hz or ${this.fZero[0]} Hz - ${this.fZero[1]} Hz.`);
}

return isOne;
Expand Down
Loading