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