; irg.m65: CC65 functions for the infrared gateway (IRG) Version 0.1 ; ------------------------------------------------------------------ ; Copyright 1994 David Deaven version 0.1 ; Permission to use, copy, and distribute this code is granted ; provided that it is not used for commercial applications. ; David Deaven -- deaven@iastate.edu ; ; This ra65 library package provides access to an infrared gateway, ; or IRG, connected to an Atari 400/800/XL/XE 8-bit computer. A ; description of how to build the IRG circuit, which simply plugs into ; a joystick port, can be found in the file README.HARDWARE included ; with this distribution. The functions defined here are: ; ; void IRGinit(int sample, int ton, int toff, int repeat, ; int tonmin, int toffmax, int qtime, int totime) ; int IRGread(char *buffer, int size) = # bytes returned ; int IRGwrite(char *buffer) = 0, or 1 if IRG is active ; ; See the file README for more information, and the C program ; irgdemo.c which demonstrates the use of these functions. ; ------------------------------------------------------------------ rdblen = 128 ; internal read buffer length (<256) ; Some device things that the standard CC65 headers don't have PACTL = $D302 PORTA = $D300 TRIG0 = $D010 GRACTL = $D01D ; ------------------------------------------------------------------ ; Start the vertical blank service routine and set parameters. ; ; void IRGinit(int sample, int ton, int toff, int repeat, ; int tonmin, int toffmax, int qtime, int totime) ; _irginit: jsr enterfun ; get all arguments ldy #16 jsr ldaxysp sta sample ldy #14 jsr ldaxysp sta ton ldy #12 jsr ldaxysp sta toff ldy #10 jsr ldaxysp sta repeat ldy #8 jsr ldaxysp sta tonmin ldy #6 jsr ldaxysp sta toffmax ldy #4 jsr ldaxysp sta qtime ldy #2 jsr ldaxysp sta totime LDA #%00111001 ; set up PIA STA PACTL ; output bit A0 LDA #%00000001 STA PORTA LDA #%00111101 STA PACTL LDA #0 ; turn IRG output off STA PORTA LDA #0 STA nread ; clear read buffer sta nwrite sta rdbuf sta irgstat ; no invalid events LDA #6 ; new immediate VBLANK LDX #VImm^ LDY #VImm\ JSR SETVBV LDA #7 ; new deferred VBLANK LDX #VBlank^ LDY #VBlank\ JSR SETVBV jmp exitfun ; ------------------------------------------------------------------ ; Read the IRG buffer safely into a user buffer. ; ; int IRGread(char *buffer, int size) = # bytes returned ; _irgread: jsr enterfun ldy #2 ; get arguments jsr ldaxysp sta blen ldy #4 jsr ldaxysp jsr psave sta ptr1 ; set to point at buffer stx ptr1+1 LDX nread ldy #0 ; # bytes transferred fine: cpx nwrite ; end of buffer? beq rddone LDA rdbuf,x ; transfer one byte STA (ptr1),Y iny INX CPX #rdblen BNE skip1 ldx #0 skip1: cmp #0 ; end of buffer? bne skip2 dey ; zero byte is meaningless, remove jmp rddone skip2: cpy blen ; buffer overflow? bmi fine rddone: stx nread ; update next read position tya ; return # bytes ldy irgstat ; bad buffer? beq rddo2 lda #0 rddo2: ldx #0 jsr prest jmp exitfun ; ------------------------------------------------------------------ ; Send a buffer out (null-terminated string). ; ; int IRGwrite(char *buffer) = 0, or 1 if IRG is active ; _irgwrite: jsr enterfun ldy #2 jsr ldaxysp jsr psave sta ptr1 stx ptr1+1 LDA CRITIC ; is anything else BEQ ok2 ; going on? ldax #1 ; if so, don't send jsr prest jmp exitfun ok2: JSR IStop ; stop DMA etc. lda repeat sta nwr wr0: LDY #$FF LDX #8 loop: INY LDA (ptr1),Y BEQ eot STA bytbuf sloop: LDA #0 ROL bytbuf ROL A STA PORTA TXA LDX ton loop1: JSR DELAY DEX BNE loop1 STX PORTA LDX toff loop0: JSR DELAY DEX BNE loop0 TAX DEX BNE sloop LDX #8 BNE loop eot: ldx qtime eot8: jsr delay dex bne eot8 dec nwr bne wr0 JSR IStart ; restart DMA etc ldax #0 jsr prest jmp exitfun nwr: .byte 0 ; ------------------------------------------------------------------ ; Immediate vertical blank code. Unlike the Atari OS code, if CRITIC is ; set, _nothing_ gets done. This state should not be maintained too ; long, but for the length of an IR packet it's OK. ; VImm: LDA CRITIC BEQ cont JMP XITVBV ; outta here cont: JMP $E45F ; OS Stage 1 ; ------------------------------------------------------------------ ; Deferred vertical blank code. Examine TRIG0 for new IR input, ; catch all input by keeping TRIG0 in hardware latch mode. When TRIG0 has ; been low, display DMA is turned off, CRITIC is enabled, and this routine ; becomes the "mainline" code with the interrupt return info still on the ; stack. An attempt is made to read a valid code into the buffer, then ; control is returned to the interrupted code. ; VBlank: LDA CRITIC BNE leave ; never happens? LDA TRIG0 BEQ rec ; IRG has been active LDA #%100 STA GRACTL ; set TRIG0 latch leave: JMP XITVBV ; outta here rec: JSR IStop LDA #0 STA GRACTL ; clear TRIG0 latch still: LDX qtime ; detect record gap LDA #1 ; IR input bit is LSB wait: JSR Delay BIT TRIG0 BEQ still ; (input not quiet) DEX BNE wait ; we'll wait as long as it takes! LDY totime ; looking for a "1" bit to start retry: LDX qtime mark: BIT TRIG0 BEQ st0 ; got "1", go for it JSR Delay DEX BNE mark DEY BNE retry JMP exit ; time-out, no harm done st0: LDY #8 ; bit counter start: LDX #0 wton: JSR Delay INX BIT TRIG0 BEQ wton CPX tonmin ; bit long enough? BPL okbit LDA #1 ; bad "1" bit STA irgstat JMP exit okbit: SEC ; store a "1" bit JSR store LDX #0 ; wait for "0" to end wtoff: JSR Delay INX BEQ eott ; never? forced EOT (very long "0") BIT TRIG0 BNE wtoff CPX qtime ; the space is EOT? BPL eott CPX toffmax ; a "0" bit? BMI start ; normal space CLC ; store a "0" bit JSR store JMP start eott: CPY #8 ; normal EOT BEQ done ; last data byte has been written CLC JSR store ; pad buffer w/zeroes JMP eott done: ldy #8 ; terminate buffer with zero pad: clc jsr store cpy #8 bne pad LDA #0 STA irgstat ; normal operation JMP exit ; ------------------------------------------------------------------ ; Store bits MSB to LSB in memory at rdbuf ; ; C = bit (0/1) ; X = not saved ; Y = #bits in bytbuf (0-7), 8==0 ; A = saved ; store: ROL bytbuf ; store byte pre-buffer DEY BEQ byte RTS byte: TAX ; save A LDA bytbuf LDY nwrite STA rdbuf,Y INY cpy #rdblen bne byte1 ldy #0 byte1: cpy nread ; buffer full? beq over sty nwrite LDY #8 ; new byte TXA RTS over: dey ; back off one cpy #$ff bne over1 ldy #rdblen dey over1: lda #0 sta rdbuf,y ; insert artificial terminator sty nwrite PLA ; pop "jsr store" return address PLA LDA #2 ; buffer overrun... STA irgstat ; ...fall through to exit exit: JSR IStart ; restart DMA etc. JMP XITVBV ; outta here ; ------------------------------------------------------------------ ; Wait one delay time, saving A, X, Y ; time = (20+5*sample) clock pds ; Delay: PHA ; 3 cycles TXA ; 2 LDX sample ; 3 dloop: DEX ; 2 BNE dloop ; 3 TAX ; 2 PLA ; 4 RTS ; 6 ; ------------------------------------------------------------------ IStop: LDA #0 STA DMACTL ; prevent DMA LDA #1 STA CRITIC RTS IStart: LDA SDMCTL STA DMACTL ; enable DMA LDA #0 STA CRITIC RTS ; ------------------------------------------------------------------ psave: ldy ptr1 ; save system pointer sty svp1 ldy ptr1+1 sty svp1+1 rts prest: ldy svp1 ; restore system pointer sty ptr1 ldy svp1+1 sty ptr1+1 rts svp1: .word 0 ; ------------------------------------------------------------------ nread: .byte 0 nwrite: .byte 0 sample: .byte 2 ton: .byte 20 toff: .byte 20 tonmin: .byte 10 toffmax: .byte 30 qtime: .byte 100 totime: .byte 25 repeat: .byte 3 bytbuf: .byte 0 blen: .byte 0 rdbuf: .blkb rdblen irgstat: .word 0 .globl _irginit .globl _irgread .globl _irgwrite