;FILE: Q15X25.ASM, Last edition: 22nd August 1995 ;new design for the multi-tone, QPSK modem. ;(c) 1995 Pawel Jalocha, SP9VRC, ;e-mail: jalocha@chopin.ifj.edu.pl, sp9vrc@gw.sp9kby.ampr.org ; ;Features: ; - 15 carriers spaced by 125 Hz modulated with DQPSK ; (differential 4-level phase keying) at 83.33 baud ; - Total raw data rate 2500 bps ; - Two phase preamble for frequency shift correction ; and fast symbol sync. ; - Forward Error Correction: two simple schemes with different levels ; of data redundancy ; - Time/frequency diversity (interleave) to de-localize burst errors ; ;This software is not to be used for purposes other than amateur radio ;without a written permision of the author. ;Usage for profit or in commercial/military products is explicitly prohibited. nolist include 'leonid' list scsjmp short ;force short jumps for .if/.endi, .while/.endw, etc. title 'New multi-tone QPSK modem by SP9VRC' ;************************************************************************* ;compile-time constants EVM56K equ 0 ;0 => DSPCARD4 ;1 => EVM56002 SampleFreq equ 8000.0 DecimateRatio equ 3 ;decimation ratio ;the maximum bandwidth of the anti-alias filter: ;sampled bandwidth = 8000/3 Hz AliasFilterLen equ 64 ;the length of the anti-alias FIR filter WindowLen equ 64 ;sliding-window length WindowLenLog equ 6 ;and its 2-base logarythm ; => FT freq. bin = 8000/3/64 Hz SymbolLen equ WindowLen/2 ;the length (time-spacing) of our symbols ; => symbol rate = 8000/3/32 = 83.3333 baud FirstDataCarr equ 18 ;first data carrier at 18*(8000/3/64) = 750 Hz DataCarrSepar equ 3 ;data carriers separated by 3*(8000/3/64) = 125 Hz ;(a very fixed parameter) DataCarriers equ 15 ;15 data carriers ; => total bandwidth = 15*3*(8000/3/64) = 1875 Hz ; => total data rate = 15*83.3333 = 2500 bps FirstTuneCarr equ FirstDataCarr+DataCarrSepar ;first carrier for tune/sync. at 875 Hz TuneCarrSepar equ DataCarrSepar*4 ;tune carriers separated by 4*125 Hz TuneCarriers equ (DataCarriers+1)/4 ;4 tune carriers RxPipeLen equ 4 ;pipe for auto-tuner, differential phase ;decoder, bit synchronizer. TxMinIdle equ 50 ;[symbols] minimal idling time should a new ;packet come just at the end of a transmition TxTuneLen equ 32 ;[symbols] the time for which the tuning sequence ;is transmitted: 32/100 baud = 0.32 sec ;make this larger if your radio has long ;Tx switch-on time. TxSyncLen equ 32 ;[symbols] the time for which the symbol-sync sequence ;is transmitted: 32/100 baud = 0.32 sec TxPreData equ 4 ;[symbols] send that many 0 symbols before the user data TxPostData equ 2 ;[symbols] and that many after the user data TxJamLen equ 16 ;[symbols] the time for which the jamming sequence ;is transmitted (for faster DCD switch-off). TxAttenuate equ 20.0 ;[dB] attenuate the output CODEC's signal. ;Set this between 0.0 and 90.0 ;to accomodate the output level for the ;modulator input of your tranceiver. TxPTThack equ 1 ;Do my own persistance decision before ;pushing the PTT. This is done because ;LEONID's PTT logic doesn't fit well ;the specific needs of this modem. TxPersistance equ 0.25 ;Persistance level per slot-time ;slot-time equals to symbol length RxGain equ 10.0 ;[dB] Rx CODEC's input gain ;set this between 0 and 22.5 dB depending on ;the audio level from your tranceiver RxAGC equ 1 ;enable the automatic gain adjustment ;for the CODEC's audio input. ;ideally you should avoid the AGC and set ;RxGain for best audio level match. ;Note, that the AGC may get fooled up by ;for example long periods of total silence, ;thus you should rather keep the quelch (if any) ;open all the time. RxAGC_MSfollow equ 1.0/16.0 ;update weight per half-symbol ;for the Mean Square tracking RxAGChold equ 320 ;[half-symbol] AGC peak hold time RxAGCfall equ 32 ;[half-symbol] AGC falling period/1.5 dB step RxAGCminMS equ 0.008 ;min. and max. tolerable audio Mean Square level RxAGCmaxMS equ 0.04 RxAGCmaxPeak equ 0.75 ;max. allowed peak audio level RxAGCsensePeak equ 0 ;take (or don't take) into acount the peak level ;when deciding about the gain changes ;taking the peak into account makes the AGC ;more "jumpy" which is not good in my opinion. RxAGCavoidDCD equ 0 ;disallow gain changes when DCD is on RxAverFollow equ 4 ;follow factor for averaging the correlations ;during the idle and tune phase. ;the actuall weight is 1/2^RxAverFollow ;per half-symbol RxMinTune equ 16 ;[symbols] minimal duration of the detected tune tones ;(a given set of pure tones) ;before deciding on the freq. error ;and going into the "tune" phase. RxTuneTimeout equ 56 ;[symbols] timeout for the "tune" phase. If bit-sync. ;is not found for that many symbols ;sync. attempt is aborted RxMinSync equ 16 ;[symbols] minimal duration of the detected sync. ;(alternating phase carriers) ;before deciding on the symbol timing ;and going into the "data" phase. RxUpdateHold equ 10 ;[symbols] hold the Rx DCD and carrier power ;update after the symbol sync. has been detected. DCDTuneAverWeight equ 1.0/16.0 ;Weight for averaging of DCD and tuning ;stat. during data phase DCDThreshold equ 0.020 ;DCD threshold: higher number -> the DCD ;is more tolerant to noise. ;0.02 is real close to the noise limit DCDMaxDrop equ 12 ;[symbols] DCD may drop for that many symbols ;before it is assumed to be gone for good RxDataSyncFollow equ 5 ;follow weight for the carrier powers ;and sync. correction while in the data phase RxFreqFollowWeight equ 1.0/32 ;weight/symbol to follow the frequency error ;during the data phase RxEarlyDCD equ 1 ;set DCD to on already in Idle state ;when some signs of the tune preamble ;are being seen. This speeds up the channel ;busy detection and makes less colisions. RxCtrlUpDown equ 1 ;Control the up/down switches to follow ;automatically frequency drift. ;this conflicts with RxMonitorRxState ! UpDownPulseLen equ 10 ;[symbols] Pulse length for the Up/Down ;corrections ;10 = 10/100 = 0.1 sec. UpDownCorrThres equ 20.0 ;[Hz] Up/Down corrections will be done only ;if frequency error is larger than this UpDownReverse equ 0 ;reverse the sense: usefull for LSB operation. RightChannel equ 0 ;Use the right CODEC's channel not the left. ;I didn't try this but Timo says it works. FEC equ 3 ;0 => no Forward Error Correction ; ;1 => one-bit FEC: for every 11 bits you add 4 so afterwards ; single bit errors can be detected and corrected. ; The effective data rate falls down to 2500*11/15 = 1833.33 bps ; ;3 => Walsh function FEC: 5 data bits -> 15 bits. ; Receiver can correct up to 3 bit errors. ; The effective data rate falls down to 2500*5/15 = 833.33 bps FECflickerRedLED equ 1 ;flicker the red LED if errors are seen ;in the FEC decoder. Interleave equ 8 ;interleave factor (0 = interleave disabled) ;bits from one bit-batch are transmitted ;at different times so a one-symbol burst error ;will corrupt only one bit from a bit-batch. ;The larger the interleave the longer burst errors ;can possibly be recovered (but at same time you ;prolong the TxFlush phase). ;For a given Interleave every transmition is prolonged ;by Interleave/2*DataCarriers symbols ;Note that Interleave makes sense when you use FEC ;at same time, otherwise it only prolongs the packets ;without any benefits. ScrambledInterleave equ 1 ;0 => linear interleave ;1 => scrambled interleavve to maximize the ; time/freq. distance between bits belonging ; to same FEC bit-batch ;the FEC and Interleave code is written exclusively for DataCarriers=15 if FEC==0 BitBatchLen equ DataCarriers endif if FEC==1 BitBatchLen equ 11 endif if FEC==3 BitBatchLen equ 5 endif ; The overall frequency plan is the following: 15 carriers ; carrier #0 at 750 Hz, #7 (the middle one) at 1625 Hz, #14 at 2500 Hz ; absolute maximum allowed mistune is +/- 80 Hz, ; but we rather expect up to +/- 60 Hz. BufLen equ 512 ;sample buffer length ;with some safety margin SPY equ 0 ; SPY=0 => KISS mode (_all_ SPY_ sub-options must be set to 0 !) ; SPY=1 => KISS code excluded, selected debug code included SPY_RxIQ equ 0 SPY_RxWindow equ 0 SPY_RxFFT equ 0 SPY_PeakMS equ 0 SPY_CODECgain equ 0 SPY_RxCarIQ equ 0 SPY_RxCorrel equ 0 SPY_RxStateRou equ 0 SPY_RxCarFreq equ 0 SPY_RxToneTune equ 0 SPY_RxSyncTune equ 0 SPY_RxDataIQ equ 0 SPY_RxCrossedIQ equ 0 SPY_RxCrossedPhase equ 0 SPY_RxCrossedPhaseAver equ 0 SPY_RxPhaseAbsAver equ 0 SPY_DCDnum equ 0 SPY_DCDaver equ 0 SPY_DataTuneAver equ 0 SPY_DataSyncAver equ 0 SPY_RxDataWord equ 0 MonitorRxState equ 0 ;monitor the state of the Rx by flashing LEDs ;connected to the UP, DOWN, CAT lines of the ;left radio channel. This is more for me to ;debug the code. ;This option conflicts with RxCtrlUpDown ;when you use the left channel. MonitorRxAGC equ 0 ;monitor the gain changes down by the AGC ;with the UP and DOWN LEDs ;This option conflicts with RxCtrlUpDown ;when you use the left channel. ;************************************************************************* ;Some simple macros if RightChannel PTT macro mode ;PTT line: clr/set/chg b\mode #4,X:$FFE4 endm else PTT macro mode ;PTT line: clr/set/chg b\mode #0,X:$FFE4 ; b\mode #3,X:$FFE4 ;*** DEBUG *** endm endif if RightChannel PushUp macro mode ;Push UP line of the TRX b\mode #5,X:$FFE4 endm else PushUp macro mode b\mode #1,X:$FFE4 endm endif if RightChannel PushDown macro mode ;Push DOWN line of the TRX b\mode #6,X:$FFE4 endm else PushDown macro mode b\mode #2,X:$FFE4 endm endif UpLED macro mode ;UP line (a red LED connected) b\mode #1,X:$FFE4 endm DownLED macro mode ;DOWN line (a red LED connected) b\mode #2,X:$FFE4 endm YellowLED macro mode ;CAT line (a yellow LED connected) b\mode #3,X:$FFE4 endm RedLED macro mode ; Red LED clr/set/chg b\mode #13,X:$FFE4 endm LongDecayAver macro Input,Aver,Scale sub Aver,Input rep Scale asr Input add Input,Aver endm ;************************************************************************* ;The actuall code (internal/external program RAM) LOMEM P:$0000 HIMEM P:$1FFF org p:user_code jmp .loop #WindowLen move X:(r1)+,a jsr 1,x0 sub x0,a move a,X:RxAGCfall,x0 ;preset the AGC "timer" to prohibit asl a x0,X:RxAGChold,y0 ;preset the AGC "timer" to prohibit gain increase move #RxAGCmaxMS,x0 ;for the RxAGChold period cmp x0,a y0,X:RxAGChold,x0 ;initialize the AGC hold count-down move a,X: move #FFTbuff,r0 move #<0,m0 move #WindowLen/2,n0 .loop #WindowLen move X:(r0),a jsr move X:1,x0 jle (r0) sub x0,a move a,X:RxDoIdle,x0 ;set Rx handler to "idle" move x0,X:ToneWindowInp,x0 ;set FFT window to "tone" move x0,X:SymbolLen/2,x0 ;make slides every half-symbol clr a x0,X:1,x1 ;and count them move #<0,x0 move #<8,n4 .loop #TuneCarriers move (r4)+ move L:(r4)+,a ;estimate the correlation amplitude abs a L:(r4)-,b ;take I and Q parts, compute absolute abs b ;values cmp b,a ;which is greater ? .if ;if I less than Q tfr b,a L:(r4),b ;swap I with Q abs b .endi ;a = greater part, b = smaller part asr b ;compute 2*(a+b/4+b/16) asr b add b,a asr b (r4)- addl b,a L:(r4)+n4,b ;load carrier's power cmp a,b x0,a ;and compare: a = 2*correl. power, b = sig. power .if ;if power < 2*correlation add x1,a ;count "good" carriers .endi move a,x0 ;save the counter .endl if SPY_RxCorrel move #<8,n4 jsr .loop #8 move L:(r4)+,a rep #8 asl a jsr TuneCarriers-1,x1 ;if more than 3 carriers are "good" cmp x1,a #1.0/@cvf(2*RxMinTune),x0 move X: ;then increment the acceptance if MonitorRxState UpLED set endif add x0,b ;counter .else ;otherwise decrement it if MonitorRxState UpLED clr endif sub x0,b .endi move b,X: bset #2,X: "tune detect" condition move #freq. factor macr x0,x1,b ;correct the tuning freq. move b,X: .loop #8*TuneCarriers move L:(r4)+,a rep #8 asl a jsr RxDoTune,x0 ;set Rx handler to "tune" move x0,X:DataWindowInp,x0 ;set FFT window to "data" move x0,X:2*RxTuneTimeout,x0 ;set timeout on the "tune" phase move x0,X:1,x0 sub x0,a jmi ;at-symbol flag move # .loop #8 move L:(r4)+,a rep #8 asl a jsr 1,x1 ;and count them move #<0,x0 move #<4,n4 move m4,m5 move r4,r5 move #<2,n5 .loop #TuneCarriers move L:(r4)+n4,a ;load the carrier's power from at-symbol move L:(r4),b ;and from inter-symbol cmp b,a ;see which is greater tlt b,a r4,r5 ;take the greater one and remember in r5 asr a (r4)+n4 ;which data were taken asr a L:(r5+n5),b ;load the I-correl. -2 neg b ;see if (-correl) > power/4 cmp a,b x0,a ;or is it safer to take power/2 ? .if ;count good carriers add x1,a move a,x0 .endi move r4,r5 .endl tfr x0,a #>TuneCarriers-1,x1 ;if more than 3 carriers are "good" cmp x1,a #1.0/@cvf(RxMinSync),x0 move X: ;then increment the acceptance if MonitorRxState DownLED set endif add x0,a ;counter .else ;otherwise decrement it if MonitorRxState DownLED clr endif sub x0,a .endi move a,X:SymbolLen/2,x1 ;see which is greater .if ;take the greater one and remember in r5 tfr b,a r4,r5 ;which data were taken move #>SymbolLen,x1 ;if the "inter-symbol" stronger .endi ;we have to shift the timing by half-symbol move x1,Y:(r1) ;save the approx. timing move L:(r5+n5),b ;compute ( [0].I - [-2].I ) / 2 sub b,a (r5)+ asr a L:(r5)+,b ;b = [-1].I jsr SymbolLen,x0 macr -x0,x1,a (r4)+n4 move a,Y:(r1)+ move L:(r5)+,a ;load [-2].I neg a L:(r5)+,b ;and [-2].Q ;invert this vector because of the bi-phase modulation jsr freq. factor macr x0,x1,b ;correct the carrier freq. move b,X: .loop #8*TuneCarriers ;send correlation data move L:(r4)+,a rep #8 asl a jsr RxDoData,x0 ;set Rx handler to "tune" move x0,X:RxUpdateHold,x0 ;set time when the statistics update move x0,X:SymbolLen/2,x0 ;reset the slide interval move x0,X: move X: |b| (di-bit = 00 or 11) tst b ;b positive => 10, negative => 01 jpl 11, negative => 00 jpl move L: RedLED clr .else RedLED set .endi endif endif if FEC==3 move X: RedLED clr .else RedLED set .endi endif endif if SPY_RxDataWord move X:1,y1 ;init. sum and increment move (r4)+n4 .loop #DataCarriers ;count the carriers which has the average move X:(r4)+,a ;phase deviation below the threshold cmp y0,a .if add y1,b .endi if SPY_RxPhaseAbsAver jsr DataCarriers/2,x0 ;if more than half carriers cmp x0,b #1.0/@cvf(DCDMaxDrop),x1 ;are OK move X: ;then increment the acceptance if MonitorRxState YellowLED set endif add x1,a ;counter .else ;otherwise decrement it if MonitorRxState YellowLED clr endif sub x1,a .endi cmp x0,b a,X: ;bring back the carrier's decision move (r4)+n4 ;if positive then correct the frequency error move Y:(r4)+,a ;find the max. and min. phase (to reject them later) tfr a,b (r4)+n4 ;initialize min and max with the first phase .loop #DataCarriers-1 ;seek min and max move Y:(r4)+,x0 ;get next phase cmp x0,a (r4)+n4 ;higher than the maximum ? tlt x0,a ;if so then substitute the maximum cmp x0,b ;lower than the minimum ? tgt x0,b ;if so then substitute the minimum .endl add b,a Y:(r4)+,x0 ;sum up all deviations move (r4)+n4 .loop #DataCarriers-1 ;but subtract the max. and min. sub x0,a Y:(r4)+,x0 ;infact we compute "-sum"... move (r4)+n4 .endl sub x0,a X:freq. factor macr x0,x1,b ;correct the carrier freq. move b,X:2*UpDownPulseLen,x0 move x0,X: else .if endif PushUp set .else PushDown set .endi endif jmp 1,x0 ;expires. sub x0,a move a,X:DecimateRatio*SymbolLen,a move X:TxDoIdle,x0 move x0,X:TxMinIdle,x0 ;obligatory silence period move x0,X:1,x0 ;check if any data for transmition if SPY jle zero output ;jump directly to the output interpolation TxStartTune PTT set ;turn on the PTT move #>ToneWindowOut,x0 ;set the window to "pure tone" move x0,X:TxDoTune,x0 ;set the state routine move x0,X:TxTuneLen,x0 ;initialize the count-down move x0,X:1,x0 jle DataWindowOut,x0 move x0,X:TxDoSync,x0 move x0,X:TxSyncLen,x0 move x0,X:1,x0 jle TxDoPreData,x0 move x0,X:TxPreData,x0 move x0,X:1,x0 jle TxDoData,x0 move x0,X:100,x0 ;make 100 data symbols move x0,X:1,x0 jle 50,x1 mpy x0,x1,a move x0,a1 move a10,L: phase change) ;11 -> 0, 10 -> +90, 00 -> +180, 01 -> +270 move #TxDataVect,r5 move #TxDoPostData,x0 move x0,X:TxPostData+(Interleave*DataCarriers+1)/2,x0 move x0,X:1,x0 jle TxDoJam,x0 move x0,X:TxJamLen,x0 move x0,X:1,x0 jle TxDoBuffFlush,x0 move x0,X:(BufLen/(SymbolLen*DecimateRatio)+2),x0 move x0,X:1,x0 ;we turn off the PTT jle 2,x1 add x1,a move a,x1 CheckSampleBlock_1 move r7,a move r2,x0 sub x0,a jpl BufLen*4,x0 add x0,a CheckSample_cmp cmp x1,a rts ;on output: a,x0,x1 are modified ;If carry=0 => we are sure that: ;1. there are at least A new input samples at X:(r2) ; to be read ;2. there are at least A locations at Y:(r2) to ; be written WaitSampleBlock ;wait for a block of samples from the CODEC ;on input: a = how many samples we want ; r2 = where the block starts jsr $80,x1 ;shift out 8 most significant bits mpy x0,x1,a #>$FF,x0 move x0,m0 and x0,a #>$100,x0 or x0,a #<$40,n0 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_lev2 move (r0)+ SinTable_lev2 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 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 turn by PI .if neg a #<%10000000,x0 neg b .endi tst a b0,y0 ;if I-part negative => turn by -PI/2 .if bset #22,x0 tfr a,b b1,y1 tfr y1,a neg b y0,a0 .endi cmp b,a a0,y0 ;if Q>I swap them. .if tfr b,a a1,y1 tfr y1,b move y0,b0 bset #21,x0 .endi tst a #1.0/PI,y0 ;normalize .while asl b asl a .endw move a,x1 andi #$FE,ccr ;divive Q by I rep #24 div x1,b tfr x0,a b0,x0 ;x0 = Q div I, a=approx angle btst #21,a1 .if macr -x0,y0,a #<%00100000,y0 add y0,a #-(1.0/PI-1.0/4.0),y0 .else mac x0,y0,a #(1.0/PI-1.0/4.0),y0 .endi mpyr x0,y0,b mpyr x0,x0,b b,y0 move b,x0 mac -x0,y0,a rts ;a = the phase (-1.0 => -PI, 1.0 => PI) ;b,x,y are modified Rand48 ;a simple random number generator move L:%11111111111,x0 ;clear extra bits, leave only and x0,a #FEC1511EncodeTable,r0 ;these 11 ones which we will encode move a1,x1 ;save the input move #$FFFF,m0 .loop #11 ror a Y:(r0)+,x0 ;take the input bits .if ;if the bit is a 1 eor x0,b ;add corresponding CRC .endi nop .endl tfr b,a or x1,a rts ;a = 15 bits containing 11 data bits (0-10) ;plus 4 FEC bits (11-14). ;b,x0,x1,r0,m0 are modified (m0 is set to $FFFF) FEC1511Decode ;a1 = 15 bits to be decoded/corrected move a1,y1 ;save the input jsr ($800000>>11),y0 mpy x0,y0,a ;shift the CRC difference into bits 0-3 move a1,n0 move y1,a move Y:(r0+n0),x0 ;pickup the correction eor x0,a x0,b ;and correct the data rts ;a1 = corrected 11 data bits (0-10) ;b1 = error pattern (bits 0..14) ;plus the old CRC bits (11-14) ;x0,x1,y0,y1,r0,m0,n0 are modified endif if FEC==3 WalshEncode move #>%11111,x0 ;a1 = 5 bits to be encoded and x0,a #WalshTable,r0 ;lookup the table and pick up move #$FFFF,m0 ;the element pointed by the input 5 bits move a1,n0 nop move Y:(r0+n0),a1 rts ;a1 = 15-bit codeword to be transmitted ;x0,r0/m0/n0 are modified WalshDecode ;a1 = 15-bit codeword to be decoded move a1,y1 ;save the input move #<0,x1 ;x1 = 0 for fast bit counting move #>16,y0 ;y0 = initial distance move #WalshTable,n0 ;here we use a brutal force approach: move #$FFFF,m0 ;we look through all the 32 codewords move #WalshTable+32,r0 ;and pick up the one with least number .loop #32 ;of different bits clr b Y:-(r0),a1 ;get the codeword, clear the bit counter eor y1,a x1,x0 ;make the difference, clear x1:x0 .loop #15 ;count in b the bits which are equal to 1 lsr a1 adc x,b .endl tfr y0,b b0,x0 cmp x0,b tge x0,b r0,r1 move b,y0 .endl move r1,r0 nop move Y:(r0)-n0,b eor y1,b r0,a1 rts ;a1 = 5 decoded bits (0..4) ;b1 = error pattern (bits 0..14) ;x0,x1,y0,y1,r0,m0,n0,r1 are modified ;if n0=0 => there was no error endif if !SPY ; KISS control frame handling - called by LEONID when a KISS control-type ; frame is received with non-standard parameters KISSctrl rts ; transmitter PTT control - a routine called by LEONID to say that we ; should transmit (carry=1) or stop transmitting (carry=0) ; we don't turn the PTT on/off here ;the modem will do it when it's the right time PTTctrl jcc $0F0F00,x0 ;r2/m2 should point to the CODEC's buffer move Y:(r2),a1 ;get the CODEC's input control word and x0,a ;extract the gain bits 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 andi #$FE,ccr ;clear carry rts ;modifies a,x0,x1 RxGainDown ;decrease the CODEC's input gain (both channels) clr a #>$0F0F00,x0 ;r2/m2 should point to the CODEC's buffer move Y:(r2),a1 ;get the CODEC's input control word and x0,a #>$010100,x0 ;extract the gain bits sub x0,a #>$F0F000,x0 ;attempt to decrease the gain jcs 1,a ;minimal TxDelay and TxTail: move a,p:kiss_pars ;we make the delays by ourselfs move a,p:kiss_pars+3 ;in the Tx state machine if TxPTThack ;if PTT-hack move #>1,a move a,p:kiss_pars+4 ;set full duplex to disable LEONID's endif ;slot-time/persistance move #KISSctrl,a1 ;switch serial interface to KISS mode move #PTTctrl,b1 opensc endif move #Buffer+2,r7 ;for the CODEC's interrupt routine move #BufLen*4-1,m7 move #Buffer,r2 ;for "cdctrl" to initialize the buffer move #<4-1,n2 move #BufLen*4-1,m2 ;initialize input/output control words in the buffer ;zero input/output data if EVM56K ;for EVM56002 use MIC input ctrlcd 1,r2,BufLen,MIC,RxGain,RxGain,LINEO|HEADP,TxAttenuate,TxAttenuate else ;for DSPCARD4 use LINE input ctrlcd 1,r2,BufLen,LINEI,RxGain,RxGain,LINEO|HEADP,TxAttenuate,TxAttenuate endif opencd SampleFreq/1000.0,HPF ;start taking samples at given rate jmp no spy request move a2,X: spy request ! move x0,Y:'S',a cmp x0,a ori #$01,ccr jne 'P',x0 putc move #>512,a move a,X:'S',a cmp x0,a jne 'P',x0 putc move #>512,a Spy_copy move #>1,x0 sub x0,a move a,X: at-symbol sample ;bit #1 = 1 => data correl. update allowed ;bit #2 = 1 => channel is busy (DCD is on) TxState dc 0 ;bit #0 = 1 => PTT ON was requested ;bit #1 = 1 => PTT OFF was requested RxStateRoutine dc RxStartIdle RxStateCounter dc 0 RxAcceptCount dc 0 if FEC RxErrPattern dc 0 ;FEC error pattern endif if RxAGC RxAudioPeak dc 0 ;peak level of the input audio RxAudioMS dc 0 ;Mean Square (the power) of the input audio RxAGCcount dc RxAGCfall endif if Interleave RxInlvPtr dc RxInlvPipe TxInlvPtr dc TxInlvPipe endif if RxCtrlUpDown RxUpDownTime dc 0 endif org Y: RxTunePhase dsm TuneCarriers RxSyncDelay dsm TuneCarriers org X: LastX = * org Y: LastY = * if @cvi(LastX)>=@cvi(LastY) org L:LastX else org L:LastY endif RxTuneCorrel dsm TuneCarriers*8 ;various correlations for ;the tuning/sync. phase RxDataCorrel dsm 3*DataCarriers ;various correlations for the data phase org X:Vect45 dc @sqt(0.5) ; dc 0.6 org Y:Vect45 dc @sqt(0.5) ; dc 0.6 ;************************************************************************* ;External data RAM if EVM56K LOMEM X:$2000,Y:$0100,L:$2000 HIMEM X:$3FFF,Y:$3FFF,L:$3FFF else LOMEM X:$0100,Y:$0100,L:$0100 HIMEM X:$1FFF,Y:$3FFF,L:$1FFF endif if EVM56K org L:$2000 else org L:$200 endif org L: WindowInpTap dsm WindowLen WindowOutTap dsm WindowLen FFTcoef dsm WindowLen ;sine/cosine table for the FFT and other stuff FFTbuff dsm WindowLen ;Work buffer for the FFT routine RxPipe dsm DataCarriers*RxPipeLen ;here we store the FFT results ;for the tone we listen to. ;this is not large so we could place ;it in internal RAM... TxDataIniVect dsm DataCarriers ;init. vectors (amplitude and phase) ;for the Tx should be made such that ;the Peak/RMS is minimal TxDataVect dsm DataCarriers ;these are used during data ;transmition phase TxTuneIniVect dsm TuneCarriers ;init. vectors for tuning preamble TxTuneVect dsm TuneCarriers LastL = * org X:LastL org Y:LastL org Y: AliasFilterInpI dsm AliasFilterLen ;anti-alias input filter (I/Q) AliasFilterInpQ dsm AliasFilterLen org X: AliasFilterOutI dsm AliasFilterLen ;anti-alias output filter (I/Q) AliasFilterOutQ dsm AliasFilterLen org Y: ToneWindowInp dsm WindowLen ;input/output FFT window ToneWindowOut dsm WindowLen ;for pure tone Tx/Rx DataWindowInp dsm WindowLen ;input/output FFT window DataWindowOut dsm WindowLen ;for data symbols Tx/Rx if Interleave org Y: RxInlvPipe dsm Interleave*DataCarriers TxInlvPipe dsm Interleave*DataCarriers endif if Interleave org Y: InterleavePattern if ScrambledInterleave dc %000000000000001 dc %000000000010000 dc %000000100000000 dc %001000000000000 dc %000000000000010 dc %000000000100000 dc %000001000000000 dc %010000000000000 dc %000000000000100 dc %000000001000000 dc %000010000000000 dc %100000000000000 dc %000000000001000 dc %000000010000000 dc %000100000000000 else ;linear interleave dc %000000000000001 dc %000000000000010 dc %000000000000100 dc %000000000001000 dc %000000000010000 dc %000000000100000 dc %000000001000000 dc %000000010000000 dc %000000100000000 dc %000001000000000 dc %000010000000000 dc %000100000000000 dc %001000000000000 dc %010000000000000 dc %100000000000000 endif endif if FEC==1 org Y: FEC1511EncodeTable dc %001100000000000 dc %010100000000000 dc %011000000000000 dc %011100000000000 dc %100100000000000 dc %101000000000000 dc %101100000000000 dc %110000000000000 dc %110100000000000 dc %111000000000000 dc %111100000000000 FEC1511DecodeTable dc %000000000000000 dc %000100000000000 dc %001000000000000 dc %000000000000001 dc %010000000000000 dc %000000000000010 dc %000000000000100 dc %000000000001000 dc %100000000000000 dc %000000000010000 dc %000000000100000 dc %000000001000000 dc %000000010000000 dc %000000100000000 dc %000001000000000 dc %000010000000000 endif if FEC==3 org Y: WalshTable dc %000000000000000 ;these are 32 codewords which are 15 bit long. dc %000000001111111 ;Every codeword differs from any other dc %000011110000111 ;at 7 or more bits dc %000011111111000 ;thus at the receiver we can correct dc %001100110011001 ;up to 3 bit errors dc %001100111100110 dc %001111000011110 dc %001111001100001 dc %010101010101010 dc %010101011010101 dc %010110100101101 dc %010110101010010 dc %011001100110011 dc %011001101001100 dc %011010010110100 dc %011010011001011 dc %100101100110100 dc %100101101001011 dc %100110010110011 dc %100110011001100 dc %101001010101101 dc %101001011010010 dc %101010100101010 dc %101010101010101 dc %110000110011110 dc %110000111100001 dc %110011000011001 dc %110011001100110 dc %111100000000111 dc %111100001111000 dc %111111110000000 dc %111111111111111 endif org X: LastX = * org Y: LastY = * if @cvi(LastX)>=@cvi(LastY) org L:LastX else org L:LastY endif Buffer dsm BufLen*4 ;CODEC's input/output buffer ;************************************************************************* ;constant tables: FIR and window shapes, FFT coefficiants, etc. nolist include 'newqpsk.dat' list ;************************************************************************* end