2 * xpmr.c - Xelatec Private Mobile Radio Processes
4 * All Rights Reserved. Copyright (C)2007, Xelatec, LLC
6 * 20070808 1235 Steven Henke, W9SH, sph@xelatec.com
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Private Land Mobile Radio Channel Voice and Signaling Processor
23 * \author Steven Henke, W9SH <sph@xelatec.com> Xelatec, LLC
26 FYI = For Your Information
27 PMR = Private Mobile Radio
30 CTCSS = Continuous Tone Coded Squelch System
32 LSD = Low Speed Data, subaudible signaling. May be tones or codes.
33 VOX = Voice Operated Transmit
34 DSP = Digital Signal Processing
36 FIR = Finite Impulse Response (Filter)
37 IIR = Infinite Impulse Response (Filter)
44 #include <sys/ioctl.h>
51 #include "xpmr_coef.h"
54 static i16 pmrChanIndex
=0; // count of created pmr instances
57 Convert a Frequency in Hz to a zero based CTCSS Table index
59 i16
CtcssFreqIndex(float freq
)
63 for(i
=0;i
<CTCSS_NUM_CODES
;i
++){
64 if(freq
==freq_ctcss
[i
])hit
=i
;
70 Takes a block of data and low pass filters it.
71 Determines the amplitude of high frequency noise for carrier detect.
72 Decimates input data to change the rate.
74 i16
pmr_rx_frontend(t_pmr_sps
*mySps
)
76 #define DCgainBpfNoise 65536
78 i16 samples
,iOutput
, *input
, *output
, *noutput
;
79 i16
*x
, *coef
, *coef2
;
80 i32 i
, naccum
, outputGain
, calcAdjust
;
82 i16 nx
, hyst
, setpt
, compOut
;
83 i16 amax
, amin
, apeak
, discounteru
, discounterl
, discfactor
;
84 i16 decimator
, decimate
, doNoise
;
86 TRACEX(("pmr_rx_frontend()\n"));
88 if(!mySps
->enabled
)return(1);
90 decimator
= mySps
->decimator
;
91 decimate
= mySps
->decimate
;
93 input
= mySps
->source
;
95 noutput
= mySps
->parentChan
->pRxNoise
;
101 calcAdjust
= mySps
->calcAdjust
;
102 outputGain
= mySps
->outputGain
;
107 discounteru
=mySps
->discounteru
;
108 discounterl
=mySps
->discounterl
;
109 discfactor
=mySps
->discfactor
;
112 compOut
=mySps
->compOut
;
114 samples
=mySps
->nSamples
*decimate
;
118 if(mySps
->parentChan
->rxCdType
!=CD_XPMR_VOX
)doNoise
=1;
121 for(i
=0;i
<samples
;i
++)
125 //shift the old samples
126 for(n
=nx
-1; n
>0; n
--)
141 y
=((y
/calcAdjust
)*outputGain
)/M_Q8
;
144 else if(y
<-32767)y
=-32767;
146 output
[iOutput
]=y
; // Rx Baseband decimated
147 noutput
[iOutput
++] = apeak
; // Rx Noise
152 // calculate noise output
155 naccum
+= coef_fir_bpf_noise_1
[n
] * x
[n
];
157 naccum
/= DCgainBpfNoise
;
162 discounteru
=discfactor
;
164 else if(--discounteru
<=0)
166 discounteru
=discfactor
;
167 amax
=(i32
)((amax
*32700)/32768);
173 discounterl
=discfactor
;
175 else if(--discounterl
<=0)
177 discounterl
=discfactor
;
178 amin
=(i32
)((amin
*32700)/32768);
188 ((t_pmr_chan
*)(mySps
->parentChan
))->rxRssi
=apeak
;
190 if(apeak
>setpt
|| (compOut
&&(apeak
>(setpt
-hyst
)))) compOut
=1;
192 mySps
->compOut
=compOut
;
196 mySps
->discounteru
=discounteru
;
197 mySps
->discounterl
=discounterl
;
203 pmr general purpose fir
204 works on a block of samples
206 i16
pmr_gp_fir(t_pmr_sps
*mySps
)
208 i32 nsamples
,inputGain
,outputGain
,calcAdjust
;
212 i16 nx
, hyst
, setpt
, compOut
;
213 i16 amax
, amin
, apeak
=0, discounteru
=0, discounterl
=0, discfactor
;
214 i16 decimator
, decimate
, interpolate
;
215 i16 numChanOut
, selChanOut
, mixOut
, monoOut
;
217 TRACEX(("pmr_gp_fir() %i\n",mySps
->enabled
));
219 if(!mySps
->enabled
)return(1);
221 inputGain
= mySps
->inputGain
;
222 calcAdjust
= mySps
->calcAdjust
;
223 outputGain
= mySps
->outputGain
;
225 input
= mySps
->source
;
226 output
= mySps
->sink
;
231 decimator
= mySps
->decimator
;
232 decimate
= mySps
->decimate
;
233 interpolate
= mySps
->interpolate
;
235 setpt
= mySps
->setpt
;
236 compOut
= mySps
->compOut
;
238 inputGain
= mySps
->inputGain
;
239 outputGain
= mySps
->outputGain
;
240 numChanOut
= mySps
->numChanOut
;
241 selChanOut
= mySps
->selChanOut
;
242 mixOut
= mySps
->mixOut
;
243 monoOut
= mySps
->monoOut
;
248 discfactor
=mySps
->discfactor
;
251 nsamples
=mySps
->nSamples
;
257 for(i
=0;i
<nsamples
;i
++)
260 output
[(i
*2)]=output
[(i
*2)+1]=0;
262 output
[(i
*numChanOut
)+selChanOut
]=0;
268 for(i
=0;i
<nsamples
;i
++)
279 for(ix
=0;ix
<interpolate
;ix
++)
284 for(n
=nx
-1; n
>0; n
--)
286 x
[0] = (input
[i
]*inputGain
)/M_Q8
;
302 y
=((y
/calcAdjust
)*outputGain
)/M_Q8
;
306 output
[(ii
*2)]=output
[(ii
*2)+1]+=y
;
309 output
[(ii
*numChanOut
)+selChanOut
]+=y
;
314 output
[(ii
*2)]=output
[(ii
*2)+1]=y
;
317 output
[(ii
*numChanOut
)+selChanOut
]=y
;
324 // amplitude detector
332 discounteru
=discfactor
;
334 else if(--discounteru
<=0)
336 discounteru
=discfactor
;
337 amax
=(i32
)((amax
*32700)/32768);
343 discounterl
=discfactor
;
345 else if(--discounterl
<=0)
347 discounterl
=discfactor
;
348 amin
=(i32
)((amin
*32700)/32768);
351 apeak
= (i32
)(amax
-amin
)/2;
353 if(apeak
>setpt
)compOut
=1;
354 else if(compOut
&&(apeak
<(setpt
-hyst
)))compOut
=0;
358 mySps
->decimator
= decimator
;
363 mySps
->discounteru
=discounteru
;
364 mySps
->discounterl
=discounterl
;
366 mySps
->compOut
=compOut
;
371 general purpose integrator lpf
373 i16
gp_inte_00(t_pmr_sps
*mySps
)
378 i32 inputGain
, outputGain
,calcAdjust
;
383 i16 coeff00
, coeff01
;
385 TRACEX(("gp_inte_00() %i\n",mySps
->enabled
));
386 if(!mySps
->enabled
)return(1);
388 input
= mySps
->source
;
389 output
= mySps
->sink
;
391 npoints
=mySps
->nSamples
;
393 inputGain
=mySps
->inputGain
;
394 outputGain
=mySps
->outputGain
;
395 calcAdjust
=mySps
->calcAdjust
;
397 coeff00
=((i16
*)mySps
->coef
)[0];
398 coeff01
=((i16
*)mySps
->coef
)[1];
399 state00
=((i32
*)mySps
->x
)[0];
401 // note fixed gain of 2 to compensate for attenuation
404 for(i
=0;i
<npoints
;i
++)
407 state00
= accum
+ (state00
*coeff01
)/M_Q15
;
408 accum
= (state00
*coeff00
)/(M_Q15
/4);
409 output
[i
]=(accum
*outputGain
)/M_Q8
;
412 ((i32
*)(mySps
->x
))[0]=state00
;
417 general purpose differentiator hpf
419 i16
gp_diff(t_pmr_sps
*mySps
)
423 i32 inputGain
, outputGain
, calcAdjust
;
433 input
= mySps
->source
;
434 output
= mySps
->sink
;
436 npoints
=mySps
->nSamples
;
438 inputGain
=mySps
->inputGain
;
439 outputGain
=mySps
->outputGain
;
440 calcAdjust
=mySps
->calcAdjust
;
442 coef
=(i16
*)(mySps
->coef
);
450 TRACEX(("gp_diff()\n"));
452 for (i
=0;i
<npoints
;i
++)
456 temp1
= input
[i
] * a0
;
457 y0
= (temp0
+ temp1
)/calcAdjust
;
458 output
[i
]=(y0
*outputGain
)/M_Q8
;
465 /* ----------------------------------------------------------------------
468 i16
CenterSlicer(t_pmr_sps
*mySps
)
470 i16 npoints
,lhit
,uhit
;
471 i16
*input
, *output
, *buff
;
473 i32 inputGain
, outputGain
, inputGainB
;
477 i32 amax
; // buffer amplitude maximum
478 i32 amin
; // buffer amplitude minimum
479 i32 apeak
; // buffer amplitude peak
481 i32 setpt
; // amplitude set point for peak tracking
483 i32 discounteru
; // amplitude detector integrator discharge counter upper
484 i32 discounterl
; // amplitude detector integrator discharge counter lower
485 i32 discfactor
; // amplitude detector integrator discharge factor
487 TRACEX(("CenterSlicer() %i\n",mySps
->enabled
));
489 input
= mySps
->source
;
490 output
= mySps
->sink
;
493 npoints
=mySps
->nSamples
;
495 inputGain
=mySps
->inputGain
;
496 outputGain
=mySps
->outputGain
;
497 inputGainB
=mySps
->inputGainB
;
503 discounteru
=mySps
->discounteru
;
504 discounterl
=mySps
->discounterl
;
506 discfactor
=mySps
->discfactor
;
507 npoints
=mySps
->nSamples
;
509 for(i
=0;i
<npoints
;i
++)
519 if(amin
<(amax
-setpt
))
529 if(amax
>(amin
+setpt
))
536 if(--discounteru
<=0 && amax
>0)
542 if(--discounterl
<=0 && amin
<0)
548 if(uhit
)discounteru
=discfactor
;
549 if(lhit
)discounterl
=discfactor
;
551 apeak
= (amax
-amin
)/2;
552 center
= (amax
+amin
)/2;
553 accum
= accum
- center
;
556 // do limiter function
557 if(accum
>inputGainB
)accum
=inputGainB
;
558 else if(accum
<-inputGainB
)accum
=-inputGainB
;
563 mySps
->debugBuff0
[i
]=center
;
566 if(mySps
->parentChan
->frameCountRx
&0x01) mySps
->parentChan
->prxDebug1
[i
]=amax
;
567 else mySps
->parentChan
->prxDebug1
[i
]=amin
;
575 mySps
->discounteru
=discounteru
;
576 mySps
->discounterl
=discounterl
;
580 /* ----------------------------------------------------------------------
582 determine peak amplitude
584 i16
MeasureBlock(t_pmr_sps
*mySps
)
589 i32 inputGain
, outputGain
;
593 i16 amax
; // buffer amplitude maximum
594 i16 amin
; // buffer amplitude minimum
595 i16 apeak
=0; // buffer amplitude peak (peak to peak)/2
596 i16 setpt
; // amplitude set point for amplitude comparator
598 i32 discounteru
; // amplitude detector integrator discharge counter upper
599 i32 discounterl
; // amplitude detector integrator discharge counter lower
600 i32 discfactor
; // amplitude detector integrator discharge factor
602 TRACEX(("MeasureBlock() %i\n",mySps
->enabled
));
604 if(!mySps
->enabled
)return 1;
608 mySps
->amax
= mySps
->amin
= mySps
->apeak
= \
609 mySps
->discounteru
= mySps
->discounterl
= \
614 input
= mySps
->source
;
615 output
= mySps
->sink
;
617 npoints
=mySps
->nSamples
;
619 inputGain
=mySps
->inputGain
;
620 outputGain
=mySps
->outputGain
;
625 discounteru
=mySps
->discounteru
;
626 discounterl
=mySps
->discounterl
;
628 discfactor
=mySps
->discfactor
;
629 npoints
=mySps
->nSamples
;
631 for(i
=0;i
<npoints
;i
++)
638 discounteru
=discfactor
;
640 else if(--discounteru
<=0)
642 discounteru
=discfactor
;
643 amax
=(i32
)((amax
*32700)/32768);
649 discounterl
=discfactor
;
651 else if(--discounterl
<=0)
653 discounterl
=discfactor
;
654 amin
=(i32
)((amin
*32700)/32768);
657 apeak
= (i32
)(amax
-amin
)/2;
658 if(output
)output
[i
]=apeak
;
664 mySps
->discounteru
=discounteru
;
665 mySps
->discounterl
=discounterl
;
666 if(apeak
>=setpt
) mySps
->compOut
=1;
667 else mySps
->compOut
=0;
669 //TRACEX((" -MeasureBlock()=%i\n",mySps->apeak));
675 i16
SoftLimiter(t_pmr_sps
*mySps
)
678 //i16 samples, lhit,uhit;
681 i32 inputGain
, outputGain
;
686 i32 amax
; // buffer amplitude maximum
687 i32 amin
; // buffer amplitude minimum
688 //i32 apeak; // buffer amplitude peak
689 i32 setpt
; // amplitude set point for amplitude comparator
690 i16 compOut
; // amplitude comparator output
692 input
= mySps
->source
;
693 output
= mySps
->sink
;
695 inputGain
=mySps
->inputGain
;
696 outputGain
=mySps
->outputGain
;
698 npoints
=mySps
->nSamples
;
701 amax
=(setpt
*124)/128;
704 TRACEX(("SoftLimiter() %i %i %i) \n",amin
, amax
,setpt
));
706 for(i
=0;i
<npoints
;i
++)
709 //accum=input[i]*mySps->inputGain/256;
713 tmp
=((accum
-setpt
)*4)/128;
715 if(accum
>amax
)accum
=amax
;
719 else if(accum
<-setpt
)
721 tmp
=((accum
+setpt
)*4)/128;
723 if(accum
<amin
)accum
=amin
;
728 output
[i
]=(accum
*outputGain
)/M_Q8
;
734 SigGen() - sine, square function generator
735 sps overloaded values
736 discfactor = phase factor
737 discfactoru = phase index
738 if source is not NULL then mix it in!
740 sign table and output gain are in Q15 format (32767=.999)
742 i16
SigGen(t_pmr_sps
*mySps
)
744 #define PH_FRACT_FACT 128
747 i16 i
,outputgain
,waveform
,numChanOut
,selChanOut
;
750 TRACEX(("SigGen(%i) \n",mySps
->option
));
752 if(!mySps
->freq
||!mySps
->enabled
)return 0;
754 outputgain
=mySps
->outputGain
;
756 numChanOut
=mySps
->numChanOut
;
757 selChanOut
=mySps
->selChanOut
;
764 (SAMPLES_PER_SINE
*mySps
->freq
*PH_FRACT_FACT
)/mySps
->sampleRate
/10;
766 TRACEX((" SigGen() discfactor = %i\n",mySps
->discfactor
));
767 if(mySps
->discounterl
)mySps
->state
=2;
769 else if(mySps
->option
==2)
771 i16 shiftfactor
=CTCSS_TURN_OFF_SHIFT
;
772 // phase shift request
775 mySps
->discounterl
=CTCSS_TURN_OFF_TIME
-(2*MS_PER_FRAME
); //
777 mySps
->discounteru
= \
778 (mySps
->discounteru
+ (((SAMPLES_PER_SINE
*shiftfactor
)/360)*PH_FRACT_FACT
)) % (SAMPLES_PER_SINE
*PH_FRACT_FACT
);
779 //printf("shiftfactor = %i\n",shiftfactor);
782 else if(mySps
->option
==3)
784 // stop it and clear the output buffer
788 for(i
=0;i
<mySps
->nSamples
;i
++)
789 mySps
->sink
[(i
*numChanOut
)+selChanOut
]=0;
792 else if(mySps
->state
==2)
795 mySps
->discounterl
-=MS_PER_FRAME
;
796 if(mySps
->discounterl
<=0)
802 else if(mySps
->state
==0)
807 ph
=mySps
->discounteru
;
809 for(i
=0;i
<mySps
->nSamples
;i
++)
814 //tmp=(sinetablex[ph/PH_FRACT_FACT]*amplitude)/M_Q16;
815 accum
=sinetablex
[ph
/PH_FRACT_FACT
];
816 accum
=(accum
*outputgain
)/M_Q8
;
821 if(ph
>SAMPLES_PER_SINE
/2)
822 accum
=outputgain
/M_Q8
;
824 accum
=-outputgain
/M_Q8
;
827 if(mySps
->source
)accum
+=mySps
->source
[i
];
829 mySps
->sink
[(i
*numChanOut
)+selChanOut
]=accum
;
831 ph
=(ph
+mySps
->discfactor
)%(SAMPLES_PER_SINE
*PH_FRACT_FACT
);
834 mySps
->discounteru
=ph
;
840 takes existing buffer and adds source buffer to destination buffer
841 sink buffer = (sink buffer * gain) + source buffer
843 i16
pmrMixer(t_pmr_sps
*mySps
)
846 i16 i
, *input
, *inputB
, *output
;
847 i16 inputGain
, inputGainB
; // apply to input data in Q7.8 format
848 i16 outputGain
; // apply to output data in Q7.8 format
849 i16 discounteru
,discounterl
,amax
,amin
,setpt
,discfactor
;
850 i16 npoints
,uhit
,lhit
,apeak
,measPeak
;
852 TRACEX(("pmrMixer()\n"));
854 input
= mySps
->source
;
855 inputB
= mySps
->sourceB
;
856 output
= mySps
->sink
;
858 inputGain
=mySps
->inputGain
;
859 inputGainB
=mySps
->inputGainB
;
860 outputGain
=mySps
->outputGain
;
865 discounteru
=mySps
->discounteru
;
866 discounterl
=mySps
->discounteru
;
868 discfactor
=mySps
->discfactor
;
869 npoints
=mySps
->nSamples
;
870 measPeak
=mySps
->measPeak
;
872 for(i
=0;i
<npoints
;i
++)
874 accum
= ((input
[i
]*inputGain
)/M_Q8
) +
875 ((inputB
[i
]*inputGainB
)/M_Q8
);
877 accum
=(accum
*outputGain
)/M_Q8
;
886 if(amin
<(amax
-setpt
)){
894 if(amax
>(amin
+setpt
)){
900 if(--discounteru
<=0 && amax
>0){
905 if(--discounterl
<=0 && amin
<0){
910 if(uhit
)discounteru
=discfactor
;
911 if(lhit
)discounterl
=discfactor
;
916 apeak
= (amax
-amin
)/2;
920 mySps
->discounteru
=discounteru
;
921 mySps
->discounterl
=discounterl
;
929 i16
DelayLine(t_pmr_sps
*mySps
)
931 i16
*input
, *output
, *buff
;
932 i16 i
, npoints
,buffsize
,inindex
,outindex
;
934 TRACEX((" DelayLine() %i\n",mySps
->enabled
));
936 input
= mySps
->source
;
937 output
= mySps
->sink
;
938 buff
= (i16
*)(mySps
->buff
);
939 buffsize
= mySps
->buffSize
;
940 npoints
= mySps
->nSamples
;
942 outindex
= mySps
->buffOutIndex
;
943 inindex
= outindex
+ mySps
->buffLead
;
945 for(i
=0;i
<npoints
;i
++)
948 outindex
%= buffsize
;
950 buff
[inindex
]=input
[i
];
951 output
[i
]=buff
[outindex
];
955 mySps
->buffOutIndex
=outindex
;
960 Continuous Tone Coded Squelch (CTCSS) Detector
962 i16
ctcss_detect(t_pmr_chan
*pmrChan
)
964 i16 i
,points2do
, points
=0, *pInput
, hit
, thit
,relax
;
965 i16 tnum
, tmp
, indexWas
=0, indexNow
, gain
, peakwas
=0, diffpeak
;
967 i16 lasttv0
=0, lasttv1
=0, lasttv2
=0, tv0
, tv1
, tv2
, indexDebug
;
969 TRACEX(("ctcss_detect(%p) %i %i %i %i\n",pmrChan
,
970 pmrChan
->rxCtcss
->enabled
,
971 pmrChan
->rxCtcssIndex
,
972 pmrChan
->rxCtcss
->testIndex
,
973 pmrChan
->rxCtcss
->decode
));
975 if(!pmrChan
->rxCtcss
->enabled
)return(1);
977 relax
= pmrChan
->rxCtcss
->relax
;
978 pInput
= pmrChan
->rxCtcss
->input
;
979 gain
= pmrChan
->rxCtcss
->gain
;
981 if(relax
) difftrig
=(-0.1*M_Q15
);
982 else difftrig
=(-0.05*M_Q15
);
986 //TRACEX((" ctcss_detect() %i %i %i %i\n", CTCSS_NUM_CODES,0,0,0));
988 for(tnum
=0;tnum
<CTCSS_NUM_CODES
;tnum
++)
995 //TRACEX((" ctcss_detect() tnum=%i %i\n",tnum,pmrChan->rxCtcssMap[tnum]));
997 if( (pmrChan
->rxCtcssMap
[tnum
] < 0) ||
998 (pmrChan
->rxCtcss
->decode
>=0 && (tnum
!= pmrChan
->rxCtcss
->decode
)) ||
999 (!pmrChan
->rxCtcss
->multiFreq
&& (tnum
!= pmrChan
->rxCtcssIndex
))
1003 //TRACEX((" ctcss_detect() tnum=%i\n",tnum));
1005 ptdet
=&(pmrChan
->rxCtcss
->tdet
[tnum
]);
1007 points
=points2do
=pmrChan
->nSamplesRx
;
1008 fudgeFactor
=ptdet
->fudgeFactor
;
1009 binFactor
=ptdet
->binFactor
;
1011 while(ptdet
->counter
< (points2do
*CTCSS_SCOUNT_MUL
))
1013 //TRACEX((" ctcss_detect() - inner loop\n"));
1014 tmp
=(ptdet
->counter
/CTCSS_SCOUNT_MUL
)+1;
1015 ptdet
->counter
-=(tmp
*CTCSS_SCOUNT_MUL
);
1017 indexNow
=points
-points2do
;
1019 ptdet
->counter
+= ptdet
->counterFactor
;
1021 accum
= pInput
[indexNow
-1]; // dude's major bug fix!
1023 peakwas
=ptdet
->peak
;
1025 ptdet
->z
[ptdet
->zIndex
]+=
1026 (((accum
- ptdet
->z
[ptdet
->zIndex
])*binFactor
)/M_Q15
);
1028 peak
= abs(ptdet
->z
[0]-ptdet
->z
[2]) + abs(ptdet
->z
[1]-ptdet
->z
[3]);
1030 if (ptdet
->peak
< peak
)
1031 ptdet
->peak
+= ( ((peak
-ptdet
->peak
)*binFactor
)/M_Q15
);
1036 static const i16 a0
=13723;
1037 static const i16 a1
=-13723;
1044 ptdet
->zd
= ptdet
->peak
;
1045 temp1
= ptdet
->peak
* a0
;
1046 diffpeak
= (temp0
+ temp1
)/1024;
1049 if(diffpeak
<(-0.03*M_Q15
))ptdet
->dvd
-=4;
1050 else if(ptdet
->dvd
<0)ptdet
->dvd
++;
1052 if((ptdet
->dvd
< -12) && diffpeak
> (-0.02*M_Q15
))ptdet
->dvu
+=2;
1053 else if(ptdet
->dvu
)ptdet
->dvu
--;
1056 if(pmrChan
->rxCtcss
->decode
==tnum
)
1058 if(relax
)tmp
=(tmp
*55)/100;
1059 else tmp
=(tmp
*80)/100;
1062 if(ptdet
->peak
> tmp
)
1064 if(ptdet
->decode
<(fudgeFactor
*32))ptdet
->decode
++;
1066 else if(pmrChan
->rxCtcss
->decode
==tnum
)
1068 if(ptdet
->peak
> ptdet
->hyst
)ptdet
->decode
--;
1069 else if(relax
) ptdet
->decode
--;
1070 else ptdet
->decode
-=4;
1077 if((pmrChan
->rxCtcss
->decode
==tnum
) && !relax
&& (ptdet
->dvu
> (0.00075*M_Q15
)))
1080 ptdet
->z
[0]=ptdet
->z
[1]=ptdet
->z
[2]=ptdet
->z
[3]=ptdet
->dvu
=0;
1081 //printf("ctcss_detect() turnoff code!\n");
1084 if(ptdet
->decode
<0 || !pmrChan
->rxCarrierDetect
)ptdet
->decode
=0;
1086 if(ptdet
->decode
>=fudgeFactor
)thit
=tnum
;
1088 #if XPMR_DEBUG0 == 1
1089 //if(thit>=0 && thit==tnum)
1090 // printf(" ctcss_detect() %i %i %i %i \n",tnum,ptdet->peak,ptdet->setpt,ptdet->hyst);
1097 //tv1=ptdet->zi*100;
1098 while(indexDebug
<indexNow
)
1100 if(indexDebug
==0)lasttv0
=ptdet
->pDebug0
[points
-1];
1101 if(ptdet
->pDebug0
)ptdet
->pDebug0
[indexDebug
]=lasttv0
;
1103 if(indexDebug
==0)lasttv1
=ptdet
->pDebug1
[points
-1];
1104 if(ptdet
->pDebug1
)ptdet
->pDebug1
[indexDebug
]=lasttv1
;
1106 if(indexDebug
==0)lasttv2
=ptdet
->pDebug2
[points
-1];
1107 if(ptdet
->pDebug2
)ptdet
->pDebug2
[indexDebug
]=lasttv2
;
1116 ptdet
->zIndex
=(++ptdet
->zIndex
)%4;
1118 ptdet
->counter
-=(points2do
*CTCSS_SCOUNT_MUL
);
1120 #if XPMR_DEBUG0 == 1
1121 for(i
=indexWas
;i
<points
;i
++)
1123 if(ptdet
->pDebug0
)ptdet
->pDebug0
[i
]=lasttv0
;
1124 if(ptdet
->pDebug1
)ptdet
->pDebug1
[i
]=lasttv1
;
1125 if(ptdet
->pDebug2
)ptdet
->pDebug2
[i
]=lasttv2
;
1130 //TRACEX((" ctcss_detect() thit %i\n",thit));
1132 if(pmrChan
->rxCtcss
->BlankingTimer
>0)pmrChan
->rxCtcss
->BlankingTimer
-=points
;
1133 if(pmrChan
->rxCtcss
->BlankingTimer
<0)pmrChan
->rxCtcss
->BlankingTimer
=0;
1135 if(thit
>=0 && pmrChan
->rxCtcss
->decode
<0 && !pmrChan
->rxCtcss
->BlankingTimer
)
1137 pmrChan
->rxCtcss
->decode
=thit
;
1139 else if(thit
<0 && pmrChan
->rxCtcss
->decode
>=0)
1141 pmrChan
->rxCtcss
->BlankingTimer
=SAMPLE_RATE_NETWORK
/5;
1142 pmrChan
->rxCtcss
->decode
=-1;
1144 for(tnum
=0;tnum
<CTCSS_NUM_CODES
;tnum
++)
1147 ptdet
=&(pmrChan
->rxCtcss
->tdet
[tnum
]);
1149 ptdet
->z
[0]=ptdet
->z
[1]=ptdet
->z
[2]=ptdet
->z
[3]=0;
1152 //TRACEX((" ctcss_detect() thit %i %i\n",thit,pmrChan->rxCtcss->decode));
1158 static i16
TxTestTone(t_pmr_chan
*pChan
, i16 function
)
1162 pChan
->spsSigGen1
->enabled
=1;
1163 pChan
->spsSigGen1
->option
=1;
1164 pChan
->spsTx
->source
=pChan
->spsSigGen1
->sink
;
1168 pChan
->spsSigGen1
->option
=3;
1174 sampling rate is 48KS/s
1175 samples are all 16 bits
1176 samples are filtered and decimated by 1/6th
1178 t_pmr_chan
*createPmrChannel(t_pmr_chan
*tChan
, i16 numSamples
)
1184 t_dec_ctcss
*pDecCtcss
;
1187 TRACEX(("createPmrChannel(%p,%i)\n",tChan
,numSamples
));
1189 pChan
= (t_pmr_chan
*)calloc(sizeof(t_pmr_chan
),1);
1193 printf("createPmrChannel() failed\n");
1197 pChan
->nSamplesRx
=numSamples
;
1198 pChan
->nSamplesTx
=numSamples
;
1200 pChan
->index
=pmrChanIndex
++;
1202 for(i
=0;i
<CTCSS_NUM_CODES
;i
++)
1204 pChan
->rxCtcssMap
[i
]=-1;
1207 pChan
->rxCtcssIndex
=-1;
1211 pChan
->rxNoiseSquelchEnable
=0;
1212 pChan
->rxHpfEnable
=0;
1213 pChan
->rxDeEmpEnable
=0;
1214 pChan
->rxCenterSlicerEnable
=0;
1215 pChan
->rxCtcssDecodeEnable
=0;
1216 pChan
->rxDcsDecodeEnable
=0;
1218 pChan
->rxCarrierPoint
= 17000;
1219 pChan
->rxCarrierHyst
= 2500;
1221 pChan
->rxCtcssFreq
=103.5;
1223 pChan
->txHpfEnable
=0;
1224 pChan
->txLimiterEnable
=0;
1225 pChan
->txPreEmpEnable
=0;
1226 pChan
->txLpfEnable
=1;
1227 pChan
->txCtcssFreq
=103.5;
1228 pChan
->txMixA
=TX_OUT_VOICE
;
1229 pChan
->txMixB
=TX_OUT_LSD
;
1233 pChan
->rxDemod
=tChan
->rxDemod
;
1234 pChan
->rxCdType
=tChan
->rxCdType
;
1235 pChan
->rxSquelchPoint
= tChan
->rxSquelchPoint
;
1236 pChan
->rxCarrierHyst
= 3000;
1237 pChan
->rxCtcssFreq
=tChan
->rxCtcssFreq
;
1239 for(i
=0;i
<CTCSS_NUM_CODES
;i
++)
1240 pChan
->rxCtcssMap
[i
]=tChan
->rxCtcssMap
[i
];
1242 pChan
->txMod
=tChan
->txMod
;
1243 pChan
->txHpfEnable
=1;
1244 pChan
->txLpfEnable
=1;
1245 pChan
->txCtcssFreq
=tChan
->txCtcssFreq
;
1246 pChan
->txMixA
=tChan
->txMixA
;
1247 pChan
->txMixB
=tChan
->txMixB
;
1248 pChan
->radioDuplex
=tChan
->radioDuplex
;
1251 TRACEX(("misc settings \n"));
1253 if(pChan
->rxCdType
==CD_XPMR_NOISE
){
1254 pChan
->rxNoiseSquelchEnable
=1;
1257 if(pChan
->rxDemod
==RX_AUDIO_FLAT
){
1258 pChan
->rxHpfEnable
=1;
1259 pChan
->rxDeEmpEnable
=1;
1262 pChan
->rxCarrierPoint
=(pChan
->rxSquelchPoint
*32767)/100;
1263 pChan
->rxCarrierHyst
= 3000; //pChan->rxCarrierPoint/15;
1265 pChan
->rxDcsDecodeEnable
=0;
1267 if(pChan
->rxCtcssFreq
!=0){
1268 pChan
->rxHpfEnable
=1;
1269 pChan
->rxCenterSlicerEnable
=1;
1270 pChan
->rxCtcssDecodeEnable
=1;
1271 pChan
->rxCtcssIndex
=CtcssFreqIndex(pChan
->rxCtcssFreq
);
1275 pChan
->txPreEmpEnable
=1;
1276 pChan
->txLimiterEnable
=1;
1279 TRACEX(("calloc buffers \n"));
1281 pChan
->pRxDemod
= calloc(numSamples
,2);
1282 pChan
->pRxNoise
= calloc(numSamples
,2);
1283 pChan
->pRxBase
= calloc(numSamples
,2);
1284 pChan
->pRxHpf
= calloc(numSamples
,2);
1285 pChan
->pRxLsd
= calloc(numSamples
,2);
1286 pChan
->pRxSpeaker
= calloc(numSamples
,2);
1287 pChan
->pRxCtcss
= calloc(numSamples
,2);
1288 pChan
->pRxDcTrack
= calloc(numSamples
,2);
1289 pChan
->pRxLsdLimit
= calloc(numSamples
,2);
1292 pChan
->pTxBase
= calloc(numSamples
,2);
1293 pChan
->pTxHpf
= calloc(numSamples
,2);
1294 pChan
->pTxPreEmp
= calloc(numSamples
,2);
1295 pChan
->pTxLimiter
= calloc(numSamples
,2);
1296 pChan
->pTxLsd
= calloc(numSamples
,2);
1297 pChan
->pTxLsdLpf
= calloc(numSamples
,2);
1298 pChan
->pTxComposite
= calloc(numSamples
,2);
1299 pChan
->pSigGen0
= calloc(numSamples
,2);
1300 pChan
->pSigGen1
= calloc(numSamples
,2);
1302 pChan
->pTxCode
= calloc(numSamples
,2);
1303 pChan
->pTxOut
= calloc(numSamples
,2*2*6); // output buffer
1305 #if XPMR_DEBUG0 == 1
1306 pChan
->pTxPttIn
= calloc(numSamples
,2);
1307 pChan
->pTxPttOut
= calloc(numSamples
,2);
1308 pChan
->prxDebug0
= calloc(numSamples
,2);
1309 pChan
->prxDebug1
= calloc(numSamples
,2);
1310 pChan
->prxDebug2
= calloc(numSamples
,2);
1311 pChan
->prxDebug3
= calloc(numSamples
,2);
1312 pChan
->ptxDebug0
= calloc(numSamples
,2);
1313 pChan
->ptxDebug1
= calloc(numSamples
,2);
1314 pChan
->ptxDebug2
= calloc(numSamples
,2);
1315 pChan
->ptxDebug3
= calloc(numSamples
,2);
1316 pChan
->pNull
= calloc(numSamples
,2);
1317 for(i
=0;i
<numSamples
;i
++)pChan
->pNull
[i
]=((i
%(numSamples
/2))*8000)-4000;
1320 TRACEX(("create ctcss\n"));
1322 pDecCtcss
= (t_dec_ctcss
*)calloc(sizeof(t_dec_ctcss
),1);
1324 pChan
->rxCtcss
=pDecCtcss
;
1325 pDecCtcss
->enabled
=1;
1326 pDecCtcss
->gain
=1*M_Q8
;
1327 pDecCtcss
->limit
=8192;
1328 pDecCtcss
->input
=pChan
->pRxLsdLimit
;
1329 pDecCtcss
->testIndex
=pChan
->rxCtcssIndex
;
1330 if(!pDecCtcss
->testIndex
)pDecCtcss
->testIndex
=1;
1331 pChan
->rxCtcssMap
[pChan
->rxCtcssIndex
]=pChan
->rxCtcssIndex
;
1332 pDecCtcss
->decode
=-1;
1334 for(i
=0;i
<CTCSS_NUM_CODES
;i
++)
1336 ptdet
=&(pChan
->rxCtcss
->tdet
[i
]);
1338 ptdet
->setpt
=(M_Q15
*0.067); // 0.069
1339 ptdet
->hyst
=(M_Q15
*0.020);
1340 ptdet
->counterFactor
=coef_ctcss_div
[i
];
1341 ptdet
->binFactor
=(M_Q15
*0.135); // was 0.140
1342 ptdet
->fudgeFactor
=8;
1345 // General Purpose Function Generator
1346 pSps
=pChan
->spsSigGen1
=createPmrSps();
1347 pSps
->parentChan
=pChan
;
1348 pSps
->sink
=pChan
->pSigGen1
;
1351 pSps
->sigProc
=SigGen
;
1352 pSps
->nSamples
=pChan
->nSamplesTx
;
1353 pSps
->sampleRate
=SAMPLE_RATE_NETWORK
;
1354 pSps
->freq
=10000; // in increments of 0.1 Hz
1355 pSps
->outputGain
=(.25*M_Q8
);
1357 pSps
->interpolate
=1;
1363 pSps
= pChan
->spsSigGen0
= createPmrSps();
1364 pSps
->parentChan
=pChan
;
1365 pSps
->sink
=pChan
->pTxLsd
;
1366 pSps
->sigProc
=SigGen
;
1369 pSps
->nSamples
=pChan
->nSamplesTx
;
1370 pSps
->sampleRate
=SAMPLE_RATE_NETWORK
;
1371 pSps
->freq
=pChan
->txCtcssFreq
*10; // in increments of 0.1 Hz
1372 pSps
->outputGain
=(0.5*M_Q8
);
1374 pSps
->interpolate
=1;
1379 // Tx LSD Low Pass Filter
1380 pSps
=pChan
->spsTxLsdLpf
=pSps
->nextSps
=createPmrSps();
1381 pSps
->source
=pChan
->pTxLsd
;
1382 pSps
->sink
=pChan
->pTxLsdLpf
;
1383 pSps
->sigProc
=pmr_gp_fir
;
1387 pSps
->nSamples
=pChan
->nSamplesTx
;
1388 pSps
->decimator
=pSps
->decimate
=1;
1389 pSps
->interpolate
=1;
1390 pSps
->inputGain
=(1*M_Q8
);
1391 pSps
->outputGain
=(1*M_Q8
);
1393 if(pChan
->txCtcssFreq
>203.0)
1395 pSps
->ncoef
=taps_fir_lpf_250_9_66
;
1397 pSps
->coef
=(void*)coef_fir_lpf_250_9_66
;
1398 pSps
->nx
=taps_fir_lpf_250_9_66
;
1400 pSps
->x
=(void*)(calloc(pSps
->nx
,pSps
->size_x
));
1401 pSps
->calcAdjust
=gain_fir_lpf_250_9_66
;
1405 pSps
->ncoef
=taps_fir_lpf_215_9_88
;
1407 pSps
->coef
=(void*)coef_fir_lpf_215_9_88
;
1408 pSps
->nx
=taps_fir_lpf_215_9_88
;
1410 pSps
->x
=(void*)(calloc(pSps
->nx
,pSps
->size_x
));
1411 pSps
->calcAdjust
=gain_fir_lpf_215_9_88
;
1414 pSps
->inputGain
=(1*M_Q8
);
1415 pSps
->outputGain
=(1*M_Q8
);
1417 if(pSps
==NULL
)printf("Error: calloc(), createPmrChannel()\n");
1421 TRACEX(("create rx\n"));
1424 // allocate space for first sps and set pointers
1425 pSps
=pChan
->spsRx
=createPmrSps();
1426 pSps
->parentChan
=pChan
;
1427 pSps
->source
=NULL
; //set when called
1428 pSps
->sink
=pChan
->pRxBase
;
1429 pSps
->sigProc
=pmr_rx_frontend
;
1431 pSps
->decimator
=pSps
->decimate
=6;
1432 pSps
->interpolate
=pSps
->interpolate
=1;
1433 pSps
->nSamples
=pChan
->nSamplesRx
;
1434 pSps
->ncoef
=taps_fir_bpf_noise_1
;
1436 pSps
->coef
=(void*)coef_fir_lpf_3K_1
;
1437 pSps
->coef2
=(void*)coef_fir_bpf_noise_1
;
1438 pSps
->nx
=taps_fir_bpf_noise_1
;
1440 pSps
->x
=(void*)(calloc(pSps
->nx
,pSps
->size_coef
));
1441 pSps
->calcAdjust
=(gain_fir_lpf_3K_1
*256)/0x0100;
1442 pSps
->outputGain
=(1.0*M_Q8
);
1444 pSps
->hyst
=pChan
->rxCarrierHyst
;
1445 pSps
->setpt
=pChan
->rxCarrierPoint
;
1446 pChan
->prxSquelchAdjust
=&pSps
->setpt
;
1447 #if XPMR_DEBUG0 == 1
1448 pSps
->debugBuff0
=pChan
->pRxDemod
;
1449 pSps
->debugBuff1
=pChan
->pRxNoise
;
1450 pSps
->debugBuff2
=pChan
->prxDebug0
;
1454 // allocate space for next sps and set pointers
1455 // Rx SubAudible Decoder Low Pass Filter
1456 pSps
=pSps
->nextSps
=createPmrSps();
1457 pSps
->parentChan
=pChan
;
1458 pSps
->source
=pChan
->pRxBase
;
1459 pSps
->sink
=pChan
->pRxLsd
;
1460 pSps
->sigProc
=pmr_gp_fir
;
1464 pSps
->nSamples
=pChan
->nSamplesRx
;
1465 pSps
->decimator
=pSps
->decimate
=1;
1466 pSps
->interpolate
=1;
1468 if(pChan
->rxCtcssFreq
>203.5)
1470 pSps
->ncoef
=taps_fir_lpf_250_9_66
;
1472 pSps
->coef
=(void*)coef_fir_lpf_250_9_66
;
1473 pSps
->nx
=taps_fir_lpf_250_9_66
;
1475 pSps
->x
=(void*)(calloc(pSps
->nx
,pSps
->size_x
));
1476 pSps
->calcAdjust
=gain_fir_lpf_250_9_66
;
1480 pSps
->ncoef
=taps_fir_lpf_215_9_88
;
1482 pSps
->coef
=(void*)coef_fir_lpf_215_9_88
;
1483 pSps
->nx
=taps_fir_lpf_215_9_88
;
1485 pSps
->x
=(void*)(calloc(pSps
->nx
,pSps
->size_x
));
1486 pSps
->calcAdjust
=gain_fir_lpf_215_9_88
;
1489 pSps
->inputGain
=(1*M_Q8
);
1490 pSps
->outputGain
=(1*M_Q8
);
1491 pChan
->prxCtcssMeasure
=pSps
->sink
;
1492 pChan
->prxCtcssAdjust
=&(pSps
->outputGain
);
1495 // allocate space for next sps and set pointers
1497 if(pChan
->rxCenterSlicerEnable
)
1499 pSps
=pSps
->nextSps
=createPmrSps();
1500 pSps
->parentChan
=pChan
;
1501 pSps
->source
=pChan
->pRxLsd
;
1502 pSps
->sink
=pChan
->pRxDcTrack
;
1503 pSps
->buff
=pChan
->pRxLsdLimit
;
1504 pSps
->sigProc
=CenterSlicer
;
1506 pSps
->nSamples
=pChan
->nSamplesRx
;
1507 pSps
->discfactor
=800;
1508 pSps
->inputGain
=(1*M_Q8
);
1509 pSps
->outputGain
=(1*M_Q8
);
1511 pSps
->inputGainB
=1000; // limiter set point
1514 // allocate space for next sps and set pointers
1516 pSps
=pSps
->nextSps
=createPmrSps();
1517 pSps
->parentChan
=pChan
;
1518 pChan
->spsRxHpf
=pSps
;
1519 pSps
->source
=pChan
->pRxBase
;
1520 pSps
->sink
=pChan
->pRxHpf
;
1521 pSps
->sigProc
=pmr_gp_fir
;
1525 pSps
->nSamples
=pChan
->nSamplesRx
;
1526 pSps
->decimator
=pSps
->decimate
=1;
1527 pSps
->interpolate
=1;
1528 pSps
->ncoef
=taps_fir_hpf_300_9_66
;
1530 pSps
->coef
=(void*)coef_fir_hpf_300_9_66
;
1531 pSps
->nx
=taps_fir_hpf_300_9_66
;
1533 pSps
->x
=(void*)(calloc(pSps
->nx
,pSps
->size_x
));
1534 if(pSps
==NULL
)printf("Error: calloc(), createPmrChannel()\n");
1535 pSps
->calcAdjust
=gain_fir_hpf_300_9_66
;
1536 pSps
->inputGain
=(1*M_Q8
);
1537 pSps
->outputGain
=(1*M_Q8
);
1538 pChan
->spsRxOut
=pSps
;
1540 // allocate space for next sps and set pointers
1542 if(pChan
->rxDeEmpEnable
){
1543 pSps
=pSps
->nextSps
=createPmrSps();
1544 pSps
->parentChan
=pChan
;
1545 pChan
->spsRxDeEmp
=pSps
;
1546 pSps
->source
=pChan
->pRxHpf
;
1547 pSps
->sink
=pChan
->pRxSpeaker
;
1548 pChan
->spsRxOut
=pSps
; // OUTPUT STRUCTURE! maw
1549 pSps
->sigProc
=gp_inte_00
;
1551 pSps
->nSamples
=pChan
->nSamplesRx
;
1553 pSps
->ncoef
=taps_int_lpf_300_1_2
;
1555 pSps
->coef
=(void*)coef_int_lpf_300_1_2
;
1557 pSps
->nx
=taps_int_lpf_300_1_2
;
1559 pSps
->x
=(void*)(calloc(pSps
->nx
,pSps
->size_x
));
1560 if(pSps
==NULL
)printf("Error: calloc(), createPmrChannel()\n");
1561 pSps
->calcAdjust
=gain_int_lpf_300_1_2
/2;
1562 pSps
->inputGain
=(1.0*M_Q8
);
1563 pSps
->outputGain
=(1.0*M_Q8
);
1564 pChan
->prxVoiceMeasure
=pSps
->sink
;
1565 pChan
->prxVoiceAdjust
=&(pSps
->outputGain
);
1568 if(pChan
->rxDelayLineEnable
)
1570 TRACEX(("create delayline\n"));
1571 pSps
=pChan
->spsDelayLine
=pSps
->nextSps
=createPmrSps();
1572 pSps
->sigProc
=DelayLine
;
1573 pSps
->source
=pChan
->pRxSpeaker
;
1574 pSps
->sink
=pChan
->pRxSpeaker
;
1576 pSps
->inputGain
=1*M_Q8
;
1577 pSps
->outputGain
=1*M_Q8
;
1578 pSps
->nSamples
=pChan
->nSamplesRx
;
1579 pSps
->buffSize
=4096;
1580 pSps
->buff
=calloc(4096,2); // one second maximum
1581 pSps
->buffLead
= (SAMPLE_RATE_NETWORK
*0.100);
1582 pSps
->buffOutIndex
=0;
1585 if(pChan
->rxCdType
==CD_XPMR_VOX
)
1587 TRACEX(("create vox measureblock\n"));
1588 pSps
=pChan
->spsRxVox
=pSps
->nextSps
=createPmrSps();
1589 pSps
->sigProc
=MeasureBlock
;
1590 pSps
->parentChan
=pChan
;
1591 pSps
->source
=pChan
->pRxBase
;
1592 pSps
->sink
=pChan
->prxDebug1
;
1593 pSps
->inputGain
=1*M_Q8
;
1594 pSps
->outputGain
=1*M_Q8
;
1595 pSps
->nSamples
=pChan
->nSamplesRx
;
1597 pSps
->setpt
=(0.01*M_Q15
);
1598 pSps
->hyst
=(pSps
->setpt
/10);
1602 // tuning measure block
1603 pSps
=pChan
->spsMeasure
=pSps
->nextSps
=createPmrSps();
1604 pSps
->parentChan
=pChan
;
1605 pSps
->source
=pChan
->spsRx
->sink
;
1606 pSps
->sink
=pChan
->prxDebug2
;
1607 pSps
->sigProc
=MeasureBlock
;
1609 pSps
->nSamples
=pChan
->nSamplesRx
;
1610 pSps
->discfactor
=10;
1612 pSps
->nextSps
=NULL
; // last sps in chain RX
1615 // CREATE TRANSMIT CHAIN
1616 TRACEX((" create tx\n"));
1620 // allocate space for first sps and set pointers
1622 // Tx HPF SubAudible
1623 if(pChan
->txHpfEnable
)
1625 pSps
=createPmrSps();
1627 pSps
->source
=pChan
->pTxBase
;
1628 pSps
->sink
=pChan
->pTxHpf
;
1629 pSps
->sigProc
=pmr_gp_fir
;
1633 pSps
->nSamples
=pChan
->nSamplesTx
;
1634 pSps
->decimator
=pSps
->decimate
=1;
1635 pSps
->interpolate
=1;
1636 pSps
->ncoef
=taps_fir_hpf_300_9_66
;
1638 pSps
->coef
=(void*)coef_fir_hpf_300_9_66
;
1639 pSps
->nx
=taps_fir_hpf_300_9_66
;
1641 pSps
->x
=(void*)(calloc(pSps
->nx
,pSps
->size_x
));
1642 if(pSps
==NULL
)printf("Error: calloc(), createPmrChannel()\n");
1643 pSps
->calcAdjust
=gain_fir_hpf_300_9_66
;
1644 pSps
->inputGain
=(1*M_Q8
);
1645 pSps
->outputGain
=(1*M_Q8
);
1646 inputTmp
=pChan
->pTxHpf
;
1650 if(pChan
->txPreEmpEnable
)
1652 if(pSps
==NULL
) pSps
=pChan
->spsTx
=createPmrSps();
1653 else pSps
=pSps
->nextSps
=createPmrSps();
1655 pSps
->parentChan
=pChan
;
1656 pSps
->source
=inputTmp
;
1657 pSps
->sink
=pChan
->pTxPreEmp
;
1659 pSps
->sigProc
=gp_diff
;
1661 pSps
->nSamples
=pChan
->nSamplesTx
;
1663 pSps
->ncoef
=taps_int_hpf_4000_1_2
;
1665 pSps
->coef
=(void*)coef_int_hpf_4000_1_2
;
1667 pSps
->nx
=taps_int_hpf_4000_1_2
;
1669 pSps
->x
=(void*)(calloc(pSps
->nx
,pSps
->size_x
));
1670 if(pSps
==NULL
)printf("Error: calloc(), createPmrChannel()\n");
1671 pSps
->outputGain
=(1*M_Q8
);
1672 pSps
->calcAdjust
=gain_int_hpf_4000_1_2
;
1673 pSps
->inputGain
=(1*M_Q8
);
1674 pSps
->outputGain
=(1*M_Q8
);
1675 inputTmp
=pSps
->sink
;
1679 if(pChan
->txLimiterEnable
)
1681 if(pSps
==NULL
) pSps
=pChan
->spsTx
=createPmrSps();
1682 else pSps
=pSps
->nextSps
=createPmrSps();
1683 pSps
->source
=inputTmp
;
1684 pSps
->sink
=pChan
->pTxLimiter
;
1685 pSps
->sigProc
=SoftLimiter
;
1687 pSps
->nSamples
=pChan
->nSamplesTx
;
1688 pSps
->inputGain
=(1*M_Q8
);
1689 pSps
->outputGain
=(1*M_Q8
);
1691 inputTmp
=pSps
->sink
;
1694 // Composite Mix of Voice and LSD
1695 if((pChan
->txMixA
==TX_OUT_COMPOSITE
)||(pChan
->txMixB
==TX_OUT_COMPOSITE
))
1698 pSps
=pChan
->spsTx
=createPmrSps();
1700 pSps
=pSps
->nextSps
=createPmrSps();
1701 pSps
->source
=inputTmp
;
1702 pSps
->sourceB
=pChan
->pTxLsdLpf
; //asdf ??? !!! maw pTxLsdLpf
1703 pSps
->sink
=pChan
->pTxComposite
;
1704 pSps
->sigProc
=pmrMixer
;
1706 pSps
->nSamples
=pChan
->nSamplesTx
;
1707 pSps
->inputGain
=2*M_Q8
;
1708 pSps
->inputGainB
=1*M_Q8
/8;
1709 pSps
->outputGain
=1*M_Q8
;
1711 inputTmp
=pSps
->sink
;
1712 pChan
->ptxCtcssAdjust
=&pSps
->inputGainB
;
1715 // Chan A Upsampler and Filter
1716 if(pSps
==NULL
) pSps
=pChan
->spsTx
=createPmrSps();
1717 else pSps
=pSps
->nextSps
=createPmrSps();
1719 pChan
->spsTxOutA
=pSps
;
1720 if(!pChan
->spsTx
)pChan
->spsTx
=pSps
;
1721 pSps
->parentChan
=pChan
;
1723 if(pChan
->txMixA
==TX_OUT_COMPOSITE
)
1725 pSps
->source
=pChan
->pTxComposite
;
1727 else if(pChan
->txMixA
==TX_OUT_LSD
)
1729 pSps
->source
=pChan
->pTxLsdLpf
;
1731 else if(pChan
->txMixA
==TX_OUT_VOICE
)
1733 pSps
->source
=pChan
->pTxHpf
;
1735 else if (pChan
->txMixA
==TX_OUT_AUX
)
1737 pSps
->source
=inputTmp
;
1744 pSps
->sink
=pChan
->pTxOut
;
1745 pSps
->sigProc
=pmr_gp_fir
;
1749 pSps
->nSamples
=pChan
->nSamplesTx
;
1750 pSps
->interpolate
=6;
1751 pSps
->ncoef
=taps_fir_lpf_3K_1
;
1753 pSps
->coef
=(void*)coef_fir_lpf_3K_1
;
1754 pSps
->nx
=taps_fir_lpf_3K_1
;
1756 pSps
->x
=(void*)(calloc(pSps
->nx
,pSps
->size_x
));
1757 if(pSps
==NULL
)printf("Error: calloc(), createPmrChannel()\n");
1758 pSps
->calcAdjust
=gain_fir_lpf_3K_1
;
1759 pSps
->inputGain
=(1*M_Q8
);
1760 pSps
->outputGain
=(1*M_Q8
);
1761 if(pChan
->txMixA
==pChan
->txMixB
)pSps
->monoOut
=1;
1762 else pSps
->monoOut
=0;
1765 // Chan B Upsampler and Filter
1766 if((pChan
->txMixA
!=pChan
->txMixB
)&&(pChan
->txMixB
!=TX_OUT_OFF
))
1768 if(pSps
==NULL
) pSps
=pChan
->spsTx
=createPmrSps();
1769 else pSps
=pSps
->nextSps
=createPmrSps();
1771 pChan
->spsTxOutB
=pSps
;
1772 pSps
->parentChan
=pChan
;
1773 if(pChan
->txMixB
==TX_OUT_COMPOSITE
)
1775 pSps
->source
=pChan
->pTxComposite
;
1777 else if(pChan
->txMixB
==TX_OUT_LSD
)
1779 pSps
->source
=pChan
->pTxLsdLpf
;
1780 // pChan->ptxCtcssAdjust=&pSps->inputGain;
1782 else if(pChan
->txMixB
==TX_OUT_VOICE
)
1784 pSps
->source
=inputTmp
;
1786 else if(pChan
->txMixB
==TX_OUT_AUX
)
1788 pSps
->source
=pChan
->pTxHpf
;
1795 pSps
->sink
=pChan
->pTxOut
;
1796 pSps
->sigProc
=pmr_gp_fir
;
1801 pSps
->nSamples
=pChan
->nSamplesTx
;
1802 pSps
->interpolate
=6;
1803 pSps
->ncoef
=taps_fir_lpf_3K_1
;
1805 pSps
->coef
=(void*)coef_fir_lpf_3K_1
;
1806 pSps
->nx
=taps_fir_lpf_3K_1
;
1808 pSps
->x
=(void*)(calloc(pSps
->nx
,pSps
->size_x
));
1809 if(pSps
==NULL
)printf("Error: calloc(), createPmrChannel()\n");
1810 pSps
->calcAdjust
=(gain_fir_lpf_3K_1
);
1811 pSps
->inputGain
=(1*M_Q8
);
1812 pSps
->outputGain
=(1*M_Q8
);
1818 #if XPMR_DEBUG0 == 1
1821 TRACEX((" configure tracing\n"));
1823 pChan
->rxCtcss
->pDebug0
=calloc(numSamples
,2);
1824 pChan
->rxCtcss
->pDebug1
=calloc(numSamples
,2);
1825 pChan
->rxCtcss
->pDebug2
=calloc(numSamples
,2);
1827 for(i
=0;i
<CTCSS_NUM_CODES
;i
++){
1828 ptdet
=&(pChan
->rxCtcss
->tdet
[i
]);
1829 ptdet
->pDebug0
=calloc(numSamples
,2);
1830 ptdet
->pDebug1
=calloc(numSamples
,2);
1831 ptdet
->pDebug2
=calloc(numSamples
,2);
1834 // buffer, 2 bytes per sample, and 16 channels
1835 pChan
->prxDebug
=calloc(numSamples
*16,2);
1836 pChan
->ptxDebug
=calloc(numSamples
*16,2);
1840 TRACEX((" createPmrChannel() end\n"));
1846 i16
destroyPmrChannel(t_pmr_chan
*pChan
)
1848 t_pmr_sps
*pmr_sps
, *tmp_sps
;
1851 TRACEX(("destroyPmrChannel()\n"));
1853 free(pChan
->pRxDemod
);
1854 free(pChan
->pRxNoise
);
1855 free(pChan
->pRxBase
);
1856 free(pChan
->pRxHpf
);
1857 free(pChan
->pRxLsd
);
1858 free(pChan
->pRxSpeaker
);
1859 free(pChan
->pRxDcTrack
);
1860 if(pChan
->pRxLsdLimit
)free(pChan
->pRxLsdLimit
);
1861 free(pChan
->pTxBase
);
1862 free(pChan
->pTxHpf
);
1863 free(pChan
->pTxPreEmp
);
1864 free(pChan
->pTxLimiter
);
1865 free(pChan
->pTxLsd
);
1866 free(pChan
->pTxLsdLpf
);
1867 if(pChan
->pTxComposite
)free(pChan
->pTxComposite
);
1868 free(pChan
->pTxCode
);
1869 free(pChan
->pTxOut
);
1871 if(pChan
->pSigGen0
)free(pChan
->pSigGen0
);
1872 if(pChan
->pSigGen1
)free(pChan
->pSigGen1
);
1874 #if XPMR_DEBUG0 == 1
1875 free(pChan
->pTxPttIn
);
1876 free(pChan
->pTxPttOut
);
1877 if(pChan
->prxDebug
)free(pChan
->prxDebug
);
1878 if(pChan
->ptxDebug
)free(pChan
->ptxDebug
);
1879 free(pChan
->rxCtcss
->pDebug0
);
1880 free(pChan
->rxCtcss
->pDebug1
);
1882 free(pChan
->prxDebug0
);
1883 free(pChan
->prxDebug1
);
1884 free(pChan
->prxDebug2
);
1885 free(pChan
->prxDebug3
);
1887 free(pChan
->ptxDebug0
);
1888 free(pChan
->ptxDebug1
);
1889 free(pChan
->ptxDebug2
);
1890 free(pChan
->ptxDebug3
);
1892 for(i
=0;i
<CTCSS_NUM_CODES
;i
++)
1894 free(pChan
->rxCtcss
->tdet
[i
].pDebug0
);
1895 free(pChan
->rxCtcss
->tdet
[i
].pDebug1
);
1896 free(pChan
->rxCtcss
->tdet
[i
].pDebug2
);
1900 free(pChan
->pRxCtcss
);
1902 pmr_sps
=pChan
->spsRx
;
1907 pmr_sps
= tmp_sps
->nextSps
;
1908 destroyPmrSps(tmp_sps
);
1917 t_pmr_sps
*createPmrSps(void)
1921 TRACEX(("createPmrSps()\n"));
1923 pSps
= (t_pmr_sps
*)calloc(sizeof(t_pmr_sps
),1);
1925 if(!pSps
)printf("Error: createPmrSps()\n");
1927 // pSps->x=calloc(pSps->nx,pSps->size_x);
1933 i16
destroyPmrSps(t_pmr_sps
*pSps
)
1935 TRACEX(("destroyPmrSps(%i)\n",pSps
->index
));
1937 if(pSps
->x
!=NULL
)free(pSps
->x
);
1942 PmrRx does the whole buffer
1944 i16
PmrRx(t_pmr_chan
*pChan
, i16
*input
, i16
*output
)
1949 TRACEX(("PmrRx() %i\n",pChan
->frameCountRx
));
1952 printf("PmrRx() pChan == NULL\n");
1956 pChan
->frameCountRx
++;
1958 pmr_sps
=pChan
->spsRx
; // first sps
1959 pmr_sps
->source
=input
;
1961 if(output
!=NULL
)pChan
->spsRxOut
->sink
=output
; //last sps
1964 if(pChan
->inputBlanking
>0)
1966 pChan
->inputBlanking
-=pChan
->nSamplesRx
;
1967 if(pChan
->inputBlanking
<0)pChan
->inputBlanking
=0;
1968 for(i
=0;i
<pChan
->nSamplesRx
*6;i
++)
1973 // || (pChan->radioDuplex && (pChan->pttIn || pChan->pttOut)))
1974 if(pChan
->rxCpuSaver
&& !pChan
->rxCarrierDetect
)
1976 if(pChan
->spsRxHpf
)pChan
->spsRxHpf
->enabled
=0;
1977 if(pChan
->spsRxDeEmp
)pChan
->spsRxDeEmp
->enabled
=0;
1981 if(pChan
->spsRxHpf
)pChan
->spsRxHpf
->enabled
=1;
1982 if(pChan
->spsRxDeEmp
)pChan
->spsRxDeEmp
->enabled
=1;
1986 while(pmr_sps
!=NULL
&& pmr_sps
!=0)
1988 TRACEX(("PmrRx() sps %i\n",i
++));
1989 pmr_sps
->sigProc(pmr_sps
);
1990 pmr_sps
= (t_pmr_sps
*)(pmr_sps
->nextSps
);
1991 //pmr_sps=NULL; // sph maw
1994 #define XPMR_VOX_HANGTIME 2000
1996 if(pChan
->rxCdType
==CD_XPMR_VOX
)
1998 if(pChan
->spsRxVox
->compOut
)
2000 pChan
->rxVoxTimer
=XPMR_VOX_HANGTIME
; //VOX HangTime in ms
2002 if(pChan
->rxVoxTimer
>0)
2004 pChan
->rxVoxTimer
-=MS_PER_FRAME
;
2005 pChan
->rxCarrierDetect
=1;
2009 pChan
->rxVoxTimer
=0;
2010 pChan
->rxCarrierDetect
=0;
2015 pChan
->rxCarrierDetect
=!pChan
->spsRx
->compOut
;
2018 if( !pChan
->rxCpuSaver
|| pChan
->rxCarrierDetect
2019 || pChan
->rxCtcss
->decode
!=-1) ctcss_detect(pChan
);
2021 #if XPMR_DEBUG0 == 1
2022 // TRACEX(("Write file.\n"));
2024 if(pChan
->b
.rxCapture
)
2026 for(i
=0;i
<pChan
->nSamplesRx
;i
++)
2028 pChan
->prxDebug
[ii
++]=input
[i
*2*6]; // input data
2029 pChan
->prxDebug
[ii
++]=output
[i
]; // output data
2030 pChan
->prxDebug
[ii
++]=pChan
->rxCarrierDetect
*M_Q14
; // carrier detect
2032 pChan
->prxDebug
[ii
++]=pChan
->rxCtcss
->decode
*M_Q15
/CTCSS_NUM_CODES
; // decoded ctcss
2034 pChan
->prxDebug
[ii
++]=0;
2036 pChan
->prxDebug
[ii
++]=pChan
->pRxNoise
[i
]; // rssi
2037 pChan
->prxDebug
[ii
++]=pChan
->pRxBase
[i
]; // decimated, low pass filtered
2038 pChan
->prxDebug
[ii
++]=pChan
->pRxHpf
[i
]; // output to network
2039 pChan
->prxDebug
[ii
++]=pChan
->pRxSpeaker
[i
];
2041 pChan
->prxDebug
[ii
++]=pChan
->pRxLsd
[i
]; // CTCSS Filtered
2042 pChan
->prxDebug
[ii
++]=pChan
->pRxDcTrack
[i
]; // DC Restoration
2043 pChan
->prxDebug
[ii
++]=pChan
->pRxLsdLimit
[i
]; // Amplitude Limited
2045 //pChan->prxDebug[ii++]=pChan->rxCtcss->tdet[pChan->rxCtcss->testIndex+1].pDebug0[i]; // Upper Adjacent CTCSS Code
2046 pChan
->prxDebug
[ii
++]=pChan
->rxCtcss
->tdet
[pChan
->rxCtcss
->testIndex
].pDebug0
[i
]; // Primary CTCSS Code
2047 pChan
->prxDebug
[ii
++]=pChan
->rxCtcss
->tdet
[pChan
->rxCtcss
->testIndex
].pDebug1
[i
]; // dv/dt of decoder output
2048 pChan
->prxDebug
[ii
++]=pChan
->rxCtcss
->tdet
[pChan
->rxCtcss
->testIndex
].pDebug2
[i
];
2050 //pChan->prxDebug[ii++]=pChan->rxCtcss->tdet[pChan->rxCtcss->testIndex-1].pDebug0[i]; // Lower Adjacent CTCSS Code
2052 pChan
->prxDebug
[ii
++]=pChan
->prxDebug1
[i
]; // Measure Output for VOX
2053 pChan
->prxDebug
[ii
++]=pChan
->prxDebug2
[i
]; // Measure Output for Tuning
2061 PmrTx does the whole buffer
2063 i16
PmrTx(t_pmr_chan
*pChan
, i16
*input
, i16
*output
)
2068 pChan
->frameCountTx
++;
2070 TRACEX(("PmrTx() %i\n",pChan
->frameCountTx
));
2073 printf("PmrTx() pChan == NULL\n");
2077 if(pChan
->b
.startSpecialTone
)
2079 pChan
->b
.startSpecialTone
=0;
2080 pChan
->spsSigGen1
->option
=1;
2081 pChan
->spsSigGen1
->enabled
=1;
2082 pChan
->b
.doingSpecialTone
=1;
2083 } else if(pChan
->b
.stopSpecialTone
)
2085 pChan
->b
.stopSpecialTone
=0;
2086 pChan
->spsSigGen1
->option
=0;
2087 pChan
->b
.doingSpecialTone
=0;
2088 pChan
->spsSigGen1
->enabled
=0;
2089 } else if(pChan
->b
.doingSpecialTone
)
2091 pChan
->spsSigGen1
->sink
=output
;
2092 pChan
->spsSigGen1
->sigProc(pChan
->spsSigGen1
);
2093 for(i
=0;i
<(pChan
->nSamplesTx
*2*6);i
+=2)output
[i
+1]=output
[i
];
2097 // handle transmitter ptt input
2099 if( pChan
->txPttIn
&& pChan
->txState
==0)
2103 pChan
->spsSigGen0
->freq
=pChan
->txCtcssFreq
*10;
2104 pChan
->spsSigGen0
->option
=1;
2105 pChan
->spsSigGen0
->enabled
=1;
2106 if(pChan
->spsTxOutA
)pChan
->spsTxOutA
->enabled
=1;
2107 if(pChan
->spsTxOutB
)pChan
->spsTxOutB
->enabled
=1;
2108 if(pChan
->spsTxLsdLpf
)pChan
->spsTxLsdLpf
->enabled
=1;
2109 TRACEX((" TxOn\n"));
2111 else if(!pChan
->txPttIn
&& pChan
->txState
==2)
2113 if( pChan
->txTocType
==TOC_NONE
|| !pChan
->txCtcssFreq
)
2116 TRACEX((" Tx Off Immediate.\n"));
2118 else if(pChan
->txCtcssFreq
&& pChan
->txTocType
==TOC_NOTONE
)
2121 pChan
->txHangTime
=TOC_NOTONE_TIME
/MS_PER_FRAME
;
2122 pChan
->spsSigGen0
->option
=3;
2123 TRACEX((" Tx Turn Off No Tone Start.\n"));
2128 pChan
->txHangTime
=0;
2129 pChan
->spsSigGen0
->option
=2;
2130 TRACEX((" Tx Turn Off Phase Shift Start.\n"));
2133 else if(pChan
->txState
==3)
2135 if(pChan
->txHangTime
)
2137 if(--pChan
->txHangTime
==0)hit
=1;
2140 else if(pChan
->txHangTime
<=0 && pChan
->spsSigGen0
->state
==0)
2143 TRACEX((" Tx Off TOC.\n"));
2147 TRACEX((" Tx Key During HangTime\n"));
2148 if((pChan
->txTocType
==TOC_PHASE
)||(pChan
->txTocType
==TOC_NONE
))
2156 if( pChan
->txCpuSaver
&& !hit
&& !pChan
->txPttIn
&& !pChan
->txPttOut
&& pChan
->txState
==0 ) return (1);
2162 if(pChan
->spsTxLsdLpf
)pChan
->spsTxLsdLpf
->option
=3;
2163 if(pChan
->spsTxOutA
)pChan
->spsTxOutA
->option
=3;
2164 if(pChan
->spsTxOutB
)pChan
->spsTxOutB
->option
=3;
2165 TRACEX((" Tx Off hit.\n"));
2168 if(pChan
->spsSigGen0
)
2170 pChan
->spsSigGen0
->sigProc(pChan
->spsSigGen0
);
2171 pmr_sps
=pChan
->spsSigGen0
->nextSps
;
2173 while(pmr_sps
!=NULL
&& pmr_sps
!=0)
2175 TRACEX((" PmrTx() subaudible sps %i\n",i
++));
2176 //printf(" CTCSS ENCODE %i %i\n",pChan->spsSigGen0->freq,pChan->spsSigGen0->outputGain);
2177 pmr_sps
->sigProc(pmr_sps
);
2178 pmr_sps
= (t_pmr_sps
*)(pmr_sps
->nextSps
);
2182 if(pChan
->spsSigGen1
&& pChan
->spsSigGen1
->enabled
)
2184 pChan
->spsSigGen1
->sigProc(pChan
->spsSigGen1
);
2188 pmr_sps
=pChan
->spsTx
;
2189 if(!pChan
->spsSigGen1
->enabled
)pmr_sps
->source
=input
;
2190 else input
=pmr_sps
->source
;
2194 if(pChan
->spsTxOutA
)pChan
->spsTxOutA
->sink
=output
;
2195 if(pChan
->spsTxOutB
)pChan
->spsTxOutB
->sink
=output
;
2199 while(pmr_sps
!=NULL
&& pmr_sps
!=0)
2201 TRACEX((" PmrTx() sps %i\n",i
++));
2202 pmr_sps
->sigProc(pmr_sps
);
2203 pmr_sps
= (t_pmr_sps
*)(pmr_sps
->nextSps
);
2207 if(pChan
->txMixA
==TX_OUT_OFF
|| !pChan
->txPttOut
){
2208 for(i
=0;i
<pChan
->nSamplesTx
*2*6;i
+=2)output
[i
]=0;
2211 if(pChan
->txMixB
==TX_OUT_OFF
|| !pChan
->txPttOut
){
2212 for(i
=0;i
<pChan
->nSamplesTx
*2*6;i
+=2)output
[i
+1]=0;
2215 #if XPMR_DEBUG0 == 1
2216 if(pChan
->b
.txCapture
)
2219 for(i
=0;i
<pChan
->nSamplesTx
;i
++)
2221 pChan
->ptxDebug
[ii
++]=input
[i
];
2222 pChan
->ptxDebug
[ii
++]=output
[i
*2*6];
2223 pChan
->ptxDebug
[ii
++]=output
[(i
*2*6)+1];
2224 pChan
->ptxDebug
[ii
++]=pChan
->txPttIn
*8192;
2226 pChan
->ptxDebug
[ii
++]=pChan
->txPttOut
*8192;
2227 if(pChan
->txHpfEnable
)pChan
->ptxDebug
[ii
++]=pChan
->pTxHpf
[i
];
2228 else pChan
->ptxDebug
[ii
++]=0;
2229 if(pChan
->txPreEmpEnable
)pChan
->ptxDebug
[ii
++]=pChan
->pTxPreEmp
[i
];
2230 else pChan
->ptxDebug
[ii
++]=0;
2231 if(pChan
->txLimiterEnable
)pChan
->ptxDebug
[ii
++]=pChan
->pTxLimiter
[i
];
2232 else pChan
->ptxDebug
[ii
++]=0;
2234 pChan
->ptxDebug
[ii
++]=pChan
->pTxLsd
[i
];
2235 pChan
->ptxDebug
[ii
++]=pChan
->pTxLsdLpf
[i
];
2236 pChan
->ptxDebug
[ii
++]=pChan
->pTxComposite
[i
];
2237 pChan
->ptxDebug
[ii
++]=pChan
->pSigGen1
[i
];
2240 pChan
->ptxDebug
[ii
++]=pChan
->ptxDebug0
[i
];
2241 pChan
->ptxDebug
[ii
++]=pChan
->ptxDebug1
[i
];
2242 pChan
->ptxDebug
[ii
++]=pChan
->ptxDebug2
[i
];
2243 pChan
->ptxDebug
[ii
++]=pChan
->ptxDebug3
[i
];
2245 pChan
->ptxDebug
[ii
++]=0;
2246 pChan
->ptxDebug
[ii
++]=0;
2247 pChan
->ptxDebug
[ii
++]=0;
2248 pChan
->ptxDebug
[ii
++]=0;