diff --git a/apps/casette/encode.py b/apps/casette/encode.py index a0d8fa7..322f81c 100644 --- a/apps/casette/encode.py +++ b/apps/casette/encode.py @@ -20,6 +20,11 @@ class FSKWriter: self.phase = 0.0 self.samples = bytearray() + self.samples.extend(b'\0'*int(1.0*self.sample_rate)) + + def finalize(self): + self.samples.extend(b'\0'*int(1.0*self.sample_rate)) + def _tone(self, frequency: float, sample_count: int) -> None: phase_step = 2.0 * math.pi * frequency / self.sample_rate scale = int(32767 * self.amplitude) @@ -41,7 +46,7 @@ class FSKWriter: for _ in range(8): self.bit(1) self.bit(0) - self.byte(0x0f) + self.byte(0xf0) def bit(self, value: int) -> None: if value: @@ -66,6 +71,7 @@ class FSKWriter: self.byte(l&0xff) self.bytes(data) self.byte(self.chsum(data)) + self.samples.extend(b'\0'*int(0.3*self.sample_rate)) def chsum(self, data: bytes) -> int: cs = 0 @@ -93,6 +99,7 @@ def main() -> None: tones.block(0, args.input.name.encode()) + tones.finalize() with wave.open(str(output_path), "wb") as wav: wav.setnchannels(1) wav.setsampwidth(2) diff --git a/apps/casette/tape_loader.asm b/apps/casette/tape_loader.asm index f89ee11..8d8728f 100644 --- a/apps/casette/tape_loader.asm +++ b/apps/casette/tape_loader.asm @@ -4,6 +4,8 @@ .org TAPE_LOADER_ROM_ADDRESS TAPE_PORT = 0x18 +MAX_CYCLE_COUNT = 20 +MAX_BLOCK_SIZE = 0x100 STACK_TOP = 0xBFFF WORK_BASE = 0xB000 @@ -15,6 +17,10 @@ LONG_LEN = WORK_BASE + 0x04 ; byte TRESHOLD = WORK_BASE + 0x05 ; byte SHORT_COUNT = WORK_BASE + 0x06 ; byte LONG_COUNT = WORK_BASE + 0x07 ; byte +BLOCK_LENGTH = WORK_BASE + 0x08 ; word +BLOCK_NUMBER = WORK_BASE + 0x0a ; byte + +BLOCK_BUFFER = WORK_BASE + 0x100 ; MAX_BLOCK_SIZE ; #################################################3 ; Entry @@ -38,42 +44,23 @@ save_iff: ld hl,#msg_start call print_with_irqs - ; Calibrate receiver - call calibrate - - ; Print parameters + ; Read the first block + call read_block + jr z,1$ + ld hl,#msg_error_checksum ei - ld hl,#msg_short_len call print_string - ld a,(SHORT_LEN) - call print_hex8 call print_crlf - - ld hl,#msg_long_len + di + jp exit +1$: + ; Filename stored in buffer + ei + ld hl,#msg_filename call print_string - ld a,(LONG_LEN) - call print_hex8 - call print_crlf - - ld hl,#msg_treshold + ld hl,#BLOCK_BUFFER call print_string - ld a,(TRESHOLD) - call print_hex8 call print_crlf - - ld hl,#msg_short_count - call print_string - ld a,(SHORT_COUNT) - call print_hex8 - call print_crlf - - ld hl,#msg_long_count - call print_string - ld a,(LONG_COUNT) - call print_hex8 - call print_crlf - - call BIOS_FLUSH di ; #################################################3 @@ -132,6 +119,19 @@ wait_cycle: ld d,a ret +; #################################################3 +; Eat A cycles +; #################################################3 +eat_cycles: + or a,a + ret z + ld c,a +1$: + call wait_cycle + dec c + jr nz,1$ + ret + ; #################################################3 ; Average 16 cycle intervals ; Returns A = average loop count @@ -157,6 +157,10 @@ average16: ret ; #################################################3 +; Calibrate +; Gets short and long pulse lenghts and bit pulse counts +; from training sequence +; carry = succeeded ; #################################################3 calibrate: ; establish comparator state @@ -164,6 +168,9 @@ calibrate: ld d,a ; Wait for the first edge call wait_edge + ; Wait for the next edge to be back in phase with the + ; audio stream + call wait_edge ; Measure shoft pulses call average16 @@ -210,6 +217,9 @@ calibrate: cp a,c jr nc,5$ inc e + ld a,#MAX_CYCLE_COUNT + cp a,e + jp c,error_cycle_count jr 4$ 5$: ld a,e @@ -223,13 +233,181 @@ calibrate: cp a,c jr c,7$ inc e + ld a,#MAX_CYCLE_COUNT + cp a,e + jp c,error_cycle_count jr 6$ 7$: ld a,e ld (LONG_COUNT),a - + + ; First cycle of short was already consymed + ld a,(SHORT_COUNT) + dec a + call eat_cycles + + ; Consume rest of training bits + ; 6 L/S pairs then last L + ld h,#6 +8$: + ld a,(LONG_COUNT) + call eat_cycles + ld a,(SHORT_COUNT) + call eat_cycles + dec h + jr nz,8$ + ld a,(LONG_COUNT) + call eat_cycles + + ; Test calibration with sync byte + call check_sync_byte ret +error_cycle_count: + ei + ld hl,#msg_error_cycle_count + call print_string + call print_crlf + di + jp exit + + +; #################################################3 +; Read one bit +; carry = value +; #################################################3 +read_bit: + call wait_cycle + ld a,(TRESHOLD) + ld c,a + ld a,b + cp a,c + jr c,2$ + + ; zero bit +1$: + ld a,(LONG_COUNT) + dec a + call eat_cycles + or a,a ; clear carry + ret + ; one bit +2$: + ld a,(SHORT_COUNT) + dec a + call eat_cycles + scf ; set carry + ret + +; #################################################3 +; Read byte +; A = byte +; #################################################3 +read_byte: + ld e,#0 + ld h,#8 +1$: + call read_bit + rl e + dec h + jr nz,1$ + ld a,e + ret + +; #################################################3 +; Check sync byte +; carry = succeeded +; #################################################3 +check_sync_byte: + call read_byte + ld e,a + ld a,#0xf0 + cp a,e + jr z,1$ + or a,a + ret +1$: + scf + ret + +error_wrong_sync_byte: + ei + ld hl,#msg_error_sync_not_found + call print_string + call print_crlf + di + jp exit + +; #################################################3 +; Read a block +; checksum in a +; #################################################3 +read_block: + call calibrate + jp nc,error_wrong_sync_byte + + ; Get block number + call read_byte + ld (BLOCK_NUMBER),a + + ; Get block length + call read_byte + ld b,a + push bc + call read_byte + pop bc + ld c,a + ld (BLOCK_LENGTH),bc + + exx + + ld bc,(BLOCK_LENGTH) + ld hl,#BLOCK_BUFFER + +1$: + exx + call read_byte + exx + + ld (hl),a + inc hl + + dec bc + ; Check for zero + ld a,b + or a,c + jr nz,1$ + + ; Read checksum + exx + call read_byte + + ; Calculate checksum of block + ld hl,#BLOCK_BUFFER + ld bc,(BLOCK_LENGTH) + push af + xor a,a + ld e,a +2$: + ld a,e + add a,(hl) + ld e,a + inc hl + dec bc + ; Check for zero + ld a,b + or a,c + jr nz,2$ + + pop af + ; e is calculated checksum + ; a is received checksum + ld h,a + ld l,e + cp a,e + ret + + ; #################################################3 ; IO Helper functions ; #################################################3 @@ -254,6 +432,15 @@ print_crlf: ld a,#10 jp BIOS_PUTC +print_hex16: + push hl + ld a,h + call print_hex8 + pop hl + ld a,l + call print_hex8 + ret + print_hex8: push af rrca @@ -302,3 +489,20 @@ msg_short_count: msg_long_count: .ascii "Long count: " .db 0 + +msg_error_cycle_count: + .ascii "Cycle count out of bounds" + .db 0 + +msg_error_sync_not_found: + .ascii "Sync not found" + .db 0 + +msg_error_checksum: + .ascii "Checksum error" + .db 0 + +msg_filename: + .ascii "Filename: " + .db 0 + diff --git a/apps/casette/test2.wav b/apps/casette/test2.wav index 9037cd5..cb94fed 100644 Binary files a/apps/casette/test2.wav and b/apps/casette/test2.wav differ