; ; $Header: E:/HAM/EVM/RCS/fsk1200.asm 1.5 1997/10/23 13:40:14 dbraun Exp $ ; ; $Log: fsk1200.asm $ ; Revision 1.5 1997/10/23 13:40:14 dbraun ; Added blinking of Orange LED for received serial port data. ; ; Revision 1.4 1997/10/21 07:24:09 dbraun ; Yellow LED now shows status of SCI TXD line. ; ; Revision 1.3 1997/01/31 16:02:51 dbraun ; Added runtime-patchable setup of all KISS parameters. ; ; Revision 1.2 1996/12/18 08:48:17 dbraun ; Adjusted audio levels for IC821, and added Rx/Tx audio monitor ; output to right channel. ; ; Revision 1.1 1996/12/02 22:54:54 dbraun ; Initial revision ; ; ;file: FSK1200.ASM ;FSK modem for 1200 bps (1200Hz and 2200Hz tones) ;(c) 1995 Pawel Jalocha, SP9VRC ;Free license is given for radio-amateur usage _only_. ;This version of 21st July 1995 opt mu nolist include 'leonid' list title '1200bps FSK modem by SP9VRC' DCDLED macro mode ; DCD LED clr/set/chg b\mode #13,X:$FFE4 endm UpLED macro mode ;UP LED b\mode #1,X:$FFE4 endm DownLED macro mode ;DOWN LED b\mode #2,X:$FFE4 endm YellowLED macro mode ;CAT line (a yellow LED connected) b\mode #3,X:$FFE4 endm OrangeLED macro mode ; (an orange LED connected) b\mode #14,X:$FFE4 endm SampleFreq equ 9600.0 BufLen equ 64 ;sample buffer length BatchLen equ 8 ;processing batch length (must be > 1) BatchLenLog equ 3 ;BatchLen = 2 ^ BatchLenLog DCrise equ 256 ;DC rise time in samples ;the larger, the slower the DC follows RMSrise equ 256 ;RMS rise time in samples ;the larger, the slower the RMS follows AGCenable equ 0 ;automatic adjustment of the input amplification AGCstereo equ 0 ;take both or only the left channel for the AGC AGCalert equ 1 ;indicate too low or too high audio levels with the LEDs AGChold equ 512 ;AGC hold time in samples AGCfall equ 128 ;AGC fall time in samples/AGC unit (1.5dB) - default if AGCenable RMSmin equ 0.050 ;minimum and maximum RMS values for the front-end AGC else RMSmin equ 0.010 ;without AGC enabled, the AGCmin and max values serve ;only to determine when to flash the LEDs. endif RMSmax equ 0.200 ;do not make these closer than by a factor of 2 ;the RMSes are indeed MSes that without the square root BitFreq equ 2*1200.0/SampleFreq ;1200 bits per second BitLen equ @cvi(2.0/BitFreq) ;bit-length in samples CarFreq equ 2*1700.0/SampleFreq ;center freq. = 1700 Hz CarDev equ 2*0500.0/SampleFreq ;deviation = +/- 500 Hz RxLevelFollow equ 1.0/32 ;Rx Levels and DCD tracking speed (counts per bit) RxDCDindicate equ 1 ;indicate DCD status with the red LED RxClockFollow equ 1.0/512 ;Rx bit-clock recovery speed (counts per sample) ;too much is too good... RxDelayLevelProc equ BitLen*8 RxDelayBitProc equ BitLen*16+1 ;"1" corrects bit-sample timing SPY equ 0 ;for spying with SPY.EXE (disables the KISS protocol) LowFreq = (1700.0-800.0)/SampleFreq ;receive/transmit filters edges (-6dB) UppFreq = (1700.0+800.0)/SampleFreq PassFilterLen equ 64 ;receive/transmit filters length ;longer length make sharper filters ;but introduces longer delays HardLimiter equ 0 ;hard limit the signal after the filter ;and then filter the signal again ;before FM demodulator ;if this is present the InternalAGC ;makes little sense. InternalAGC equ 1 ;somehow helps (or substitutes) the CODEC-level AGC. AutoTune equ 1 ;bit threshold automatic adjustment SmoothTransmit equ 0 ;smooth transmit data before applying to the carrier RxGain equ 9.0 ;Line In (initial, if AGC enabled) gain ;Ideal for IC821 9600-baud-mode data output TxAttenuate equ 4.5 ;Attenuation factor for Tx audio MonitorAttenuate equ 10.5 ;Attenuation factor for Rx/Tx monitor audio DefTxDelay equ 20 ;default value for the txdelay (20 => 200 ms) DefTxTail equ 3 ;default value for the txtail (3 => 30 ms) DefTxDuplex equ 0 ;1 = full duplex mode ;0 = simplex mode (for normal VHF packet) DefSlotTime equ 5 ;default value of the slottime, in 10ms units. DefPersist equ 63 ;default value of the persistence, in 0-255 units. SciTimerRate equ baud ;interrupt rate of the SCI timer. This we need ;for proper scaling of txdelay and txtail. ;It is 19200 unless you have messed up the LEONID ;or the SCI itself or if the new LEONID version ;has changed the data/timer rate. ;************************************************************************* ;The actuall code (internal/external program RAM) LOMEM P:$0000 HIMEM P:$1FFF org p:user_code andi #%11110011,mr ;scaling bits = 00 move #$FFFF,m1 ;r1 to address the coeff. of all filters ;or any other linear structures move #Buffer,r2 ;for us to address the input and output samples move #<4-1,n2 move #(SciTimerRate/100),x1 ; time scale parameter mpy x0,x1,a asr a ; integer multiply correction move a0,p:kiss_pars ; product in low order word move x:(SciTimerRate/100),x1 ; time scale parameter mpy x0,x1,a asr a move a0,p:kiss_pars+2 move x:(SciTimerRate/100),x1 ; time scale parameter mpy x0,x1,a asr a move a0,p:kiss_pars+3 move x:1 .loop #BatchLen-1 ;average samples with the batch add x0,a X:(r2)+n2,x0 add x0,b X:(r2)+,x0 .endl endif add x0,a X:(r2)+n2,x0 add x0,b move x1,r2 ;restore r2 if BatchLenLog>0 .loop #BatchLenLog ;scale the average asr a asr b .endl ;now: a = left DC, b = right DC endif rnd a #(1.0-1.0/DCrise*BatchLen),y0 ;futher DC filter rnd b #1.0/DCrise*BatchLen,y1 move Y:1 .loop #BatchLen-1 ;sum up the signal squares mac x0,x0,a X:(r2)+n2,x0 mac x0,x0,b X:(r2)+,x0 .endl endif mac x0,x0,a X:(r2)+n2,x0 mac x0,x0,b move x1,r2 ;restore r2 if BatchLenLog>0 .loop #BatchLenLog ;divide by BatchLen asr a asr b .endl ;now: a = left RMS, b = right RMS endif rnd a #(1.0-1.0/RMSrise*BatchLen),y0 ; filter these RMSes to get smoother rise/fall rnd b #1.0/RMSrise*BatchLen,y1 move X:BatchLen,x0 sub x0,a #>AGCfall,x0 move a,X:$0F0F00,x0 and x0,a ;extract the gain cmp x0,a #>$010100,x0 ;already maximum ? jeq $F0F000,x0 ;if not, increment the gain by 1 move a1,x1 move Y:(r2),a1 ;and reload all the control words and x0,a n2,x0 ;in the output buffer or x1,a #<4,n2 ;make n2=4 for a moment .loop #BufLen move a1,Y:(r2)+n2 .endl move x0,n2 ;restore n2 move #0.7071,y0 ;increase the RMSes to follow the gain move X:RMSleft,x0 ;increase faster mpyr x0,y0,a asl a X:AGChold,x0 ;initialize the AGC hold count-down move x0,X:$0F0F00,x0 and x0,a #>$010100,x0 ;extract the gain bits sub x0,a #>$F0F000,x0 ;attempt to decrease the gain jcs $000010,x0 ;minimum reference value cmp x0,b tlt x0,b move b,x0 ;x0 = reference, a = FM out. cmpm x0,a ;a larger than reference ? jge $7FFFFF,a1 ;a bit tricky... move a,x1 move x1,a ScaleDone endif move #RxBitFilter,r1 ;aply the bit-filter move a,Y:(r4) ;put new data sample into the bit-filter tap clr a X:(r1)+,x0 Y:(r4)+,y0 ;filter the Tx data tap .loop #BitFilterLen-1 mac x0,y0,a X:(r1)+,x0 Y:(r4)+,y0 .endl mac x0,y0,a ;a=filtered rx data ; rep #2 asr a if SPY move a,X: positive transition jgt non-positive transition ? jgt $000020,x0 cmp x1,b ;eye open ? jge $000010,x0 jge YellowLED clr .else YellowLED set .endi ; Do the same for the Rx data line and the orange LED. btst #0,x:$ffe5 ; Port C data register .if OrangeLED clr .else OrangeLED set .endi jmp $80,x1 ;shift out 8 most significant bits mpy x0,x1,a #>$FF,x0 ori #%00000011,mr ;disable interrupts move x0,m0 and x0,a #>$100,x0 or x0,a #<$40,n0 ori #%00000100,omr ;enable the sine ROM table move a1,r0 ;put the 8 most significant bits into r0 with offset = $100 move a0,y0 ;save the remaining bits in y0 jclr #23,y0,SinTable move (r0)+ SinTable move Y:(r0+n0),x0 ;x0 = coarse cosine move Y:(r0),x1 ;x1 = coarse sine mpyr x1,y0,a #PI/256.0,y1 tfr x0,a a,x1 macr -x1,y1,a ;a = fine cosine mpyr x0,y0,b Y:(r0),x1 andi #%11111011,omr ;disable the sine ROM table tfr x1,b b,x1 macr x1,y1,b #PI*PI/2.0/65536.0,y1 ;b = fine sine mpyr y0,y0,a a,x0 andi #%11111100,mr ;enable interrupts move a,y0 mpyr y0,y1,a tfr x0,a a,y1 macr -x0,y1,a b,x1 ;a = super fine cosine macr -x1,y1,b ;b = super fine sine rts ;x,y are modified ;r0,m0,n0 are modified ;maximum error is about 0.7E-6 ;execution time 4+64+4 clock cycles ;including "jsr 'S',a cmp x0,a jne 'P',x0 putc move #>512,a Spy_copy move #>1,x0 sub x0,a move a,X: