Merged revisions 86066 via svnmerge from
[asterisk/asterisk.git] / channels / xpmr / xpmr.c
1 /*
2  * xpmr.c - Xelatec Private Mobile Radio Processes
3  * 
4  * All Rights Reserved. Copyright (C)2007, Xelatec, LLC
5  * 
6  * 20070808 1235 Steven Henke, W9SH, sph@xelatec.com
7  *
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.
13  *
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.
17  */
18
19 /*! \file
20  *
21  * \brief Private Land Mobile Radio Channel Voice and Signaling Processor
22  *
23  * \author Steven Henke, W9SH <sph@xelatec.com> Xelatec, LLC
24  */
25 /*
26         FYI     = For Your Information
27         PMR     = Private Mobile Radio
28         RX      = Receive
29         TX      = Transmit
30         CTCSS   = Continuous Tone Coded Squelch System
31         TONE    = Same as above.
32         LSD     = Low Speed Data, subaudible signaling. May be tones or codes.
33         VOX     = Voice Operated Transmit
34         DSP     = Digital Signal Processing
35         LPF     = Low Pass Filter
36         FIR     = Finite Impulse Response (Filter)
37         IIR     = Infinite Impulse Response (Filter)
38 */
39 #include <stdio.h>
40 #include <ctype.h>
41 #include <math.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <sys/ioctl.h>
45 #include <fcntl.h>
46 #include <sys/time.h>
47 #include <stdlib.h>
48 #include <errno.h>
49
50 #include "xpmr.h"
51 #include "xpmr_coef.h"
52 #include "sinetabx.h"
53
54 static i16 pmrChanIndex=0;                              // count of created pmr instances
55
56 /*
57         Convert a Frequency in Hz to a zero based CTCSS Table index
58 */
59 i16 CtcssFreqIndex(float freq)
60 {
61         i16 i,hit=-1;
62
63         for(i=0;i<CTCSS_NUM_CODES;i++){
64                 if(freq==freq_ctcss[i])hit=i;
65         }
66         return hit;
67 }
68 /*
69         pmr_rx_frontend 
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.
73 */
74 i16 pmr_rx_frontend(t_pmr_sps *mySps) 
75 {
76         #define DCgainBpfNoise  65536
77  
78         i16 samples,iOutput, *input, *output, *noutput;
79         i16 *x, *coef, *coef2;
80     i32 i, naccum, outputGain, calcAdjust;
81         i64 y;
82         i16 nx, hyst, setpt, compOut;
83         i16 amax, amin, apeak, discounteru, discounterl, discfactor;
84         i16 decimator, decimate, doNoise;
85
86         TRACEX(("pmr_rx_frontend()\n"));
87
88         if(!mySps->enabled)return(1);
89
90         decimator = mySps->decimator;
91         decimate = mySps->decimate;
92
93         input     = mySps->source;
94         output    = mySps->sink;
95         noutput   = mySps->parentChan->pRxNoise;
96
97         nx        = mySps->nx;
98         coef      = mySps->coef;
99         coef2     = mySps->coef2;
100
101         calcAdjust = mySps->calcAdjust;
102         outputGain = mySps->outputGain;
103
104         amax=mySps->amax;
105         amin=mySps->amin;
106         apeak=mySps->apeak;
107         discounteru=mySps->discounteru;
108         discounterl=mySps->discounterl;
109         discfactor=mySps->discfactor;
110         setpt=mySps->setpt;
111         hyst=mySps->hyst;
112         compOut=mySps->compOut;
113
114         samples=mySps->nSamples*decimate;
115         x=mySps->x;             
116         iOutput=0;
117
118         if(mySps->parentChan->rxCdType!=CD_XPMR_VOX)doNoise=1;
119         else doNoise=0;
120                         
121         for(i=0;i<samples;i++)
122         {
123                 i16 n;
124
125                 //shift the old samples
126             for(n=nx-1; n>0; n--)
127                x[n] = x[n-1];
128
129             x[0] = input[i*2];
130         
131                 --decimator;
132
133                 if(decimator<=0)
134                 {
135                         decimator=decimate;
136                         
137                     y=0; 
138                     for(n=0; n<nx; n++)
139                         y += coef[n] * x[n];
140
141                     y=((y/calcAdjust)*outputGain)/M_Q8;
142
143                         if(y>32767)y=32767;
144                         else if(y<-32767)y=-32767;
145
146                     output[iOutput]=y;                                  // Rx Baseband decimated
147                         noutput[iOutput++] = apeak;                     // Rx Noise
148                 }
149
150                 if(doNoise)
151                 {
152                         // calculate noise output
153                         naccum=0;
154                     for(n=0; n<nx; n++)
155                         naccum += coef_fir_bpf_noise_1[n] * x[n];
156                     
157                     naccum /= DCgainBpfNoise;
158         
159                         if(naccum>amax)
160                         {
161                                 amax=naccum;
162                                 discounteru=discfactor;
163                         }
164                         else if(--discounteru<=0)
165                         {
166                                 discounteru=discfactor;
167                                 amax=(i32)((amax*32700)/32768);
168                         }
169
170                         if(naccum<amin)
171                         {
172                                 amin=naccum;
173                                 discounterl=discfactor;
174                         }
175                         else if(--discounterl<=0)
176                         {
177                                 discounterl=discfactor;
178                                 amin=(i32)((amin*32700)/32768);
179                         }
180                 
181                         apeak=(amax-amin)/2;
182                         
183                 }  // if doNoise
184         }
185
186         if(doNoise)
187         {
188                 ((t_pmr_chan *)(mySps->parentChan))->rxRssi=apeak;
189                 
190                 if(apeak>setpt || (compOut&&(apeak>(setpt-hyst)))) compOut=1;
191                 else compOut=0;
192                 mySps->compOut=compOut;
193                 mySps->amax=amax;
194                 mySps->amin=amin;                               
195                 mySps->apeak=apeak;
196                 mySps->discounteru=discounteru;
197                 mySps->discounterl=discounterl; 
198         }
199
200         return 0;
201 }
202 /*             
203         pmr general purpose fir
204         works on a block of samples
205 */
206 i16 pmr_gp_fir(t_pmr_sps *mySps) 
207 {
208         i32 nsamples,inputGain,outputGain,calcAdjust;
209         i16 *input, *output;
210         i16 *x, *coef;
211     i32 i, ii;
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;
216
217         TRACEX(("pmr_gp_fir() %i\n",mySps->enabled));
218
219         if(!mySps->enabled)return(1);
220
221         inputGain  = mySps->inputGain;
222         calcAdjust = mySps->calcAdjust;
223         outputGain = mySps->outputGain;
224
225         input      = mySps->source;
226         output     = mySps->sink;
227         x          = mySps->x;
228         nx         = mySps->nx;
229         coef       = mySps->coef;
230         
231         decimator   = mySps->decimator;
232         decimate        = mySps->decimate;
233         interpolate = mySps->interpolate;
234
235         setpt      = mySps->setpt;
236         compOut    = mySps->compOut;
237
238         inputGain  = mySps->inputGain;
239         outputGain = mySps->outputGain;
240         numChanOut = mySps->numChanOut;
241         selChanOut = mySps->selChanOut;
242         mixOut     = mySps->mixOut;
243         monoOut    = mySps->monoOut;
244
245         amax=mySps->amax;
246         amin=mySps->amin;                               
247
248         discfactor=mySps->discfactor;
249         hyst=mySps->hyst;                               
250         setpt=mySps->setpt;     
251         nsamples=mySps->nSamples;
252
253         if(mySps->option==3)
254         {
255                 mySps->option=0;
256                 mySps->enabled=0;
257                 for(i=0;i<nsamples;i++)
258                 {
259                         if(monoOut)
260                                 output[(i*2)]=output[(i*2)+1]=0;
261                         else
262                                 output[(i*numChanOut)+selChanOut]=0;
263                 }
264                 return 0;
265         }
266
267         ii=0;
268         for(i=0;i<nsamples;i++)
269         {
270                 int ix;
271
272                 int64_t y=0;
273                 
274                 if(decimate<0)
275                 {
276                         decimator=decimate;     
277                 }
278
279                 for(ix=0;ix<interpolate;ix++)
280                 {
281                         i16 n; 
282                         y=0;
283         
284                     for(n=nx-1; n>0; n--)
285                        x[n] = x[n-1];
286                     x[0] = (input[i]*inputGain)/M_Q8;
287                 
288                         #if 0
289                         --decimator;
290                         if(decimator<=0)
291                         {
292                                 decimator=decimate;
293                             for(n=0; n<nx; n++)
294                                 y += coef[n] * x[n];
295                                 y /= (outputGain*3);  
296                                 output[ii++]=y;
297                         }
298                         #else
299                     for(n=0; n<nx; n++)
300                         y += coef[n] * x[n];
301
302                         y=((y/calcAdjust)*outputGain)/M_Q8;
303                         
304                         if(mixOut){
305                                 if(monoOut){
306                                         output[(ii*2)]=output[(ii*2)+1]+=y;
307                                 }
308                                 else{
309                                         output[(ii*numChanOut)+selChanOut]+=y;  
310                                 }
311                         }
312                         else{
313                                 if(monoOut){
314                                         output[(ii*2)]=output[(ii*2)+1]=y;
315                                 }
316                                 else{
317                                         output[(ii*numChanOut)+selChanOut]=y;
318                                 }
319                         }
320                         ii++;
321                     #endif
322                 }
323
324                 // amplitude detector
325                 if(setpt)
326                 {
327                         i16 accum=y;
328
329                         if(accum>amax)
330                         {
331                                 amax=accum;
332                                 discounteru=discfactor;
333                         }
334                         else if(--discounteru<=0)
335                         {
336                                 discounteru=discfactor;
337                                 amax=(i32)((amax*32700)/32768);
338                         }
339         
340                         if(accum<amin)
341                         {
342                                 amin=accum;
343                                 discounterl=discfactor;
344                         }
345                         else if(--discounterl<=0)
346                         {
347                                 discounterl=discfactor;
348                                 amin=(i32)((amin*32700)/32768);
349                         }
350         
351                         apeak = (i32)(amax-amin)/2;
352                          
353                         if(apeak>setpt)compOut=1;
354                         else if(compOut&&(apeak<(setpt-hyst)))compOut=0;
355                 }
356         }
357
358         mySps->decimator = decimator;
359
360         mySps->amax=amax;
361         mySps->amin=amin;                               
362         mySps->apeak=apeak;  
363         mySps->discounteru=discounteru;
364         mySps->discounterl=discounterl; 
365         
366         mySps->compOut=compOut;
367         
368         return 0;
369 }
370 /*
371         general purpose integrator lpf
372 */
373 i16 gp_inte_00(t_pmr_sps *mySps)
374 {
375         i16 npoints;
376         i16 *input, *output;
377
378         i32 inputGain, outputGain,calcAdjust;
379         i32     i;
380         i32 accum;
381
382         i32 state00;
383         i16 coeff00, coeff01;
384
385         TRACEX(("gp_inte_00() %i\n",mySps->enabled));
386         if(!mySps->enabled)return(1);
387
388         input   = mySps->source;
389         output  = mySps->sink;
390
391         npoints=mySps->nSamples;
392
393         inputGain=mySps->inputGain;
394         outputGain=mySps->outputGain;
395         calcAdjust=mySps->calcAdjust;
396
397         coeff00=((i16*)mySps->coef)[0];
398         coeff01=((i16*)mySps->coef)[1];
399         state00=((i32*)mySps->x)[0];
400
401         // note fixed gain of 2 to compensate for attenuation
402         // in passband
403
404         for(i=0;i<npoints;i++)
405         {
406                 accum=input[i];
407                 state00 = accum + (state00*coeff01)/M_Q15;
408                 accum = (state00*coeff00)/(M_Q15/4);
409                 output[i]=(accum*outputGain)/M_Q8;
410         }
411
412         ((i32*)(mySps->x))[0]=state00;
413
414         return 0;
415 }
416 /*
417         general purpose differentiator hpf
418 */
419 i16 gp_diff(t_pmr_sps *mySps)
420 {
421         i16 *input, *output;
422         i16 npoints;
423         i32 inputGain, outputGain, calcAdjust;
424         i32     i;
425         i32 temp0,temp1;
426         i16 x0;
427         i32 y0;
428         i16 a0,a1;
429         i16 b0;
430         i16 *coef;
431         i16 *x;
432
433         input   = mySps->source;
434         output  = mySps->sink;
435
436         npoints=mySps->nSamples;
437
438         inputGain=mySps->inputGain;
439         outputGain=mySps->outputGain;
440         calcAdjust=mySps->calcAdjust;
441
442         coef=(i16*)(mySps->coef);
443         x=(i16*)(mySps->x);
444         a0=coef[0];
445         a1=coef[1];
446         b0=coef[2];
447
448         x0=x[0];
449
450         TRACEX(("gp_diff()\n"));
451
452         for (i=0;i<npoints;i++)
453     {
454                 temp0 = x0 * a1;
455                    x0 = input[i];
456                 temp1 = input[i] * a0;
457                    y0 = (temp0 + temp1)/calcAdjust;
458                 output[i]=(y0*outputGain)/M_Q8;
459     }
460
461         x[0]=x0;
462
463         return 0;
464 }
465 /*      ----------------------------------------------------------------------
466         CenterSlicer
467 */
468 i16 CenterSlicer(t_pmr_sps *mySps)
469 {
470         i16 npoints,lhit,uhit;
471         i16 *input, *output, *buff;
472
473         i32 inputGain, outputGain, inputGainB;
474         i32     i;
475         i32 accum;
476
477         i32  amax;                      // buffer amplitude maximum
478         i32  amin;                      // buffer amplitude minimum
479         i32  apeak;                     // buffer amplitude peak
480         i32  center;
481         i32  setpt;                     // amplitude set point for peak tracking
482
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
486
487         TRACEX(("CenterSlicer() %i\n",mySps->enabled));
488
489         input   = mySps->source;
490         output  = mySps->sink;
491         buff    = mySps->buff;
492
493         npoints=mySps->nSamples;
494
495         inputGain=mySps->inputGain;
496         outputGain=mySps->outputGain;
497         inputGainB=mySps->inputGainB;
498
499         amax=mySps->amax;
500         amin=mySps->amin;
501         setpt=mySps->setpt;
502         apeak=mySps->apeak;
503         discounteru=mySps->discounteru;
504         discounterl=mySps->discounterl;
505
506         discfactor=mySps->discfactor;
507         npoints=mySps->nSamples;
508
509         for(i=0;i<npoints;i++)
510         {
511                 accum=input[i];
512
513                 lhit=uhit=0;
514
515                 if(accum>amax)
516                 {
517                         amax=accum;
518                         uhit=1;
519                         if(amin<(amax-setpt))
520                         {
521                                 amin=(amax-setpt);
522                                 lhit=1;
523                         }
524                 }
525                 else if(accum<amin)
526                 {
527                         amin=accum;
528                         lhit=1;
529                         if(amax>(amin+setpt))
530                         {
531                                 amax=(amin+setpt);
532                                 uhit=1;
533                         }
534                 }
535         
536                 if(--discounteru<=0 && amax>0)
537                 {
538                         amax--;
539                         uhit=1;
540                 }
541         
542                 if(--discounterl<=0 && amin<0)
543                 {
544                         amin++;
545                         lhit=1;
546                 }
547         
548                 if(uhit)discounteru=discfactor; 
549                 if(lhit)discounterl=discfactor; 
550                 
551                 apeak = (amax-amin)/2;
552                 center = (amax+amin)/2;
553                 accum = accum - center;
554                 output[i]=accum;
555         
556                 // do limiter function
557                 if(accum>inputGainB)accum=inputGainB;
558                 else if(accum<-inputGainB)accum=-inputGainB;
559                 buff[i]=accum;
560
561                 #if XPMR_DEBUG0 == 1
562                 #if 0
563                 mySps->debugBuff0[i]=center;
564                 #endif
565             #if 0
566                 if(mySps->parentChan->frameCountRx&0x01) mySps->parentChan->prxDebug1[i]=amax;
567                 else mySps->parentChan->prxDebug1[i]=amin;
568                 #endif
569                 #endif
570         }
571
572         mySps->amax=amax;
573         mySps->amin=amin;
574         mySps->apeak=apeak;
575         mySps->discounteru=discounteru;
576         mySps->discounterl=discounterl;
577
578         return 0;
579 }
580 /*      ----------------------------------------------------------------------
581         MeasureBlock
582         determine peak amplitude
583 */
584 i16 MeasureBlock(t_pmr_sps *mySps)
585 {
586         i16 npoints;
587         i16 *input, *output;
588
589         i32 inputGain, outputGain;
590         i32     i;
591         i32 accum;
592
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
597
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
601
602         TRACEX(("MeasureBlock() %i\n",mySps->enabled));
603
604         if(!mySps->enabled)return 1;
605
606         if(mySps->option==3)
607         {
608                 mySps->amax = mySps->amin = mySps->apeak = \
609                 mySps->discounteru = mySps->discounterl = \
610                 mySps->enabled = 0;
611                 return 1;
612         }
613
614         input   = mySps->source;
615         output  = mySps->sink;
616
617         npoints=mySps->nSamples;
618
619         inputGain=mySps->inputGain;
620         outputGain=mySps->outputGain;
621
622         amax=mySps->amax;
623         amin=mySps->amin;
624         setpt=mySps->setpt;
625         discounteru=mySps->discounteru;
626         discounterl=mySps->discounterl;
627
628         discfactor=mySps->discfactor;
629         npoints=mySps->nSamples;
630
631         for(i=0;i<npoints;i++)
632         {
633                 accum=input[i];
634
635                 if(accum>amax)
636                 {
637                         amax=accum;
638                         discounteru=discfactor;
639                 }
640                 else if(--discounteru<=0)
641                 {
642                         discounteru=discfactor;
643                         amax=(i32)((amax*32700)/32768);
644                 }
645
646                 if(accum<amin)
647                 {
648                         amin=accum;
649                         discounterl=discfactor;
650                 }
651                 else if(--discounterl<=0)
652                 {
653                         discounterl=discfactor;
654                         amin=(i32)((amin*32700)/32768);
655                 }
656
657                 apeak = (i32)(amax-amin)/2;
658                 if(output)output[i]=apeak;
659         }
660     
661         mySps->amax=amax;
662         mySps->amin=amin;
663         mySps->apeak=apeak;
664         mySps->discounteru=discounteru;
665         mySps->discounterl=discounterl;
666         if(apeak>=setpt) mySps->compOut=1;
667         else mySps->compOut=0;
668         
669         //TRACEX((" -MeasureBlock()=%i\n",mySps->apeak));
670         return 0;
671 }
672 /*
673         SoftLimiter
674 */
675 i16 SoftLimiter(t_pmr_sps *mySps)
676 {
677         i16 npoints;
678         //i16 samples, lhit,uhit;
679         i16 *input, *output;
680
681         i32 inputGain, outputGain;
682         i32     i;
683         i32 accum;
684         i32  tmp;
685
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
691
692         input   = mySps->source;
693         output  = mySps->sink;
694
695         inputGain=mySps->inputGain;
696         outputGain=mySps->outputGain;
697
698         npoints=mySps->nSamples;
699
700         setpt=mySps->setpt;
701         amax=(setpt*124)/128;
702         amin=-amax;
703
704         TRACEX(("SoftLimiter() %i %i %i) \n",amin, amax,setpt));
705
706         for(i=0;i<npoints;i++)
707         {
708                 accum=input[i];
709                 //accum=input[i]*mySps->inputGain/256;
710
711                 if(accum>setpt)
712                 {
713                     tmp=((accum-setpt)*4)/128;
714                     accum=setpt+tmp;
715                         if(accum>amax)accum=amax;
716                         compOut=1;
717                         accum=setpt;
718                 }
719                 else if(accum<-setpt)
720                 {
721                     tmp=((accum+setpt)*4)/128;
722                     accum=(-setpt)-tmp;
723                         if(accum<amin)accum=amin;
724                         compOut=1;
725                         accum=-setpt;
726                 }
727
728                 output[i]=(accum*outputGain)/M_Q8;
729         }
730
731         return 0;
732 }
733 /*
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!
739
740         sign table and output gain are in Q15 format (32767=.999)
741 */
742 i16     SigGen(t_pmr_sps *mySps)
743 {
744         #define PH_FRACT_FACT   128
745
746         i32 ph;
747         i16 i,outputgain,waveform,numChanOut,selChanOut;
748         i32 accum;                               
749
750         TRACEX(("SigGen(%i) \n",mySps->option));
751
752         if(!mySps->freq ||!mySps->enabled)return 0;
753
754         outputgain=mySps->outputGain;
755         waveform=0;
756         numChanOut=mySps->numChanOut; 
757         selChanOut=mySps->selChanOut;
758
759     if(mySps->option==1)
760         {
761                 mySps->option=0;
762                 mySps->state=1;
763                 mySps->discfactor=
764                         (SAMPLES_PER_SINE*mySps->freq*PH_FRACT_FACT)/mySps->sampleRate/10;
765         
766                 TRACEX((" SigGen() discfactor = %i\n",mySps->discfactor));
767                 if(mySps->discounterl)mySps->state=2;
768         }
769         else if(mySps->option==2)
770         {
771                 i16 shiftfactor=CTCSS_TURN_OFF_SHIFT;
772                 // phase shift request
773                 mySps->option=0;
774                 mySps->state=2;
775                 mySps->discounterl=CTCSS_TURN_OFF_TIME-(2*MS_PER_FRAME);                // 
776
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);
780                 //shiftfactor+=10;
781         }
782         else if(mySps->option==3)
783         {
784                 // stop it and clear the output buffer
785                 mySps->option=0;
786                 mySps->state=0;
787                 mySps->enabled=0;
788                 for(i=0;i<mySps->nSamples;i++)
789                         mySps->sink[(i*numChanOut)+selChanOut]=0;
790                 return(0);
791         }
792         else if(mySps->state==2)
793         {
794                 // doing turn off
795                 mySps->discounterl-=MS_PER_FRAME;
796                 if(mySps->discounterl<=0)
797                 {
798                         mySps->option=3;
799                         mySps->state=2;
800                 }
801         }
802         else if(mySps->state==0)
803         {
804                 return(0);
805         }
806
807         ph=mySps->discounteru;
808
809         for(i=0;i<mySps->nSamples;i++)
810         {
811                 if(!waveform)
812                 {
813                         // sine
814                         //tmp=(sinetablex[ph/PH_FRACT_FACT]*amplitude)/M_Q16;
815                         accum=sinetablex[ph/PH_FRACT_FACT];
816                         accum=(accum*outputgain)/M_Q8;
817             }
818                 else
819                 {
820                         // square
821                         if(ph>SAMPLES_PER_SINE/2)
822                                 accum=outputgain/M_Q8;
823                         else
824                                 accum=-outputgain/M_Q8;
825                 }
826
827                 if(mySps->source)accum+=mySps->source[i];
828
829                 mySps->sink[(i*numChanOut)+selChanOut]=accum;
830
831                 ph=(ph+mySps->discfactor)%(SAMPLES_PER_SINE*PH_FRACT_FACT);
832         }
833
834         mySps->discounteru=ph;
835
836         return 0;
837 }
838 /*
839         adder/mixer
840         takes existing buffer and adds source buffer to destination buffer
841         sink buffer = (sink buffer * gain) + source buffer 
842 */
843 i16 pmrMixer(t_pmr_sps *mySps)
844 {
845         i32 accum;
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;
851
852         TRACEX(("pmrMixer()\n"));
853
854         input     = mySps->source;
855         inputB    = mySps->sourceB;
856         output    = mySps->sink;
857
858         inputGain=mySps->inputGain;
859         inputGainB=mySps->inputGainB;
860         outputGain=mySps->outputGain;
861         
862         amax=mySps->amax;
863         amin=mySps->amin;
864         setpt=mySps->setpt;
865         discounteru=mySps->discounteru;
866         discounterl=mySps->discounteru;
867
868         discfactor=mySps->discfactor;
869         npoints=mySps->nSamples;
870         measPeak=mySps->measPeak;
871
872         for(i=0;i<npoints;i++)
873         {
874                 accum = ((input[i]*inputGain)/M_Q8) + 
875                                 ((inputB[i]*inputGainB)/M_Q8);
876
877                 accum=(accum*outputGain)/M_Q8;
878                 output[i]=accum;
879
880                 if(measPeak){
881                         lhit=uhit=0;
882         
883                         if(accum>amax){
884                                 amax=accum;
885                                 uhit=1;
886                                 if(amin<(amax-setpt)){
887                                         amin=(amax-setpt);
888                                         lhit=1;
889                                 }
890                         }
891                         else if(accum<amin){
892                                 amin=accum;
893                                 lhit=1;
894                                 if(amax>(amin+setpt)){
895                                         amax=(amin+setpt);
896                                         uhit=1;
897                                 }
898                         }
899                 
900                         if(--discounteru<=0 && amax>0){
901                                 amax--;
902                                 uhit=1;
903                         }
904                 
905                         if(--discounterl<=0 && amin<0){
906                                 amin++;
907                                 lhit=1;
908                         }
909                 
910                         if(uhit)discounteru=discfactor; 
911                         if(lhit)discounterl=discfactor;
912                 }       
913         }
914
915         if(measPeak){
916                 apeak = (amax-amin)/2;
917                 mySps->apeak=apeak;
918                 mySps->amax=amax;
919                 mySps->amin=amin;
920                 mySps->discounteru=discounteru;
921                 mySps->discounterl=discounterl;
922         }
923         
924         return 0;
925 }
926 /*
927         DelayLine 
928 */
929 i16 DelayLine(t_pmr_sps *mySps)
930 {
931         i16 *input, *output, *buff;
932         i16      i, npoints,buffsize,inindex,outindex;
933
934         TRACEX((" DelayLine() %i\n",mySps->enabled));
935         
936         input           = mySps->source;
937         output          = mySps->sink;
938         buff            = (i16*)(mySps->buff);
939         buffsize        = mySps->buffSize;
940         npoints         = mySps->nSamples;
941
942         outindex        = mySps->buffOutIndex;
943         inindex         = outindex + mySps->buffLead;
944
945         for(i=0;i<npoints;i++)
946         {
947                 inindex %= buffsize;
948                 outindex %= buffsize;
949                 
950                 buff[inindex]=input[i];
951                 output[i]=buff[outindex];
952                 inindex++;
953                 outindex++;
954         }
955         mySps->buffOutIndex=outindex;
956
957         return 0;
958 }
959 /*
960         Continuous Tone Coded Squelch (CTCSS) Detector
961 */
962 i16 ctcss_detect(t_pmr_chan *pmrChan)
963 {
964         i16 i,points2do, points=0, *pInput, hit, thit,relax; 
965         i16 tnum, tmp, indexWas=0, indexNow, gain, peakwas=0, diffpeak;
966         i16 difftrig;
967         i16 lasttv0=0, lasttv1=0, lasttv2=0, tv0, tv1, tv2, indexDebug;
968
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));
974
975         if(!pmrChan->rxCtcss->enabled)return(1);
976
977         relax  = pmrChan->rxCtcss->relax; 
978         pInput = pmrChan->rxCtcss->input;
979         gain   = pmrChan->rxCtcss->gain;
980         
981         if(relax) difftrig=(-0.1*M_Q15);
982         else difftrig=(-0.05*M_Q15);
983
984         thit=hit=-1;
985
986         //TRACEX((" ctcss_detect() %i  %i  %i  %i\n", CTCSS_NUM_CODES,0,0,0));
987
988         for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++)
989         {
990                 i32 accum, peak;
991                 t_tdet  *ptdet;
992                 i16 fudgeFactor;
993                 i16 binFactor;
994
995                 //TRACEX((" ctcss_detect() tnum=%i %i\n",tnum,pmrChan->rxCtcssMap[tnum]));
996
997                 if( (pmrChan->rxCtcssMap[tnum] < 0) || 
998                     (pmrChan->rxCtcss->decode>=0 && (tnum!= pmrChan->rxCtcss->decode)) ||
999                         (!pmrChan->rxCtcss->multiFreq && (tnum!= pmrChan->rxCtcssIndex))
1000                   )
1001                         continue;
1002
1003                 //TRACEX((" ctcss_detect() tnum=%i\n",tnum));
1004
1005                 ptdet=&(pmrChan->rxCtcss->tdet[tnum]);
1006                 indexDebug=0;
1007                 points=points2do=pmrChan->nSamplesRx;
1008                 fudgeFactor=ptdet->fudgeFactor;
1009                 binFactor=ptdet->binFactor;
1010
1011                 while(ptdet->counter < (points2do*CTCSS_SCOUNT_MUL))
1012                 {
1013                         //TRACEX((" ctcss_detect() - inner loop\n"));
1014                         tmp=(ptdet->counter/CTCSS_SCOUNT_MUL)+1;
1015                     ptdet->counter-=(tmp*CTCSS_SCOUNT_MUL);
1016                         points2do-=tmp;
1017                         indexNow=points-points2do;
1018                         
1019                         ptdet->counter += ptdet->counterFactor;
1020
1021                         accum = pInput[indexNow-1];             // dude's major bug fix!
1022
1023                         peakwas=ptdet->peak;
1024
1025                         ptdet->z[ptdet->zIndex]+=
1026                                 (((accum - ptdet->z[ptdet->zIndex])*binFactor)/M_Q15);
1027
1028                         peak = abs(ptdet->z[0]-ptdet->z[2]) + abs(ptdet->z[1]-ptdet->z[3]);
1029
1030                         if (ptdet->peak < peak)
1031                                 ptdet->peak += ( ((peak-ptdet->peak)*binFactor)/M_Q15);
1032                         else
1033                                 ptdet->peak=peak;
1034
1035                         {
1036                                 static const i16 a0=13723;
1037                                 static const i16 a1=-13723;
1038                                 i32 temp0,temp1;
1039                                 i16 x0;
1040         
1041                                 //differentiate
1042                                 x0=ptdet->zd;
1043                                 temp0 = x0 * a1;
1044                                 ptdet->zd = ptdet->peak;
1045                                 temp1 = ptdet->peak * a0;
1046                             diffpeak = (temp0 + temp1)/1024;
1047                         }
1048
1049                         if(diffpeak<(-0.03*M_Q15))ptdet->dvd-=4;
1050                         else if(ptdet->dvd<0)ptdet->dvd++;
1051
1052                         if((ptdet->dvd < -12) && diffpeak > (-0.02*M_Q15))ptdet->dvu+=2;
1053                         else if(ptdet->dvu)ptdet->dvu--;
1054
1055                         tmp=ptdet->setpt;
1056                         if(pmrChan->rxCtcss->decode==tnum)
1057                         {
1058                                 if(relax)tmp=(tmp*55)/100;
1059                                 else tmp=(tmp*80)/100;
1060                         }
1061
1062                         if(ptdet->peak > tmp)
1063                         {
1064                             if(ptdet->decode<(fudgeFactor*32))ptdet->decode++;
1065                         }
1066                         else if(pmrChan->rxCtcss->decode==tnum)
1067                         {
1068                                 if(ptdet->peak > ptdet->hyst)ptdet->decode--;
1069                                 else if(relax) ptdet->decode--; 
1070                                 else ptdet->decode-=4; 
1071                         }
1072                         else
1073                         {
1074                                 ptdet->decode=0;
1075                         }
1076
1077                         if((pmrChan->rxCtcss->decode==tnum) && !relax && (ptdet->dvu > (0.00075*M_Q15)))
1078                         {
1079                                 ptdet->decode=0;
1080                                 ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=ptdet->dvu=0;
1081                                 //printf("ctcss_detect() turnoff code!\n");
1082                         }
1083
1084                         if(ptdet->decode<0 || !pmrChan->rxCarrierDetect)ptdet->decode=0;
1085
1086                         if(ptdet->decode>=fudgeFactor)thit=tnum;  
1087
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);
1091
1092                         // tv0=accum;
1093                         tv0=ptdet->peak;
1094                         tv1=diffpeak;
1095                         tv2=ptdet->dvu;
1096                         
1097                         //tv1=ptdet->zi*100;
1098                         while(indexDebug<indexNow)
1099                         {
1100                                 if(indexDebug==0)lasttv0=ptdet->pDebug0[points-1];
1101                                 if(ptdet->pDebug0)ptdet->pDebug0[indexDebug]=lasttv0;
1102
1103                                 if(indexDebug==0)lasttv1=ptdet->pDebug1[points-1];
1104                                 if(ptdet->pDebug1)ptdet->pDebug1[indexDebug]=lasttv1;
1105
1106                                 if(indexDebug==0)lasttv2=ptdet->pDebug2[points-1];
1107                                 if(ptdet->pDebug2)ptdet->pDebug2[indexDebug]=lasttv2;
1108
1109                                 indexDebug++;
1110                         }
1111                         lasttv0=tv0;
1112                         lasttv1=tv1;
1113                         lasttv2=tv2*100;
1114                         #endif
1115                         indexWas=indexNow;
1116                         ptdet->zIndex=(++ptdet->zIndex)%4;
1117                 }
1118                 ptdet->counter-=(points2do*CTCSS_SCOUNT_MUL);
1119
1120                 #if XPMR_DEBUG0 == 1
1121                 for(i=indexWas;i<points;i++)
1122                 {
1123                         if(ptdet->pDebug0)ptdet->pDebug0[i]=lasttv0;
1124                         if(ptdet->pDebug1)ptdet->pDebug1[i]=lasttv1;
1125                         if(ptdet->pDebug2)ptdet->pDebug2[i]=lasttv2;
1126                 }
1127                 #endif
1128         }
1129
1130         //TRACEX((" ctcss_detect() thit %i\n",thit));
1131
1132         if(pmrChan->rxCtcss->BlankingTimer>0)pmrChan->rxCtcss->BlankingTimer-=points;
1133         if(pmrChan->rxCtcss->BlankingTimer<0)pmrChan->rxCtcss->BlankingTimer=0;
1134
1135     if(thit>=0 && pmrChan->rxCtcss->decode<0 && !pmrChan->rxCtcss->BlankingTimer)
1136     {
1137                 pmrChan->rxCtcss->decode=thit;          
1138         }
1139         else if(thit<0 && pmrChan->rxCtcss->decode>=0)
1140         {
1141                 pmrChan->rxCtcss->BlankingTimer=SAMPLE_RATE_NETWORK/5;
1142                 pmrChan->rxCtcss->decode=-1;    
1143
1144                 for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++)
1145                 {
1146                     t_tdet      *ptdet=NULL;
1147                         ptdet=&(pmrChan->rxCtcss->tdet[tnum]);
1148                     ptdet->decode=0;
1149                         ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=0;
1150                 }
1151         }
1152         //TRACEX((" ctcss_detect() thit %i %i\n",thit,pmrChan->rxCtcss->decode));
1153         return(0);
1154 }
1155 /*
1156         TxTestTone
1157 */
1158 static i16      TxTestTone(t_pmr_chan *pChan, i16 function)
1159 {
1160         if(function==1)
1161         {
1162                 pChan->spsSigGen1->enabled=1;
1163                 pChan->spsSigGen1->option=1;
1164                 pChan->spsTx->source=pChan->spsSigGen1->sink;
1165         }
1166         else
1167         {
1168                 pChan->spsSigGen1->option=3;
1169         }
1170         return 0;
1171 }
1172 /*      
1173         assumes:
1174         sampling rate is 48KS/s
1175         samples are all 16 bits
1176     samples are filtered and decimated by 1/6th
1177 */
1178 t_pmr_chan      *createPmrChannel(t_pmr_chan *tChan, i16 numSamples)
1179 {
1180         i16 i, *inputTmp;
1181
1182         t_pmr_chan      *pChan;
1183         t_pmr_sps       *pSps;
1184         t_dec_ctcss     *pDecCtcss;
1185         t_tdet          *ptdet;
1186
1187         TRACEX(("createPmrChannel(%p,%i)\n",tChan,numSamples));
1188
1189         pChan = (t_pmr_chan *)calloc(sizeof(t_pmr_chan),1);
1190
1191         if(pChan==NULL)
1192         {
1193                 printf("createPmrChannel() failed\n");
1194                 return(NULL);
1195         }
1196         
1197         pChan->nSamplesRx=numSamples;
1198         pChan->nSamplesTx=numSamples;
1199
1200         pChan->index=pmrChanIndex++;
1201
1202         for(i=0;i<CTCSS_NUM_CODES;i++)
1203         {
1204                 pChan->rxCtcssMap[i]=-1;        
1205         }
1206
1207         pChan->rxCtcssIndex=-1;
1208
1209         if(tChan==NULL)
1210         {
1211                 pChan->rxNoiseSquelchEnable=0;
1212                 pChan->rxHpfEnable=0;
1213                 pChan->rxDeEmpEnable=0;
1214                 pChan->rxCenterSlicerEnable=0;
1215                 pChan->rxCtcssDecodeEnable=0;
1216                 pChan->rxDcsDecodeEnable=0;
1217
1218                 pChan->rxCarrierPoint = 17000;
1219                 pChan->rxCarrierHyst = 2500;
1220
1221                 pChan->rxCtcssFreq=103.5;
1222
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;
1230         }
1231         else
1232         {
1233                 pChan->rxDemod=tChan->rxDemod;
1234                 pChan->rxCdType=tChan->rxCdType;
1235                 pChan->rxSquelchPoint = tChan->rxSquelchPoint;
1236                 pChan->rxCarrierHyst = 3000;
1237                 pChan->rxCtcssFreq=tChan->rxCtcssFreq;
1238
1239                 for(i=0;i<CTCSS_NUM_CODES;i++)
1240                         pChan->rxCtcssMap[i]=tChan->rxCtcssMap[i];
1241                 
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;
1249         }
1250
1251         TRACEX(("misc settings \n"));
1252
1253         if(pChan->rxCdType==CD_XPMR_NOISE){
1254                 pChan->rxNoiseSquelchEnable=1;
1255         }
1256
1257         if(pChan->rxDemod==RX_AUDIO_FLAT){
1258                 pChan->rxHpfEnable=1;
1259                 pChan->rxDeEmpEnable=1;
1260         }
1261
1262         pChan->rxCarrierPoint=(pChan->rxSquelchPoint*32767)/100;
1263         pChan->rxCarrierHyst = 3000; //pChan->rxCarrierPoint/15;
1264         
1265         pChan->rxDcsDecodeEnable=0;
1266
1267         if(pChan->rxCtcssFreq!=0){
1268                 pChan->rxHpfEnable=1;
1269                 pChan->rxCenterSlicerEnable=1;
1270                 pChan->rxCtcssDecodeEnable=1;
1271                 pChan->rxCtcssIndex=CtcssFreqIndex(pChan->rxCtcssFreq);
1272         }
1273
1274         if(pChan->txMod){
1275                 pChan->txPreEmpEnable=1;
1276                 pChan->txLimiterEnable=1;
1277         }
1278         
1279         TRACEX(("calloc buffers \n"));
1280
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);
1290         
1291         
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);
1301
1302         pChan->pTxCode      = calloc(numSamples,2);
1303         pChan->pTxOut           = calloc(numSamples,2*2*6);             // output buffer
1304         
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;
1318         #endif
1319
1320         TRACEX(("create ctcss\n"));
1321
1322         pDecCtcss = (t_dec_ctcss *)calloc(sizeof(t_dec_ctcss),1);
1323          
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;
1333
1334         for(i=0;i<CTCSS_NUM_CODES;i++)
1335         {
1336                 ptdet=&(pChan->rxCtcss->tdet[i]);
1337                 ptdet->state=1;
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;   
1343         }
1344
1345         // General Purpose Function Generator
1346         pSps=pChan->spsSigGen1=createPmrSps();
1347         pSps->parentChan=pChan;
1348         pSps->sink=pChan->pSigGen1; 
1349         pSps->numChanOut=1;
1350         pSps->selChanOut=0;
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);
1356         pSps->option=0;
1357         pSps->interpolate=1;
1358         pSps->decimate=1;
1359         pSps->enabled=0;
1360
1361
1362         // CTCSS ENCODER
1363         pSps = pChan->spsSigGen0 = createPmrSps();
1364         pSps->parentChan=pChan;
1365         pSps->sink=pChan->pTxLsd;  
1366         pSps->sigProc=SigGen; 
1367         pSps->numChanOut=1;
1368         pSps->selChanOut=0;
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);
1373         pSps->option=0;
1374         pSps->interpolate=1;
1375         pSps->decimate=1;
1376         pSps->enabled=0;
1377
1378
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;
1384         pSps->enabled=0;
1385         pSps->numChanOut=1;
1386         pSps->selChanOut=0;
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);
1392
1393         if(pChan->txCtcssFreq>203.0)
1394         {
1395                 pSps->ncoef=taps_fir_lpf_250_9_66;
1396                 pSps->size_coef=2;
1397                 pSps->coef=(void*)coef_fir_lpf_250_9_66;
1398                 pSps->nx=taps_fir_lpf_250_9_66;
1399                 pSps->size_x=2;
1400                 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
1401                 pSps->calcAdjust=gain_fir_lpf_250_9_66;
1402         }
1403         else
1404         {
1405                 pSps->ncoef=taps_fir_lpf_215_9_88;
1406                 pSps->size_coef=2;
1407                 pSps->coef=(void*)coef_fir_lpf_215_9_88;
1408                 pSps->nx=taps_fir_lpf_215_9_88;
1409                 pSps->size_x=2;
1410                 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
1411                 pSps->calcAdjust=gain_fir_lpf_215_9_88;
1412         }
1413
1414         pSps->inputGain=(1*M_Q8);
1415         pSps->outputGain=(1*M_Q8);
1416         
1417         if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n"); 
1418
1419                 
1420         // RX Process
1421         TRACEX(("create rx\n"));
1422         pSps = NULL;
1423
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;
1430         pSps->enabled=1;
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;
1435         pSps->size_coef=2;
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;
1439         pSps->size_x=2;
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);
1443         pSps->discfactor=2;       
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;
1451         #endif
1452
1453  
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;
1461         pSps->enabled=1;
1462         pSps->numChanOut=1;
1463         pSps->selChanOut=0;
1464         pSps->nSamples=pChan->nSamplesRx;
1465         pSps->decimator=pSps->decimate=1;
1466         pSps->interpolate=1;
1467
1468         if(pChan->rxCtcssFreq>203.5)
1469         {
1470                 pSps->ncoef=taps_fir_lpf_250_9_66;
1471                 pSps->size_coef=2;
1472                 pSps->coef=(void*)coef_fir_lpf_250_9_66;
1473                 pSps->nx=taps_fir_lpf_250_9_66;
1474                 pSps->size_x=2;
1475                 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
1476                 pSps->calcAdjust=gain_fir_lpf_250_9_66;
1477         }
1478         else
1479         {
1480                 pSps->ncoef=taps_fir_lpf_215_9_88;
1481                 pSps->size_coef=2;
1482                 pSps->coef=(void*)coef_fir_lpf_215_9_88;
1483                 pSps->nx=taps_fir_lpf_215_9_88;
1484                 pSps->size_x=2;
1485                 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
1486                 pSps->calcAdjust=gain_fir_lpf_215_9_88;
1487         }
1488
1489         pSps->inputGain=(1*M_Q8);
1490         pSps->outputGain=(1*M_Q8);
1491         pChan->prxCtcssMeasure=pSps->sink;
1492         pChan->prxCtcssAdjust=&(pSps->outputGain);      
1493
1494
1495         // allocate space for next sps and set pointers
1496         // CenterSlicer
1497         if(pChan->rxCenterSlicerEnable)
1498         {
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;
1505                 pSps->enabled=1;
1506                 pSps->nSamples=pChan->nSamplesRx;
1507                 pSps->discfactor=800;
1508                 pSps->inputGain=(1*M_Q8);
1509                 pSps->outputGain=(1*M_Q8);
1510                 pSps->setpt=3000;
1511                 pSps->inputGainB=1000;                  // limiter set point
1512         }
1513
1514         // allocate space for next sps and set pointers
1515         // Rx HPF
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;
1522         pSps->enabled=1;
1523         pSps->numChanOut=1;
1524         pSps->selChanOut=0;
1525         pSps->nSamples=pChan->nSamplesRx;
1526         pSps->decimator=pSps->decimate=1;
1527         pSps->interpolate=1;
1528         pSps->ncoef=taps_fir_hpf_300_9_66;
1529         pSps->size_coef=2;
1530         pSps->coef=(void*)coef_fir_hpf_300_9_66;
1531         pSps->nx=taps_fir_hpf_300_9_66;
1532         pSps->size_x=2;
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;
1539
1540         // allocate space for next sps and set pointers
1541         // Rx DeEmp
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;
1550                 pSps->enabled=1;
1551                 pSps->nSamples=pChan->nSamplesRx;
1552         
1553                 pSps->ncoef=taps_int_lpf_300_1_2;
1554                 pSps->size_coef=2;
1555                 pSps->coef=(void*)coef_int_lpf_300_1_2;
1556         
1557                 pSps->nx=taps_int_lpf_300_1_2;
1558                 pSps->size_x=4;
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);      
1566         }
1567
1568         if(pChan->rxDelayLineEnable)
1569         {
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;
1575                 pSps->enabled=0;
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;
1583         }
1584
1585         if(pChan->rxCdType==CD_XPMR_VOX)
1586         {
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;
1596                 pSps->discfactor=3;
1597                 pSps->setpt=(0.01*M_Q15);
1598                 pSps->hyst=(pSps->setpt/10);
1599                 pSps->enabled=1;
1600         }
1601
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;
1608         pSps->enabled=0;
1609         pSps->nSamples=pChan->nSamplesRx;
1610         pSps->discfactor=10;        
1611
1612         pSps->nextSps=NULL;             // last sps in chain RX
1613
1614
1615         // CREATE TRANSMIT CHAIN
1616         TRACEX((" create tx\n"));
1617         inputTmp=NULL;
1618         pSps = NULL;
1619
1620         // allocate space for first sps and set pointers
1621
1622         // Tx HPF SubAudible
1623         if(pChan->txHpfEnable)
1624         {
1625                 pSps=createPmrSps();
1626                 pChan->spsTx=pSps;
1627                 pSps->source=pChan->pTxBase;
1628                 pSps->sink=pChan->pTxHpf;  
1629                 pSps->sigProc=pmr_gp_fir;
1630                 pSps->enabled=1;
1631                 pSps->numChanOut=1;
1632                 pSps->selChanOut=0;
1633                 pSps->nSamples=pChan->nSamplesTx;
1634                 pSps->decimator=pSps->decimate=1;
1635                 pSps->interpolate=1;
1636                 pSps->ncoef=taps_fir_hpf_300_9_66;
1637                 pSps->size_coef=2;
1638                 pSps->coef=(void*)coef_fir_hpf_300_9_66;
1639                 pSps->nx=taps_fir_hpf_300_9_66;
1640                 pSps->size_x=2;
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;
1647         }
1648
1649         // Tx PreEmphasis
1650         if(pChan->txPreEmpEnable)
1651         {
1652                 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps();
1653                 else pSps=pSps->nextSps=createPmrSps();
1654                 
1655                 pSps->parentChan=pChan;
1656                 pSps->source=inputTmp;
1657                 pSps->sink=pChan->pTxPreEmp;  
1658                 
1659                 pSps->sigProc=gp_diff;
1660                 pSps->enabled=1;
1661                 pSps->nSamples=pChan->nSamplesTx;
1662         
1663                 pSps->ncoef=taps_int_hpf_4000_1_2;
1664                 pSps->size_coef=2;
1665                 pSps->coef=(void*)coef_int_hpf_4000_1_2;
1666         
1667                 pSps->nx=taps_int_hpf_4000_1_2;
1668                 pSps->size_x=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;
1676         }
1677
1678         // Tx Limiter
1679         if(pChan->txLimiterEnable)
1680         {
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;
1686                 pSps->enabled=1;
1687                 pSps->nSamples=pChan->nSamplesTx;
1688                 pSps->inputGain=(1*M_Q8);
1689                 pSps->outputGain=(1*M_Q8);
1690                 pSps->setpt=12000;
1691                 inputTmp=pSps->sink;
1692         }
1693
1694         // Composite Mix of Voice and LSD
1695         if((pChan->txMixA==TX_OUT_COMPOSITE)||(pChan->txMixB==TX_OUT_COMPOSITE))
1696         {
1697                 if(pSps==NULL)
1698                         pSps=pChan->spsTx=createPmrSps();
1699                 else
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;
1705                 pSps->enabled=1;
1706                 pSps->nSamples=pChan->nSamplesTx;
1707                 pSps->inputGain=2*M_Q8; 
1708                 pSps->inputGainB=1*M_Q8/8; 
1709                 pSps->outputGain=1*M_Q8;
1710                 pSps->setpt=0;
1711                 inputTmp=pSps->sink;
1712                 pChan->ptxCtcssAdjust=&pSps->inputGainB;
1713         }
1714
1715         // Chan A Upsampler and Filter 
1716         if(pSps==NULL) pSps=pChan->spsTx=createPmrSps();
1717         else pSps=pSps->nextSps=createPmrSps();
1718
1719         pChan->spsTxOutA=pSps;
1720         if(!pChan->spsTx)pChan->spsTx=pSps;
1721         pSps->parentChan=pChan;
1722
1723         if(pChan->txMixA==TX_OUT_COMPOSITE)
1724         {
1725                 pSps->source=pChan->pTxComposite;       
1726         }
1727         else if(pChan->txMixA==TX_OUT_LSD)
1728         {
1729                 pSps->source=pChan->pTxLsdLpf;  
1730         }
1731         else if(pChan->txMixA==TX_OUT_VOICE)
1732         {
1733                 pSps->source=pChan->pTxHpf;
1734         }
1735         else if (pChan->txMixA==TX_OUT_AUX)
1736         {
1737                 pSps->source=inputTmp;                           
1738         }
1739         else
1740         {
1741                 pSps->source=NULL;                               
1742         }
1743         
1744         pSps->sink=pChan->pTxOut;  
1745         pSps->sigProc=pmr_gp_fir;
1746         pSps->enabled=1;
1747         pSps->numChanOut=2;
1748         pSps->selChanOut=0;
1749         pSps->nSamples=pChan->nSamplesTx;
1750         pSps->interpolate=6;
1751         pSps->ncoef=taps_fir_lpf_3K_1;
1752         pSps->size_coef=2;
1753         pSps->coef=(void*)coef_fir_lpf_3K_1;
1754         pSps->nx=taps_fir_lpf_3K_1;
1755         pSps->size_x=2;
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;
1763
1764
1765         // Chan B Upsampler and Filter 
1766         if((pChan->txMixA!=pChan->txMixB)&&(pChan->txMixB!=TX_OUT_OFF))
1767         {
1768                 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps();
1769                 else pSps=pSps->nextSps=createPmrSps();
1770
1771                 pChan->spsTxOutB=pSps;
1772                 pSps->parentChan=pChan;
1773                 if(pChan->txMixB==TX_OUT_COMPOSITE)
1774                 {
1775                         pSps->source=pChan->pTxComposite;       
1776                 }
1777                 else if(pChan->txMixB==TX_OUT_LSD)
1778                 {
1779                         pSps->source=pChan->pTxLsdLpf;
1780                         // pChan->ptxCtcssAdjust=&pSps->inputGain;
1781                 }
1782                 else if(pChan->txMixB==TX_OUT_VOICE)
1783                 {
1784                         pSps->source=inputTmp;
1785                 }
1786                 else if(pChan->txMixB==TX_OUT_AUX)
1787                 {
1788                         pSps->source=pChan->pTxHpf;
1789                 }
1790                 else
1791                 {
1792                         pSps->source=NULL;       
1793                 }
1794
1795                 pSps->sink=pChan->pTxOut;  
1796                 pSps->sigProc=pmr_gp_fir;
1797                 pSps->enabled=1;
1798                 pSps->numChanOut=2;
1799                 pSps->selChanOut=1;
1800                 pSps->mixOut=0;
1801                 pSps->nSamples=pChan->nSamplesTx;
1802                 pSps->interpolate=6;
1803                 pSps->ncoef=taps_fir_lpf_3K_1;
1804                 pSps->size_coef=2;
1805                 pSps->coef=(void*)coef_fir_lpf_3K_1;
1806                 pSps->nx=taps_fir_lpf_3K_1;
1807                 pSps->size_x=2;
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);
1813                 
1814         }
1815
1816         pSps->nextSps=NULL;
1817
1818         #if XPMR_DEBUG0 == 1
1819         {
1820                 TRACEX((" configure tracing\n"));
1821             t_tdet      *ptdet;
1822                 
1823                 pChan->rxCtcss->pDebug0=calloc(numSamples,2);
1824                 pChan->rxCtcss->pDebug1=calloc(numSamples,2);
1825                 pChan->rxCtcss->pDebug2=calloc(numSamples,2);
1826
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);
1832                 }
1833
1834                 // buffer, 2 bytes per sample, and 16 channels
1835                 pChan->prxDebug=calloc(numSamples*16,2);
1836                 pChan->ptxDebug=calloc(numSamples*16,2);
1837         }
1838         #endif
1839
1840         TRACEX((" createPmrChannel() end\n"));
1841
1842         return pChan;
1843 }
1844 /*      
1845 */
1846 i16 destroyPmrChannel(t_pmr_chan *pChan)
1847 {
1848         t_pmr_sps       *pmr_sps, *tmp_sps;
1849
1850         TRACEX(("destroyPmrChannel()\n"));
1851
1852         free(pChan->pRxDemod);
1853         free(pChan->pRxNoise);
1854         free(pChan->pRxBase);
1855         free(pChan->pRxHpf);
1856         free(pChan->pRxLsd);
1857         free(pChan->pRxSpeaker);
1858         free(pChan->pRxDcTrack);
1859         if(pChan->pRxLsdLimit)free(pChan->pRxLsdLimit);
1860         free(pChan->pTxBase);
1861         free(pChan->pTxHpf);
1862         free(pChan->pTxPreEmp);
1863         free(pChan->pTxLimiter);
1864         free(pChan->pTxLsd);
1865         free(pChan->pTxLsdLpf);
1866         if(pChan->pTxComposite)free(pChan->pTxComposite);
1867         free(pChan->pTxCode);
1868         free(pChan->pTxOut);
1869
1870         if(pChan->pSigGen0)free(pChan->pSigGen0);
1871         if(pChan->pSigGen1)free(pChan->pSigGen1);
1872
1873         #if XPMR_DEBUG0 == 1
1874         free(pChan->pTxPttIn);
1875         free(pChan->pTxPttOut);
1876         if(pChan->prxDebug)free(pChan->prxDebug);
1877         if(pChan->ptxDebug)free(pChan->ptxDebug);
1878         free(pChan->rxCtcss->pDebug0);
1879         free(pChan->rxCtcss->pDebug1);
1880
1881         free(pChan->prxDebug0);
1882         free(pChan->prxDebug1);
1883         free(pChan->prxDebug2);
1884         free(pChan->prxDebug3);
1885
1886         free(pChan->ptxDebug0);
1887         free(pChan->ptxDebug1);
1888         free(pChan->ptxDebug2);
1889         free(pChan->ptxDebug3);
1890
1891         i16 i;
1892         for(i=0;i<CTCSS_NUM_CODES;i++)
1893         {
1894                 free(pChan->rxCtcss->tdet[i].pDebug0);
1895                 free(pChan->rxCtcss->tdet[i].pDebug1);
1896                 free(pChan->rxCtcss->tdet[i].pDebug2);
1897         }
1898         #endif
1899
1900         free(pChan->pRxCtcss);
1901
1902         pmr_sps=pChan->spsRx;
1903                                                         
1904         while(pmr_sps)
1905         {
1906                 tmp_sps = pmr_sps;
1907                 pmr_sps = tmp_sps->nextSps;
1908                 destroyPmrSps(tmp_sps);
1909         }
1910
1911         free(pChan);
1912
1913         return 0;
1914 }
1915 /*
1916 */
1917 t_pmr_sps *createPmrSps(void)
1918 {
1919         t_pmr_sps  *pSps;
1920
1921         TRACEX(("createPmrSps()\n"));
1922
1923         pSps = (t_pmr_sps *)calloc(sizeof(t_pmr_sps),1);
1924
1925         if(!pSps)printf("Error: createPmrSps()\n");
1926
1927         // pSps->x=calloc(pSps->nx,pSps->size_x);
1928
1929         return pSps;
1930 }
1931 /*
1932 */
1933 i16 destroyPmrSps(t_pmr_sps  *pSps)
1934 {
1935         TRACEX(("destroyPmrSps(%i)\n",pSps->index));
1936
1937         if(pSps->x!=NULL)free(pSps->x);
1938         free(pSps);
1939         return 0;
1940 }
1941 /*      
1942         PmrRx does the whole buffer
1943 */
1944 i16 PmrRx(t_pmr_chan *pChan, i16 *input, i16 *output)
1945 {
1946         int i,ii;
1947         t_pmr_sps *pmr_sps;
1948
1949         TRACEX(("PmrRx() %i\n",pChan->frameCountRx));
1950
1951         if(pChan==NULL){
1952                 printf("PmrRx() pChan == NULL\n");
1953                 return 1;
1954         }
1955
1956         pChan->frameCountRx++;
1957
1958         pmr_sps=pChan->spsRx;           // first sps
1959         pmr_sps->source=input;
1960
1961         if(output!=NULL)pChan->spsRxOut->sink=output;    //last sps
1962
1963         #if 0
1964         if(pChan->inputBlanking>0)
1965         {
1966                 pChan->inputBlanking-=pChan->nSamplesRx;
1967                 if(pChan->inputBlanking<0)pChan->inputBlanking=0;
1968                 for(i=0;i<pChan->nSamplesRx*6;i++)
1969                         input[i]=0;
1970         }
1971         #endif
1972         
1973         // || (pChan->radioDuplex && (pChan->pttIn || pChan->pttOut)))
1974         if(pChan->rxCpuSaver && !pChan->rxCarrierDetect) 
1975         {
1976                 if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=0;
1977                 if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=0;
1978         }
1979         else
1980         {
1981                 if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=1;
1982                 if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=1;
1983         }
1984
1985         i=0;
1986         while(pmr_sps!=NULL && pmr_sps!=0)
1987         {
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
1992         }
1993
1994         #define XPMR_VOX_HANGTIME       2000
1995         
1996         if(pChan->rxCdType==CD_XPMR_VOX)
1997         {
1998                 if(pChan->spsRxVox->compOut)
1999                 {
2000                         pChan->rxVoxTimer=XPMR_VOX_HANGTIME;    //VOX HangTime in ms
2001                 }
2002                 if(pChan->rxVoxTimer>0)
2003                 {
2004                         pChan->rxVoxTimer-=MS_PER_FRAME;
2005                         pChan->rxCarrierDetect=1;
2006                 }
2007                 else
2008                 {
2009                         pChan->rxVoxTimer=0;
2010                         pChan->rxCarrierDetect=0;
2011                 }
2012         }
2013         else
2014         {
2015                 pChan->rxCarrierDetect=!pChan->spsRx->compOut;
2016         }
2017
2018         if( !pChan->rxCpuSaver || pChan->rxCarrierDetect 
2019                 || pChan->rxCtcss->decode!=-1) ctcss_detect(pChan);
2020
2021         #if XPMR_DEBUG0 == 1
2022         // TRACEX(("Write file.\n"));
2023         ii=0;
2024         if(pChan->b.rxCapture)
2025         {
2026                 for(i=0;i<pChan->nSamplesRx;i++)
2027                 {
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
2031                         if(pChan->rxCtcss)
2032                                 pChan->prxDebug[ii++]=pChan->rxCtcss->decode*M_Q15/CTCSS_NUM_CODES;                                     // decoded ctcss
2033                         else
2034                                 pChan->prxDebug[ii++]=0;                                                                                                                        
2035         
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];
2040         
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
2044                         
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];
2049
2050                         //pChan->prxDebug[ii++]=pChan->rxCtcss->tdet[pChan->rxCtcss->testIndex-1].pDebug0[i];           // Lower Adjacent CTCSS Code
2051                         
2052                         pChan->prxDebug[ii++]=pChan->prxDebug1[i];              // Measure Output for VOX
2053                         pChan->prxDebug[ii++]=pChan->prxDebug2[i];              // Measure Output for Tuning
2054                 }
2055         }
2056         #endif
2057
2058         return 0;
2059 }
2060 /*      
2061         PmrTx does the whole buffer
2062 */
2063 i16 PmrTx(t_pmr_chan *pChan, i16 *input, i16 *output)
2064 {
2065         int i, hit=0;
2066         t_pmr_sps *pmr_sps;
2067
2068         pChan->frameCountTx++;
2069
2070         TRACEX(("PmrTx() %i\n",pChan->frameCountTx));
2071
2072         if(pChan==NULL){
2073                 printf("PmrTx() pChan == NULL\n");
2074                 return 1;
2075         }
2076
2077         if(pChan->b.startSpecialTone)
2078         {
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)
2084         {
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)
2090         {
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];
2094                 return 0;
2095         }
2096
2097         // handle transmitter ptt input
2098         hit=0;
2099         if( pChan->txPttIn && pChan->txState==0)
2100         {
2101                 pChan->txState = 2;
2102                 pChan->txPttOut=1;
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"));
2110         }
2111         else if(!pChan->txPttIn && pChan->txState==2)
2112         {
2113                 if( pChan->txTocType==TOC_NONE || !pChan->txCtcssFreq )
2114                 {
2115                         hit=1;
2116                         TRACEX((" Tx Off Immediate.\n"));
2117         }
2118                 else if(pChan->txCtcssFreq && pChan->txTocType==TOC_NOTONE)
2119                 {
2120                         pChan->txState=3;
2121                         pChan->txHangTime=TOC_NOTONE_TIME/MS_PER_FRAME;
2122                         pChan->spsSigGen0->option=3;
2123                         TRACEX((" Tx Turn Off No Tone Start.\n"));
2124                 }
2125                 else
2126                 {
2127                         pChan->txState=3;
2128                         pChan->txHangTime=0;
2129                         pChan->spsSigGen0->option=2;
2130                         TRACEX((" Tx Turn Off Phase Shift Start.\n"));
2131                 }
2132         } 
2133         else if(pChan->txState==3)
2134         {
2135                 if(pChan->txHangTime)
2136                 {
2137                         if(--pChan->txHangTime==0)hit=1;
2138
2139                 }
2140                 else if(pChan->txHangTime<=0 && pChan->spsSigGen0->state==0)
2141                 {       
2142                         hit=1;
2143                         TRACEX((" Tx Off TOC.\n"));
2144                 }
2145                 if(pChan->txPttIn)
2146                 {
2147                         TRACEX((" Tx Key During HangTime\n"));           
2148                         if((pChan->txTocType==TOC_PHASE)||(pChan->txTocType==TOC_NONE))
2149                         {
2150                                 pChan->txState = 2;
2151                                 hit=0;
2152                         }
2153                 }
2154         }
2155
2156         if( pChan->txCpuSaver && !hit && !pChan->txPttIn && !pChan->txPttOut && pChan->txState==0 ) return (1); 
2157
2158         if(hit)
2159         {
2160                 pChan->txPttOut=0;
2161                 pChan->txState=0;
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"));
2166         }
2167
2168         if(pChan->spsSigGen0)
2169         {
2170                 pChan->spsSigGen0->sigProc(pChan->spsSigGen0);
2171                 pmr_sps=pChan->spsSigGen0->nextSps;
2172                 i=0;
2173                 while(pmr_sps!=NULL && pmr_sps!=0)
2174                 {
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);
2179                 }
2180         }
2181
2182         if(pChan->spsSigGen1 && pChan->spsSigGen1->enabled)
2183         {
2184                 pChan->spsSigGen1->sigProc(pChan->spsSigGen1);
2185         }
2186
2187         // Do Voice
2188         pmr_sps=pChan->spsTx;
2189         if(!pChan->spsSigGen1->enabled)pmr_sps->source=input;
2190         else input=pmr_sps->source;
2191
2192         if(output!=NULL)
2193         {
2194                 if(pChan->spsTxOutA)pChan->spsTxOutA->sink=output;
2195                 if(pChan->spsTxOutB)pChan->spsTxOutB->sink=output;
2196         }
2197
2198         i=0;
2199         while(pmr_sps!=NULL && pmr_sps!=0)
2200         {
2201                 TRACEX((" PmrTx() sps %i\n",i++));
2202                 pmr_sps->sigProc(pmr_sps);
2203                 pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps);
2204         }
2205
2206
2207         if(pChan->txMixA==TX_OUT_OFF || !pChan->txPttOut){
2208                 for(i=0;i<pChan->nSamplesTx*2*6;i+=2)output[i]=0;
2209         }
2210
2211         if(pChan->txMixB==TX_OUT_OFF || !pChan->txPttOut ){
2212                 for(i=0;i<pChan->nSamplesTx*2*6;i+=2)output[i+1]=0;
2213         }
2214
2215         #if XPMR_DEBUG0 == 1
2216         if(pChan->b.txCapture)
2217         {
2218                 i16 ii=0;
2219                 for(i=0;i<pChan->nSamplesTx;i++)
2220                 {
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;
2225         
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;
2233         
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];
2238                                          
2239                         #if 1
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];
2244                         #else
2245                         pChan->ptxDebug[ii++]=0;
2246                         pChan->ptxDebug[ii++]=0;
2247                         pChan->ptxDebug[ii++]=0;
2248                         pChan->ptxDebug[ii++]=0;
2249                         #endif
2250                 }
2251         }
2252         #endif
2253
2254         return 0;
2255 }
2256 /* end of file */