Fix unused-but-set-variable warnings
[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  * 20080118 0800 sph@xelatec.com major fixes and features
28  */
29
30 /*! \file
31  *
32  * \brief Private Land Mobile Radio Channel Voice and Signaling Processor
33  *
34  * \author Steven Henke, W9SH <sph@xelatec.com> Xelatec, LLC
35  */
36 /*
37         FYI     = For Your Information
38         PMR     = Private Mobile Radio
39         RX      = Receive
40         TX      = Transmit
41         CTCSS   = Continuous Tone Coded Squelch System
42         TONE    = Same as above.
43         LSD     = Low Speed Data, subaudible signaling. May be tones or codes.
44         VOX     = Voice Operated Transmit
45         DSP     = Digital Signal Processing
46         LPF     = Low Pass Filter
47         FIR     = Finite Impulse Response (Filter)
48         IIR     = Infinite Impulse Response (Filter)
49 */
50
51 // XPMR_FILE_VERSION(__FILE__, "$Revision$")
52
53 #include <stdio.h>
54 #include <ctype.h>
55 #include <math.h>
56 #include <string.h>
57 #include <unistd.h>
58 #include <sys/ioctl.h>
59 #ifdef HAVE_SYS_IO_H
60 #include <sys/io.h>
61 #endif
62 #include <fcntl.h>
63 #include <sys/time.h>
64 #include <stdlib.h>
65 #include <errno.h>
66            
67 #include "xpmr.h"
68 #include "xpmr_coef.h"
69 #include "sinetabx.h"
70
71 static i16 pmrChanIndex=0;                              // count of created pmr instances
72 //static i16 pmrSpsIndex=0;
73
74 #if (DTX_PROG == 1) ||  XPMR_PPTP == 1
75 static int ppdrvdev=0;
76 #endif
77
78 /*
79         Trace Routines
80 */
81 void strace(i16 point, t_sdbg *sdbg, i16 idx, i16 value)
82 {
83         // make dbg_trace buffer in structure
84         if(!sdbg->mode || sdbg->point[point]<0){
85                 return;
86     } else {
87                 sdbg->buffer[(idx*XPMR_DEBUG_CHANS) + sdbg->point[point]] = value;
88         }
89 }
90 /*
91
92 */
93 void strace2(t_sdbg *sdbg)
94 {
95         int i;
96         for(i=0;i<XPMR_DEBUG_CHANS;i++)
97         {
98                 if(sdbg->source[i])
99                 {
100                         int ii;
101                         for(ii=0;ii<SAMPLES_PER_BLOCK;ii++)
102                         {
103                                 sdbg->buffer[ii*XPMR_DEBUG_CHANS + i] = sdbg->source[i][ii];
104                     }
105                 }
106         }
107 }
108 #if XPMR_PPTP == 1
109 /*
110         Hardware Trace Signals via the PC Parallel Port
111 */
112 void    pptp_init (void)
113 {
114         if (ppdrvdev == 0)
115         ppdrvdev = open("/dev/ppdrv_device", 0);
116
117     if (ppdrvdev < 0)
118     {
119         ast_log(LOG_ERROR, "open /dev/ppdrv_ppdrvdev returned %i\n",ppdrvdev);
120                 exit(0);
121         }
122         ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX | DTX_TP1 | DTX_TP2);
123         ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR,    DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX | DTX_TP1 | DTX_TP2);
124 }
125 /*
126 */
127 void    pptp_write(i16 bit, i16 state)
128 {
129         if(bit==0)
130         {
131                 if(state)ioctl(ppdrvdev,PPDRV_IOC_PINSET,DTX_TP1);
132                 else ioctl(ppdrvdev,PPDRV_IOC_PINCLEAR,DTX_TP1);
133         }
134         else
135         {
136                 if(state)ioctl(ppdrvdev,PPDRV_IOC_PINSET,DTX_TP2);
137                 else ioctl(ppdrvdev,PPDRV_IOC_PINCLEAR,DTX_TP2);
138         }
139 }
140 #endif
141 /*
142         take source string allocate and copy
143         copy is modified, delimiters are replaced with zeros to mark
144         end of string
145         count set pointers
146         string_parse( char *src, char *dest, char **sub)
147 */
148 i16 string_parse(char *src, char **dest, char ***ptrs)
149 {
150         char *p,*pd;
151         char *ptstr[1000];
152         i16 i, slen, numsub;
153
154         TRACEJ(2,("string_parse(%s)\n",src));
155
156         slen=strlen(src);
157         TRACEJ(2,(" source len = %i\n",slen));
158
159         pd=*dest;
160         free(pd);
161     pd=calloc(slen+1,1);
162         memcpy(pd,src,slen);
163         *dest=pd;
164
165         p=0;
166         numsub=0;
167         for(i=0;i<slen+1;i++)
168         {
169                 TRACEJ(5,(" pd[%i] = %c\n",i,pd[i]));
170
171                 if( p==0 && pd[i]!=',' && pd[i]!=' ' )
172                 {
173                         p=&(pd[i]);     
174                 }
175                 else if(pd[i]==',' || pd[i]==0 )
176                 {
177                         ptstr[numsub]=p;
178                         pd[i]=0;
179                         p=0;
180                         numsub++;
181                 }
182         }
183
184         for(i=0;i<numsub;i++)
185         {
186                 TRACEJ(5,(" ptstr[%i] = %p %s\n",i,ptstr[i],ptstr[i]));
187         }
188
189         if(*ptrs)free(*ptrs);
190         *ptrs=calloc(numsub,4);
191         for(i=0;i<numsub;i++)
192         {
193                 (*ptrs)[i]=ptstr[i];    
194                 TRACEJ(5,(" %i = %s\n",i,(*ptrs)[i]));
195         }
196         TRACEJ(5,("string_parse()=%i\n\n",numsub));
197
198         return numsub;
199 }
200 /*
201         the parent program defines
202         pRxCodeSrc and pTxCodeSrc string pointers to the list of codes
203         pTxCodeDefault the default Tx Code.
204
205 */
206 i16 code_string_parse(t_pmr_chan *pChan)
207 {
208         i16 i, ii, hit, ti;
209         char *p;
210         float f, maxctcsstxfreq;
211
212         t_pmr_sps       *pSps;
213         i16     maxctcssindex;
214
215         TRACEF(1,("code_string_parse(%i)\n",0)); 
216         TRACEF(1,("pChan->pRxCodeSrc %s \n",pChan->pRxCodeSrc));
217         TRACEF(1,("pChan->pTxCodeSrc %s \n",pChan->pTxCodeSrc));
218         TRACEF(1,("pChan->pTxCodeDefault %s \n",pChan->pTxCodeDefault));
219
220         //printf("code_string_parse() %s / %s / %s / %s \n",pChan->name, pChan->pTxCodeDefault,pChan->pTxCodeSrc,pChan->pRxCodeSrc);
221
222         maxctcssindex=CTCSS_NULL;
223         maxctcsstxfreq=CTCSS_NULL;
224         pChan->txctcssdefault_index=CTCSS_NULL;
225         pChan->txctcssdefault_value=CTCSS_NULL;
226
227         pChan->b.ctcssRxEnable=pChan->b.ctcssTxEnable=0;
228         pChan->b.dcsRxEnable=pChan->b.dcsTxEnable=0;
229         pChan->b.lmrRxEnable=pChan->b.lmrTxEnable=0;
230         pChan->b.mdcRxEnable=pChan->b.mdcTxEnable=0;
231         pChan->b.dstRxEnable=pChan->b.dstTxEnable=0;
232         pChan->b.p25RxEnable=pChan->b.p25TxEnable=0;
233
234         if(pChan->spsLsdGen){
235                 pChan->spsLsdGen->enabled=0;
236                 pChan->spsLsdGen->state=0;
237         }
238
239         TRACEF(1,("code_string_parse(%i) 05\n",0));
240
241         pChan->numrxcodes = string_parse( pChan->pRxCodeSrc, &(pChan->pRxCodeStr), &(pChan->pRxCode));
242         pChan->numtxcodes = string_parse( pChan->pTxCodeSrc, &(pChan->pTxCodeStr), &(pChan->pTxCode));
243
244         if(pChan->numrxcodes!=pChan->numtxcodes)printf("ERROR: numrxcodes != numtxcodes \n");
245         
246         pChan->rxCtcss->enabled=0;
247         pChan->rxCtcss->gain=1*M_Q8;
248         pChan->rxCtcss->limit=8192;
249         pChan->rxCtcss->input=pChan->pRxLsdLimit;
250         pChan->rxCtcss->decode=CTCSS_NULL;
251
252         pChan->rxCtcss->testIndex=0;
253         if(!pChan->rxCtcss->testIndex)pChan->rxCtcss->testIndex=3;
254
255         pChan->rxctcssfreq[0]=0;        // decode now   CTCSS_RXONLY
256
257         for(i=0;i<CTCSS_NUM_CODES;i++)
258         {
259                 pChan->rxctcss[i]=0;
260                 pChan->txctcss[i]=0;
261                 pChan->rxCtcssMap[i]=CTCSS_NULL;
262         }
263
264         TRACEF(1,("code_string_parse(%i) 10\n",0));
265         
266         #ifdef XPMRX_H
267         xpmrx(pChan,XXO_LSDCODEPARSE);
268         #endif
269
270         // Do Receive Codes String
271         for(i=0;i<pChan->numrxcodes;i++)
272         {
273                 i16 ri,_ti;
274                 float _f;
275
276                 p=pChan->pStr=pChan->pRxCode[i];
277
278                 #ifdef HAVE_XPMRX
279                 if(!xpmrx(pChan,XXO_LSDCODEPARSE_1))
280                 #endif
281                 {
282                         sscanf(p, "%30f", &_f);
283                         ri=CtcssFreqIndex(_f);
284                         if(ri>maxctcssindex)maxctcssindex=ri;
285
286                         sscanf(pChan->pTxCode[i], "%30f", &_f);
287                     _ti=CtcssFreqIndex(_f);
288                         if(_f>maxctcsstxfreq)maxctcsstxfreq=_f;
289
290                         if(ri>CTCSS_NULL && _ti>CTCSS_NULL)
291                         {
292                                 pChan->b.ctcssRxEnable=pChan->b.ctcssTxEnable=1;
293                                 pChan->rxCtcssMap[ri]=_ti;
294                                 pChan->numrxctcssfreqs++;
295                                 TRACEF(1,("pChan->rxctcss[%i]=%s  pChan->rxCtcssMap[%i]=%i\n",i,pChan->rxctcss[i],ri,_ti));
296                         }
297                         else if(ri>CTCSS_NULL && _f==0)
298                         {
299                                 pChan->b.ctcssRxEnable=1;
300                                 pChan->rxCtcssMap[ri]=CTCSS_RXONLY;
301                                 pChan->numrxctcssfreqs++;
302                                 TRACEF(1,("pChan->rxctcss[%i]=%s  pChan->rxCtcssMap[%i]=%i RXONLY\n",i,pChan->rxctcss[i],ri,_ti));
303                         }
304                         else
305                         {
306                                 i16 _ii;
307                                 pChan->numrxctcssfreqs=0;
308                                 for(_ii=0;_ii<CTCSS_NUM_CODES;_ii++) pChan->rxCtcssMap[_ii]=CTCSS_NULL;
309                                 TRACEF(1,("WARNING: Invalid Channel code detected and ignored. %i %s %s \n",i,pChan->pRxCode[i],pChan->pTxCode[i]));
310                         }
311                 }
312         }
313
314         TRACEF(1,("code_string_parse() CTCSS Init Struct  %i  %i\n",pChan->b.ctcssRxEnable,pChan->b.ctcssTxEnable));
315         if(pChan->b.ctcssRxEnable)
316         {
317                 pChan->rxHpfEnable=1;
318                 pChan->spsRxLsdNrz->enabled=pChan->rxCenterSlicerEnable=1;
319                 pChan->rxCtcssDecodeEnable=1;
320                 pChan->rxCtcss->enabled=1;
321         }
322         else
323         {
324                 pChan->rxHpfEnable=1;
325                 pChan->spsRxLsdNrz->enabled=pChan->rxCenterSlicerEnable=0;
326                 pChan->rxCtcssDecodeEnable=0;
327                 pChan->rxCtcss->enabled=0;
328         }
329
330         TRACEF(1,("code_string_parse() CTCSS Init Decoders \n"));
331         for(i=0;i<CTCSS_NUM_CODES;i++)
332         {
333                 t_tdet *ptdet;
334                 ptdet=&(pChan->rxCtcss->tdet[i]);
335                 ptdet->counterFactor=coef_ctcss_div[i];
336                 ptdet->state=1;
337                 ptdet->setpt=(M_Q15*0.041);                                     // 0.069
338                 ptdet->hyst =(M_Q15*0.0130);
339                 ptdet->binFactor=(M_Q15*0.135);                         // was 0.140
340                 ptdet->fudgeFactor=8;
341         }
342
343
344         // DEFAULT TX CODE
345         TRACEF(1,("code_string_parse() Default Tx Code %s \n",pChan->pTxCodeDefault));
346         pChan->txcodedefaultsmode=SMODE_NULL;
347         p=pChan->pStr=pChan->pTxCodeDefault;
348
349         #ifdef HAVE_XPMRX
350         if(!lsd_code_parse(pChan,3))
351         #endif
352         {
353                 sscanf(p, "%30f", &f);
354             ti=CtcssFreqIndex(f);
355                 if(f>maxctcsstxfreq)maxctcsstxfreq=f;
356
357                 if(ti>CTCSS_NULL)
358                 {
359                         pChan->b.ctcssTxEnable=1;
360                         pChan->txctcssdefault_index=ti;
361                         pChan->txctcssdefault_value=f;
362                         pChan->spsSigGen0->freq=f*10;
363                         pChan->txcodedefaultsmode=SMODE_CTCSS;
364                         TRACEF(1,("code_string_parse() Tx Default CTCSS = %s %i %f\n",p,ti,f));
365                 }
366         }
367
368
369         // set x for maximum length and just change pointers
370         TRACEF(1,("code_string_parse() Filter Config \n"));
371         pSps=pChan->spsTxLsdLpf;
372         if(pSps->x)free(pSps->x);
373         if(maxctcsstxfreq>203.5)
374         {
375                 pSps->ncoef=taps_fir_lpf_250_9_66;
376                 pSps->size_coef=2;
377                 pSps->coef=(void*)coef_fir_lpf_250_9_66;
378                 pSps->nx=taps_fir_lpf_250_9_66;
379                 pSps->size_x=2;
380                 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
381                 pSps->calcAdjust=gain_fir_lpf_250_9_66;
382                 TRACEF(1,("code_string_parse() Tx Filter Freq High\n"));
383         }
384         else
385         {
386                 pSps->ncoef=taps_fir_lpf_215_9_88;
387                 pSps->size_coef=2;
388                 pSps->coef=(void*)coef_fir_lpf_215_9_88;
389                 pSps->nx=taps_fir_lpf_215_9_88;
390                 pSps->size_x=2;
391                 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
392                 pSps->calcAdjust=gain_fir_lpf_215_9_88;
393                 TRACEF(1,("code_string_parse() Tx Filter Freq Low\n"));
394         }
395
396         // CTCSS Rx Decoder Low Pass Filter
397         hit=0;
398         ii=     CtcssFreqIndex(203.5);
399         for(i=ii;i<CTCSS_NUM_CODES;i++)
400         {
401                 if(pChan->rxCtcssMap[i]>CTCSS_NULL)hit=1;
402         }
403
404         pSps=pChan->spsRxLsd;
405         if(pSps->x)free(pSps->x);
406         if(hit)
407         {
408                 pSps->ncoef=taps_fir_lpf_250_9_66;
409                 pSps->size_coef=2;
410                 pSps->coef=(void*)coef_fir_lpf_250_9_66;
411                 pSps->nx=taps_fir_lpf_250_9_66;
412                 pSps->size_x=2;
413                 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
414                 pSps->calcAdjust=gain_fir_lpf_250_9_66;
415                 TRACEF(1,("code_string_parse() Rx Filter Freq High\n"));
416         }
417         else
418         {
419                 pSps->ncoef=taps_fir_lpf_215_9_88;
420                 pSps->size_coef=2;
421                 pSps->coef=(void*)coef_fir_lpf_215_9_88;
422                 pSps->nx=taps_fir_lpf_215_9_88;
423                 pSps->size_x=2;
424                 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
425                 pSps->calcAdjust=gain_fir_lpf_215_9_88;
426                 TRACEF(1,("code_string_parse() Rx Filter Freq Low\n"));
427         }
428
429         if(pChan->b.ctcssRxEnable || pChan->b.dcsRxEnable || pChan->b.lmrRxEnable)
430         {
431                 pChan->rxCenterSlicerEnable=1;
432                 pSps->enabled=1;
433         }
434         else
435         {
436                 pChan->rxCenterSlicerEnable=0;
437                 pSps->enabled=0;
438         }
439
440         #if XPMR_DEBUG0 == 1
441         TRACEF(2,("code_string_parse() ctcssRxEnable = %i \n",pChan->b.ctcssRxEnable));
442         TRACEF(2,("                    ctcssTxEnable = %i \n",pChan->b.ctcssTxEnable));
443         TRACEF(2,("                      dcsRxEnable = %i \n",pChan->b.dcsRxEnable));
444         TRACEF(2,("                      lmrRxEnable = %i \n",pChan->b.lmrRxEnable));
445         TRACEF(2,("               txcodedefaultsmode = %i \n",pChan->txcodedefaultsmode));
446         for(i=0;i<CTCSS_NUM_CODES;i++)
447         {
448                 TRACEF(2,("rxCtcssMap[%i] = %i \n",i,pChan->rxCtcssMap[i]));
449         }
450     #endif
451
452         #ifdef HAVE_XPMRX
453         lsd_code_parse(pChan,5);
454         #endif
455
456         TRACEF(1,("code_string_parse(%i) end\n",0));
457
458         return 0;
459 }
460 /*
461         Convert a Frequency in Hz to a zero based CTCSS Table index
462 */
463 i16 CtcssFreqIndex(float freq)
464 {
465         i16 i,hit=CTCSS_NULL;
466
467         for(i=0;i<CTCSS_NUM_CODES;i++){
468                 if(freq==freq_ctcss[i])hit=i;
469         }
470         return hit;
471 }
472 /*
473         pmr_rx_frontend
474         Takes a block of data and low pass filters it.
475         Determines the amplitude of high frequency noise for carrier detect.
476         Decimates input data to change the rate.
477 */
478 i16 pmr_rx_frontend(t_pmr_sps *mySps)
479 {
480         #define DCgainBpfNoise  65536
481
482         i16 samples,iOutput, *input, *output, *noutput;
483         i16 *x, *coef;
484     i32 i, naccum, outputGain, calcAdjust;
485         i64 y;
486         i16 nx, hyst, setpt, compOut;
487         i16 amax, amin, apeak, discounteru, discounterl, discfactor;
488         i16 decimator, decimate, doNoise;
489
490         TRACEJ(5,("pmr_rx_frontend()\n"));
491
492         if(!mySps->enabled)return(1);
493
494         decimator = mySps->decimator;
495         decimate = mySps->decimate;
496
497         input     = mySps->source;
498         output    = mySps->sink;
499         noutput   = mySps->parentChan->pRxNoise;
500
501         nx        = mySps->nx;
502         coef      = mySps->coef;
503
504         calcAdjust = mySps->calcAdjust;
505         outputGain = mySps->outputGain;
506
507         amax=mySps->amax;
508         amin=mySps->amin;
509         apeak=mySps->apeak;
510         discounteru=mySps->discounteru;
511         discounterl=mySps->discounterl;
512         discfactor=mySps->discfactor;
513         setpt=mySps->setpt;
514         hyst=mySps->hyst;
515         compOut=mySps->compOut;
516
517         samples=mySps->nSamples*decimate;
518         x=mySps->x;
519         iOutput=0;
520
521         if(mySps->parentChan->rxCdType!=CD_XPMR_VOX)doNoise=1;
522         else doNoise=0;
523
524         for(i=0;i<samples;i++)
525         {
526                 i16 n;
527
528                 //shift the old samples
529             for(n=nx-1; n>0; n--)
530                x[n] = x[n-1];
531
532             x[0] = input[i*2];
533
534                 --decimator;
535
536                 if(decimator<=0)
537                 {
538                         decimator=decimate;
539
540                     y=0;
541                     for(n=0; n<nx; n++)
542                         y += coef[n] * x[n];
543
544                     y=((y/calcAdjust)*outputGain)/M_Q8;
545
546                         if(y>32767)y=32767;
547                         else if(y<-32767)y=-32767;
548
549                     output[iOutput]=y;                                  // Rx Baseband decimated
550                         noutput[iOutput++] = apeak;                     // Rx Noise
551                 }
552
553                 if(doNoise)
554                 {
555                         // calculate noise output
556                         naccum=0;
557                     for(n=0; n<nx; n++)
558                         naccum += coef_fir_bpf_noise_1[n] * x[n];
559
560                     naccum /= DCgainBpfNoise;
561
562                         if(naccum>amax)
563                         {
564                                 amax=naccum;
565                                 discounteru=discfactor;
566                         }
567                         else if(--discounteru<=0)
568                         {
569                                 discounteru=discfactor;
570                                 amax=(i32)((amax*32700)/32768);
571                         }
572
573                         if(naccum<amin)
574                         {
575                                 amin=naccum;
576                                 discounterl=discfactor;
577                         }
578                         else if(--discounterl<=0)
579                         {
580                                 discounterl=discfactor;
581                                 amin=(i32)((amin*32700)/32768);
582                         }
583
584                         apeak=(amax-amin)/2;
585
586                 }  // if doNoise
587         }
588
589         if(doNoise)
590         {
591                 ((t_pmr_chan *)(mySps->parentChan))->rxRssi=apeak;
592
593                 if(apeak>setpt || (compOut&&(apeak>(setpt-hyst)))) compOut=1;
594                 else compOut=0;
595                 mySps->compOut=compOut;
596                 mySps->amax=amax;
597                 mySps->amin=amin;
598                 mySps->apeak=apeak;
599                 mySps->discounteru=discounteru;
600                 mySps->discounterl=discounterl;
601         }
602
603         return 0;
604 }
605 /*
606         pmr general purpose fir
607         works on a block of samples
608 */
609 i16 pmr_gp_fir(t_pmr_sps *mySps)
610 {
611         i32 nsamples,inputGain,outputGain,calcAdjust;
612         i16 *input, *output;
613         i16 *x, *coef;
614     i32 i, ii;
615         i16 nx, hyst, setpt, compOut;
616         i16 amax, amin, apeak=0, discounteru=0, discounterl=0, discfactor;
617         i16 decimator, decimate, interpolate;
618         i16 numChanOut, selChanOut, mixOut, monoOut;
619
620         TRACEJ(5,("pmr_gp_fir() %i %i\n",mySps->index, mySps->enabled));
621
622         if(!mySps->enabled)return(1);
623
624         inputGain  = mySps->inputGain;
625         calcAdjust = mySps->calcAdjust;
626         outputGain = mySps->outputGain;
627
628         input      = mySps->source;
629         output     = mySps->sink;
630         x          = mySps->x;
631         nx         = mySps->nx;
632         coef       = mySps->coef;
633
634         decimator   = mySps->decimator;
635         decimate        = mySps->decimate;
636         interpolate = mySps->interpolate;
637
638         setpt      = mySps->setpt;
639         compOut    = mySps->compOut;
640
641         inputGain  = mySps->inputGain;
642         outputGain = mySps->outputGain;
643         numChanOut = mySps->numChanOut;
644         selChanOut = mySps->selChanOut;
645         mixOut     = mySps->mixOut;
646         monoOut    = mySps->monoOut;
647
648         amax=mySps->amax;
649         amin=mySps->amin;
650
651         discfactor=mySps->discfactor;
652         hyst=mySps->hyst;
653         setpt=mySps->setpt;
654         nsamples=mySps->nSamples;
655
656         if(mySps->option==3)
657         {
658                 mySps->option=0;
659                 mySps->enabled=0;
660                 for(i=0;i<nsamples;i++)
661                 {
662                         if(monoOut)
663                                 output[(i*2)]=output[(i*2)+1]=0;
664                         else
665                                 output[(i*numChanOut)+selChanOut]=0;
666                 }
667                 return 0;
668         }
669
670         ii=0;
671         for(i=0;i<nsamples;i++)
672         {
673                 int ix;
674
675                 int64_t y=0;
676
677                 if(decimate<0)
678                 {
679                         decimator=decimate;
680                 }
681
682                 for(ix=0;ix<interpolate;ix++)
683                 {
684                         i16 n;
685                         y=0;
686
687                     for(n=nx-1; n>0; n--)
688                        x[n] = x[n-1];
689                     x[0] = (input[i]*inputGain)/M_Q8;
690
691                         #if 0
692                         --decimator;
693                         if(decimator<=0)
694                         {
695                                 decimator=decimate;
696                             for(n=0; n<nx; n++)
697                                 y += coef[n] * x[n];
698                                 y /= (outputGain*3);
699                                 output[ii++]=y;
700                         }
701                         #else
702                     for(n=0; n<nx; n++)
703                         y += coef[n] * x[n];
704
705                         y=((y/calcAdjust)*outputGain)/M_Q8;
706
707                         if(mixOut){
708                                 if(monoOut){
709                                         output[(ii*2)]=output[(ii*2)+1]+=y;
710                                 }
711                                 else{
712                                         output[(ii*numChanOut)+selChanOut]+=y;
713                                 }
714                         }
715                         else{
716                                 if(monoOut){
717                                         output[(ii*2)]=output[(ii*2)+1]=y;
718                                 }
719                                 else{
720                                         output[(ii*numChanOut)+selChanOut]=y;
721                                 }
722                         }
723                         ii++;
724                     #endif
725                 }
726
727                 // amplitude detector
728                 if(setpt)
729                 {
730                         i16 accum=y;
731
732                         if(accum>amax)
733                         {
734                                 amax=accum;
735                                 discounteru=discfactor;
736                         }
737                         else if(--discounteru<=0)
738                         {
739                                 discounteru=discfactor;
740                                 amax=(i32)((amax*32700)/32768);
741                         }
742
743                         if(accum<amin)
744                         {
745                                 amin=accum;
746                                 discounterl=discfactor;
747                         }
748                         else if(--discounterl<=0)
749                         {
750                                 discounterl=discfactor;
751                                 amin=(i32)((amin*32700)/32768);
752                         }
753
754                         apeak = (i32)(amax-amin)/2;
755
756                         if(apeak>setpt)compOut=1;
757                         else if(compOut&&(apeak<(setpt-hyst)))compOut=0;
758                 }
759         }
760
761         mySps->decimator = decimator;
762
763         mySps->amax=amax;
764         mySps->amin=amin;
765         mySps->apeak=apeak;
766         mySps->discounteru=discounteru;
767         mySps->discounterl=discounterl;
768
769         mySps->compOut=compOut;
770
771         return 0;
772 }
773 /*
774         general purpose integrator lpf
775 */
776 i16 gp_inte_00(t_pmr_sps *mySps)
777 {
778         i16 npoints;
779         i16 *input, *output;
780
781         i32 outputGain;
782         i32     i;
783         i32 accum;
784
785         i32 state00;
786         i16 coeff00, coeff01;
787
788         TRACEJ(5,("gp_inte_00() %i\n",mySps->enabled));
789         if(!mySps->enabled)return(1);
790
791         input   = mySps->source;
792         output  = mySps->sink;
793
794         npoints=mySps->nSamples;
795
796         outputGain=mySps->outputGain;
797
798         coeff00=((i16*)mySps->coef)[0];
799         coeff01=((i16*)mySps->coef)[1];
800         state00=((i32*)mySps->x)[0];
801
802         // note fixed gain of 2 to compensate for attenuation
803         // in passband
804
805         for(i=0;i<npoints;i++)
806         {
807                 accum=input[i];
808                 state00 = accum + (state00*coeff01)/M_Q15;
809                 accum = (state00*coeff00)/(M_Q15/4);
810                 output[i]=(accum*outputGain)/M_Q8;
811         }
812
813         ((i32*)(mySps->x))[0]=state00;
814
815         return 0;
816 }
817 /*
818         general purpose differentiator hpf
819 */
820 i16 gp_diff(t_pmr_sps *mySps)
821 {
822         i16 *input, *output;
823         i16 npoints;
824         i32 outputGain, calcAdjust;
825         i32     i;
826         i32 temp0,temp1;
827         i16 x0;
828         i32 _y0;
829         i16 a0,a1;
830         i16 *coef;
831         i16 *x;
832
833         input   = mySps->source;
834         output  = mySps->sink;
835
836         npoints=mySps->nSamples;
837
838         outputGain=mySps->outputGain;
839         calcAdjust=mySps->calcAdjust;
840
841         coef=(i16*)(mySps->coef);
842         x=(i16*)(mySps->x);
843         a0=coef[0];
844         a1=coef[1];
845
846         x0=x[0];
847
848         TRACEJ(5,("gp_diff()\n"));
849
850         for (i=0;i<npoints;i++)
851     {
852                 temp0 = x0 * a1;
853                    x0 = input[i];
854                 temp1 = input[i] * a0;
855                   _y0 = (temp0 + temp1)/calcAdjust;
856                   _y0 = (_y0*outputGain)/M_Q8;
857                 
858                 if(_y0>32766)_y0=32766;
859                 else if(_y0<-32766)_y0=-32766;
860         output[i]=_y0;
861     }
862
863         x[0]=x0;
864
865         return 0;
866 }
867 /*      ----------------------------------------------------------------------
868         CenterSlicer
869 */
870 i16 CenterSlicer(t_pmr_sps *mySps)
871 {
872         i16 npoints/*, lhit, uhit*/;
873         i16 *input, *output, *buff;
874
875         i32 inputGainB;
876         i32     i;
877         i32 accum;
878
879         i32  amax;                      // buffer amplitude maximum
880         i32  amin;                      // buffer amplitude minimum
881         i32  apeak;                     // buffer amplitude peak
882         i32  center;
883         i32  setpt;                     // amplitude set point for peak tracking
884
885         i32  discounteru;       // amplitude detector integrator discharge counter upper
886         i32  discounterl;       // amplitude detector integrator discharge counter lower
887         i32  discfactor;        // amplitude detector integrator discharge factor
888
889         TRACEJ(5,("CenterSlicer() %i\n",mySps->enabled));
890         if(!mySps->enabled)return(1);
891
892         input   = mySps->source;
893         output  = mySps->sink;                          // limited output
894         buff    = mySps->buff;
895
896         npoints=mySps->nSamples;
897
898         inputGainB=mySps->inputGainB;
899
900         amax=mySps->amax;
901         amin=mySps->amin;
902         setpt=mySps->setpt;
903         apeak=mySps->apeak;
904         discounteru=mySps->discounteru;
905         discounterl=mySps->discounterl;
906
907         discfactor=mySps->discfactor;
908         npoints=mySps->nSamples;
909
910         for(i=0;i<npoints;i++)
911         {
912                 #if XPMR_DEBUG0 == 1
913                 static i32 tfx=0;
914                 #endif
915                 accum=input[i];
916
917                 /* lhit=uhit=0; */
918
919                 if(accum>amax)
920                 {
921                         amax=accum;
922                         /* uhit=1; */
923                         if(amin<(amax-setpt))
924                         {
925                                 amin=(amax-setpt);
926                                 /* lhit=1; */
927                         }
928                 }
929                 else if(accum<amin)
930                 {
931                         amin=accum;
932                         /* lhit=1; */
933                         if(amax>(amin+setpt))
934                         {
935                                 amax=(amin+setpt);
936                                 /* uhit=1; */
937                         }
938                 }
939                 #if 0
940                 if((discounteru-=1)<=0 && amax>amin)
941                 {
942                         if((amax-=10)<amin)amax=amin;
943                         uhit=1;
944                 }
945
946                 if((discounterl-=1)<=0 && amin<amax)
947                 {
948                         if((amin+=10)>amax)amin=amax;
949                         lhit=1;
950                 }
951                 if(uhit)discounteru=discfactor;
952                 if(lhit)discounterl=discfactor;
953
954                 #else
955                  
956                 if((amax-=discfactor)<amin)amax=amin;
957                 if((amin+=discfactor)>amax)amin=amax;
958
959                 #endif
960
961                 apeak = (amax-amin)/2;
962                 center = (amax+amin)/2;
963                 accum = accum - center;
964
965                 output[i]=accum;                        // sink output unlimited/centered.
966
967                 // do limiter function
968                 if(accum>inputGainB)accum=inputGainB;
969                 else if(accum<-inputGainB)accum=-inputGainB;
970                 buff[i]=accum;
971
972                 #if XPMR_DEBUG0 == 1
973                 #if 0
974                 mySps->parentChan->pRxLsdCen[i]=center;         // trace center ref
975                 #else
976                 if((tfx++/8)&1)                                                         // trace min/max levels
977                         mySps->parentChan->pRxLsdCen[i]=amax;
978                 else
979                         mySps->parentChan->pRxLsdCen[i]=amin;
980                 #endif
981             #if 0
982                 if(mySps->parentChan->frameCountRx&0x01) mySps->parentChan->prxDebug1[i]=amax;
983                 else mySps->parentChan->prxDebug1[i]=amin;
984                 #endif
985                 #endif
986         }
987
988         mySps->amax=amax;
989         mySps->amin=amin;
990         mySps->apeak=apeak;
991         mySps->discounteru=discounteru;
992         mySps->discounterl=discounterl;
993
994         return 0;
995 }
996 /*      ----------------------------------------------------------------------
997         MeasureBlock
998         determine peak amplitude
999 */
1000 i16 MeasureBlock(t_pmr_sps *mySps)
1001 {
1002         i16 npoints;
1003         i16 *input, *output;
1004
1005         i32     i;
1006         i32 accum;
1007
1008         i16  amax;                      // buffer amplitude maximum
1009         i16  amin;                      // buffer amplitude minimum
1010         i16  apeak=0;                   // buffer amplitude peak (peak to peak)/2
1011         i16  setpt;                     // amplitude set point for amplitude comparator
1012
1013         i32  discounteru;       // amplitude detector integrator discharge counter upper
1014         i32  discounterl;       // amplitude detector integrator discharge counter lower
1015         i32  discfactor;        // amplitude detector integrator discharge factor
1016
1017         TRACEJ(5,("MeasureBlock() %i\n",mySps->enabled));
1018
1019         if(!mySps->enabled)return 1;
1020
1021         if(mySps->option==3)
1022         {
1023                 mySps->amax = mySps->amin = mySps->apeak = \
1024                 mySps->discounteru = mySps->discounterl = \
1025                 mySps->enabled = 0;
1026                 return 1;
1027         }
1028
1029         input   = mySps->source;
1030         output  = mySps->sink;
1031
1032         npoints=mySps->nSamples;
1033
1034         amax=mySps->amax;
1035         amin=mySps->amin;
1036         setpt=mySps->setpt;
1037         discounteru=mySps->discounteru;
1038         discounterl=mySps->discounterl;
1039
1040         discfactor=mySps->discfactor;
1041         npoints=mySps->nSamples;
1042
1043         for(i=0;i<npoints;i++)
1044         {
1045                 accum=input[i];
1046
1047                 if(accum>amax)
1048                 {
1049                         amax=accum;
1050                         discounteru=discfactor;
1051                 }
1052                 else if(--discounteru<=0)
1053                 {
1054                         discounteru=discfactor;
1055                         amax=(i32)((amax*32700)/32768);
1056                 }
1057
1058                 if(accum<amin)
1059                 {
1060                         amin=accum;
1061                         discounterl=discfactor;
1062                 }
1063                 else if(--discounterl<=0)
1064                 {
1065                         discounterl=discfactor;
1066                         amin=(i32)((amin*32700)/32768);
1067                 }
1068
1069                 apeak = (i32)(amax-amin)/2;
1070                 if(output)output[i]=apeak;
1071         }
1072
1073         mySps->amax=amax;
1074         mySps->amin=amin;
1075         mySps->apeak=apeak;
1076         mySps->discounteru=discounteru;
1077         mySps->discounterl=discounterl;
1078         if(apeak>=setpt) mySps->compOut=1;
1079         else mySps->compOut=0;
1080
1081         //TRACEX((" -MeasureBlock()=%i\n",mySps->apeak));
1082         return 0;
1083 }
1084 /*
1085         SoftLimiter
1086 */
1087 i16 SoftLimiter(t_pmr_sps *mySps)
1088 {
1089         i16 npoints;
1090         //i16 samples, lhit,uhit;
1091         i16 *input, *output;
1092
1093         i32 /*inputGain, */outputGain;
1094         i32     i;
1095         i32 accum;
1096         i32  tmp;
1097
1098         i32  amax;                      // buffer amplitude maximum
1099         i32  amin;                      // buffer amplitude minimum
1100         //i32  apeak;           // buffer amplitude peak
1101         i32  setpt;                     // amplitude set point for amplitude comparator
1102
1103         input   = mySps->source;
1104         output  = mySps->sink;
1105
1106         /* inputGain=mySps->inputGain; */
1107         outputGain=mySps->outputGain;
1108
1109         npoints=mySps->nSamples;
1110
1111         setpt=mySps->setpt;
1112         amax=(setpt*124)/128;
1113         amin=-amax;
1114
1115         TRACEJ(5,("SoftLimiter() %i %i %i) \n",amin, amax,setpt));
1116
1117         for(i=0;i<npoints;i++)
1118         {
1119                 accum=input[i];
1120                 //accum=input[i]*mySps->inputGain/256;
1121
1122                 if(accum>setpt)
1123                 {
1124                     tmp=((accum-setpt)*4)/128;
1125                     accum=setpt+tmp;
1126                         if(accum>amax)accum=amax;
1127                         accum=setpt;
1128                 }
1129                 else if(accum<-setpt)
1130                 {
1131                     tmp=((accum+setpt)*4)/128;
1132                     accum=(-setpt)-tmp;
1133                         if(accum<amin)accum=amin;
1134                         accum=-setpt;
1135                 }
1136
1137                 output[i]=(accum*outputGain)/M_Q8;
1138         }
1139
1140         return 0;
1141 }
1142 /*
1143         SigGen() - sine, square function generator
1144         sps overloaded values
1145         discfactor  = phase factor
1146         discfactoru = phase index
1147         if source is not NULL then mix it in!
1148
1149         sign table and output gain are in Q15 format (32767=.999)
1150 */
1151 i16     SigGen(t_pmr_sps *mySps)
1152 {
1153         #define PH_FRACT_FACT   128
1154
1155         i32 ph;
1156         i16 i,outputgain,waveform,numChanOut,selChanOut;
1157         i32 accum;
1158         
1159         t_pmr_chan *pChan;
1160         pChan=mySps->parentChan;
1161         TRACEC(5,("SigGen(%i %i %i)\n",mySps->option,mySps->enabled,mySps->state));
1162
1163         if(!mySps->freq ||!mySps->enabled)return 0;
1164
1165         outputgain=mySps->outputGain;
1166         waveform=0;
1167         numChanOut=mySps->numChanOut;
1168         selChanOut=mySps->selChanOut;
1169
1170     if(mySps->option==1)
1171         {
1172                 mySps->option=0;
1173                 mySps->state=1;
1174                 mySps->discfactor=
1175                         (SAMPLES_PER_SINE*mySps->freq*PH_FRACT_FACT)/mySps->sampleRate/10;
1176
1177                 TRACEF(5,(" SigGen() discfactor = %i\n",mySps->discfactor));
1178                 if(mySps->discounterl)mySps->state=2;
1179         }
1180         else if(mySps->option==2)
1181         {
1182                 i16 shiftfactor=CTCSS_TURN_OFF_SHIFT;
1183                 // phase shift request
1184                 mySps->option=0;
1185                 mySps->state=2;
1186                 mySps->discounterl=CTCSS_TURN_OFF_TIME-(2*MS_PER_FRAME);                //
1187
1188                 mySps->discounteru = \
1189                         (mySps->discounteru + (((SAMPLES_PER_SINE*shiftfactor)/360)*PH_FRACT_FACT)) % (SAMPLES_PER_SINE*PH_FRACT_FACT);
1190                 //printf("shiftfactor = %i\n",shiftfactor);
1191                 //shiftfactor+=10;
1192         }
1193         else if(mySps->option==3)
1194         {
1195                 // stop it and clear the output buffer
1196                 mySps->option=0;
1197                 mySps->state=0;
1198                 mySps->enabled=0;
1199                 for(i=0;i<mySps->nSamples;i++)
1200                         mySps->sink[(i*numChanOut)+selChanOut]=0;
1201                 return(0);
1202         }
1203         else if(mySps->state==2)
1204         {
1205                 // doing turn off
1206                 mySps->discounterl-=MS_PER_FRAME;
1207                 if(mySps->discounterl<=0)
1208                 {
1209                         mySps->option=3;
1210                         mySps->state=2;
1211                 }
1212         }
1213         else if(mySps->state==0)
1214         {
1215                 return(0);
1216         }
1217
1218         ph=mySps->discounteru;
1219
1220         for(i=0;i<mySps->nSamples;i++)
1221         {
1222                 if(!waveform)
1223                 {
1224                         // sine
1225                         //tmp=(sinetablex[ph/PH_FRACT_FACT]*amplitude)/M_Q16;
1226                         accum=sinetablex[ph/PH_FRACT_FACT];
1227                         accum=(accum*outputgain)/M_Q8;
1228             }
1229                 else
1230                 {
1231                         // square
1232                         if(ph>SAMPLES_PER_SINE/2)
1233                                 accum=outputgain/M_Q8;
1234                         else
1235                                 accum=-outputgain/M_Q8;
1236                 }
1237
1238                 if(mySps->source)accum+=mySps->source[i];
1239
1240                 mySps->sink[(i*numChanOut)+selChanOut]=accum;
1241
1242                 ph=(ph+mySps->discfactor)%(SAMPLES_PER_SINE*PH_FRACT_FACT);
1243         }
1244
1245         mySps->discounteru=ph;
1246
1247         return 0;
1248 }
1249 /*
1250         adder/mixer
1251         takes existing buffer and adds source buffer to destination buffer
1252         sink buffer = (sink buffer * gain) + source buffer
1253 */
1254 i16 pmrMixer(t_pmr_sps *mySps)
1255 {
1256         i32 accum;
1257         i16 i, *input, *inputB, *output;
1258         i16  inputGain, inputGainB;             // apply to input data   in Q7.8 format
1259         i16  outputGain;        // apply to output data  in Q7.8 format
1260         i16      discounteru,discounterl,amax,amin,setpt,discfactor;
1261         i16      npoints,uhit,lhit,apeak,measPeak;
1262
1263         t_pmr_chan *pChan;
1264         pChan=mySps->parentChan;
1265         TRACEF(5,("pmrMixer()\n"));
1266
1267         input     = mySps->source;
1268         inputB    = mySps->sourceB;
1269         output    = mySps->sink;
1270
1271         inputGain=mySps->inputGain;
1272         inputGainB=mySps->inputGainB;
1273         outputGain=mySps->outputGain;
1274
1275         amax=mySps->amax;
1276         amin=mySps->amin;
1277         setpt=mySps->setpt;
1278         discounteru=mySps->discounteru;
1279         discounterl=mySps->discounteru;
1280
1281         discfactor=mySps->discfactor;
1282         npoints=mySps->nSamples;
1283         measPeak=mySps->measPeak;
1284
1285         for(i=0;i<npoints;i++)
1286         {
1287                 accum = ((input[i]*inputGain)/M_Q8) +
1288                                 ((inputB[i]*inputGainB)/M_Q8);
1289
1290                 accum=(accum*outputGain)/M_Q8;
1291                 output[i]=accum;
1292
1293                 if(measPeak){
1294                         lhit=uhit=0;
1295
1296                         if(accum>amax){
1297                                 amax=accum;
1298                                 uhit=1;
1299                                 if(amin<(amax-setpt)){
1300                                         amin=(amax-setpt);
1301                                         lhit=1;
1302                                 }
1303                         }
1304                         else if(accum<amin){
1305                                 amin=accum;
1306                                 lhit=1;
1307                                 if(amax>(amin+setpt)){
1308                                         amax=(amin+setpt);
1309                                         uhit=1;
1310                                 }
1311                         }
1312
1313                         if(--discounteru<=0 && amax>0){
1314                                 amax--;
1315                                 uhit=1;
1316                         }
1317
1318                         if(--discounterl<=0 && amin<0){
1319                                 amin++;
1320                                 lhit=1;
1321                         }
1322
1323                         if(uhit)discounteru=discfactor;
1324                         if(lhit)discounterl=discfactor;
1325                 }
1326         }
1327
1328         if(measPeak){
1329                 apeak = (amax-amin)/2;
1330                 mySps->apeak=apeak;
1331                 mySps->amax=amax;
1332                 mySps->amin=amin;
1333                 mySps->discounteru=discounteru;
1334                 mySps->discounterl=discounterl;
1335         }
1336
1337         return 0;
1338 }
1339 /*
1340         DelayLine
1341 */
1342 i16 DelayLine(t_pmr_sps *mySps)
1343 {
1344         i16 *input, *output, *buff;
1345         i16      i, npoints,buffsize,inindex,outindex;
1346
1347         t_pmr_chan *pChan;
1348         pChan=mySps->parentChan;
1349         TRACEF(5,(" DelayLine() %i\n",mySps->enabled));
1350
1351         input           = mySps->source;
1352         output          = mySps->sink;
1353         buff            = (i16*)(mySps->buff);
1354         buffsize        = mySps->buffSize;
1355         npoints         = mySps->nSamples;
1356
1357         outindex        = mySps->buffOutIndex;
1358         inindex         = outindex + mySps->buffLead;
1359
1360         for(i=0;i<npoints;i++)
1361         {
1362                 inindex %= buffsize;
1363                 outindex %= buffsize;
1364
1365                 buff[inindex]=input[i];
1366                 output[i]=buff[outindex];
1367                 inindex++;
1368                 outindex++;
1369         }
1370         mySps->buffOutIndex=outindex;
1371
1372         return 0;
1373 }
1374 /*
1375         Continuous Tone Coded Squelch (CTCSS) Detector
1376 */
1377 i16 ctcss_detect(t_pmr_chan *pChan)
1378 {
1379         i16 i,points2do,*pInput,hit,thit,relax;
1380         i16 tnum, tmp,indexNow,diffpeak;
1381         /* i16 difftrig; */
1382         i16 tv0,tv1,tv2,tv3,indexDebug;
1383         i16 points=0;
1384         i16 indexWas=0;
1385
1386         TRACEF(5,("ctcss_detect(%p) %i %i %i %i\n",pChan,
1387                 pChan->rxCtcss->enabled,
1388                 0,
1389                 pChan->rxCtcss->testIndex,
1390                 pChan->rxCtcss->decode));
1391
1392         if(!pChan->rxCtcss->enabled)return(1);
1393
1394         relax  = pChan->rxCtcss->relax;
1395         pInput = pChan->rxCtcss->input;
1396
1397         /*
1398         if(relax) difftrig=(-0.1*M_Q15);
1399         else difftrig=(-0.05*M_Q15);
1400         */
1401
1402         thit=hit=-1;
1403
1404         //TRACEX((" ctcss_detect() %i  %i  %i  %i\n", CTCSS_NUM_CODES,0,0,0));
1405
1406         for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++)
1407         {
1408                 i32 accum, peak;
1409                 t_tdet  *ptdet;
1410                 i16 fudgeFactor;
1411                 i16 binFactor;
1412
1413                 TRACEF(6,(" ctcss_detect() tnum=%i %i\n",tnum,pChan->rxCtcssMap[tnum]));
1414                 //if(tnum==14)printf("ctcss_detect() %i %i %i\n",tnum,pChan->rxCtcssMap[tnum], pChan->rxCtcss->decode );
1415
1416                 if( (pChan->rxCtcssMap[tnum]==CTCSS_NULL) ||
1417                     (pChan->rxCtcss->decode>CTCSS_NULL && (tnum!= pChan->rxCtcss->decode))
1418                   )
1419                         continue;
1420
1421                 TRACEF(6,(" ctcss_detect() tnum=%i\n",tnum));
1422
1423                 ptdet=&(pChan->rxCtcss->tdet[tnum]);
1424                 indexDebug=0;
1425                 points=points2do=pChan->nSamplesRx;
1426                 fudgeFactor=ptdet->fudgeFactor;
1427                 binFactor=ptdet->binFactor;
1428
1429                 while(ptdet->counter < (points2do*CTCSS_SCOUNT_MUL))
1430                 {
1431                         tmp=(ptdet->counter/CTCSS_SCOUNT_MUL)+1;
1432                     ptdet->counter-=(tmp*CTCSS_SCOUNT_MUL);
1433                         points2do-=tmp;
1434                         indexNow=points-points2do;
1435
1436                         ptdet->counter += ptdet->counterFactor;
1437
1438                         accum = pInput[indexNow-1];             // duuuude's major bug fix!
1439
1440                         ptdet->z[ptdet->zIndex]+=
1441                                 (((accum - ptdet->z[ptdet->zIndex])*binFactor)/M_Q15);
1442
1443                         peak = abs(ptdet->z[0]-ptdet->z[2]) + abs(ptdet->z[1]-ptdet->z[3]);
1444
1445                         if (ptdet->peak < peak)
1446                                 ptdet->peak += ( ((peak-ptdet->peak)*binFactor)/M_Q15);
1447                         else
1448                                 ptdet->peak=peak;
1449
1450                         {
1451                                 static const i16 a0=13723;
1452                                 static const i16 a1=-13723;
1453                                 i32 temp0,temp1;
1454                                 i16 x0;
1455
1456                                 //differentiate
1457                                 x0=ptdet->zd;
1458                                 temp0 = x0 * a1;
1459                                 ptdet->zd = ptdet->peak;
1460                                 temp1 = ptdet->peak * a0;
1461                             diffpeak = (temp0 + temp1)/1024;
1462                         }
1463
1464                         if(diffpeak<(-0.03*M_Q15))ptdet->dvd-=4;
1465                         else if(ptdet->dvd<0)ptdet->dvd++;
1466
1467                         if((ptdet->dvd < -12) && diffpeak > (-0.02*M_Q15))ptdet->dvu+=2;
1468                         else if(ptdet->dvu)ptdet->dvu--;
1469
1470                         tmp=ptdet->setpt;
1471                         if(pChan->rxCtcss->decode==tnum)
1472                         {
1473                                 if(relax)tmp=(tmp*55)/100;
1474                                 else tmp=(tmp*80)/100;
1475                         }
1476
1477                         if(ptdet->peak > tmp)
1478                         {
1479                             if(ptdet->decode<(fudgeFactor*32))ptdet->decode++;
1480                         }
1481                         else if(pChan->rxCtcss->decode==tnum)
1482                         {
1483                                 if(ptdet->peak > ptdet->hyst)ptdet->decode--;
1484                                 else if(relax) ptdet->decode--;
1485                                 else ptdet->decode-=4;
1486                         }
1487                         else
1488                         {
1489                                 ptdet->decode=0;
1490                         }
1491
1492                         if((pChan->rxCtcss->decode==tnum) && !relax && (ptdet->dvu > (0.00075*M_Q15)))
1493                         {
1494                                 ptdet->decode=0;
1495                                 ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=ptdet->dvu=0;
1496                                 TRACEF(4,("ctcss_detect() turnoff detected by dvdt for tnum = %i.\n",tnum));
1497                         }
1498
1499                         if(ptdet->decode<0 || !pChan->rxCarrierDetect)ptdet->decode=0;
1500
1501                         if(ptdet->decode>=fudgeFactor)
1502                         {
1503                                 thit=tnum;
1504                                 if(pChan->rxCtcss->decode!=tnum)
1505                                 {
1506                                         ptdet->zd=ptdet->dvu=ptdet->dvd=0;      
1507                                 }
1508                         }
1509
1510                         #if XPMR_DEBUG0 == 1
1511                         if(thit>=0 && thit==tnum)
1512                                 TRACEF(6,(" ctcss_detect() %i %i %i %i \n",tnum,ptdet->peak,ptdet->setpt,ptdet->hyst));
1513
1514                         if(ptdet->pDebug0)
1515                         {
1516                                 tv0=ptdet->peak;
1517                                 tv1=ptdet->decode;
1518                                 tv2=tmp;
1519                                 tv3=ptdet->dvu*32;
1520
1521                                 if(indexDebug==0)
1522                                 {
1523                                         ptdet->lasttv0=ptdet->pDebug0[points-1];
1524                                         ptdet->lasttv1=ptdet->pDebug1[points-1];
1525                                         ptdet->lasttv2=ptdet->pDebug2[points-1];
1526                                         ptdet->lasttv3=ptdet->pDebug3[points-1];
1527                                 }
1528
1529                                 while(indexDebug<indexNow)
1530                                 {
1531                                         ptdet->pDebug0[indexDebug]=ptdet->lasttv0;
1532                                         ptdet->pDebug1[indexDebug]=ptdet->lasttv1;
1533                                         ptdet->pDebug2[indexDebug]=ptdet->lasttv2;
1534                                         ptdet->pDebug3[indexDebug]=ptdet->lasttv3;
1535                                         indexDebug++;
1536                                 }
1537                                 ptdet->lasttv0=tv0;
1538                                 ptdet->lasttv1=tv1;
1539                                 ptdet->lasttv2=tv2;
1540                                 ptdet->lasttv3=tv3;
1541                         }
1542                         #endif
1543                         indexWas=indexNow;
1544                         ptdet->zIndex=(ptdet->zIndex + 1) % 4;
1545                 }
1546                 ptdet->counter-=(points2do*CTCSS_SCOUNT_MUL);
1547
1548                 #if XPMR_DEBUG0 == 1
1549                 for(i=indexWas;i<points;i++)
1550                 {
1551                         ptdet->pDebug0[i]=ptdet->lasttv0;
1552                         ptdet->pDebug1[i]=ptdet->lasttv1;
1553                         ptdet->pDebug2[i]=ptdet->lasttv2;
1554                         ptdet->pDebug3[i]=ptdet->lasttv3;
1555                 }
1556                 #endif
1557         }
1558
1559         //TRACEX((" ctcss_detect() thit %i\n",thit));
1560
1561         if(pChan->rxCtcss->BlankingTimer>0)pChan->rxCtcss->BlankingTimer-=points;
1562         if(pChan->rxCtcss->BlankingTimer<0)pChan->rxCtcss->BlankingTimer=0;
1563
1564     if(thit>CTCSS_NULL && pChan->rxCtcss->decode<=CTCSS_NULL && !pChan->rxCtcss->BlankingTimer)
1565     {
1566                 pChan->rxCtcss->decode=thit;
1567                 sprintf(pChan->rxctcssfreq,"%.1f",freq_ctcss[thit]);
1568                 TRACEC(1,("ctcss decode  %i  %.1f\n",thit,freq_ctcss[thit]));
1569         }
1570         else if(thit<=CTCSS_NULL && pChan->rxCtcss->decode>CTCSS_NULL)
1571         {
1572                 pChan->rxCtcss->BlankingTimer=SAMPLE_RATE_NETWORK/5;
1573                 pChan->rxCtcss->decode=CTCSS_NULL;
1574                 strcpy(pChan->rxctcssfreq,"0");
1575                 TRACEC(1,("ctcss decode  NULL\n"));
1576                 for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++)
1577                 {
1578                     t_tdet      *ptdet=NULL;
1579                         ptdet=&(pChan->rxCtcss->tdet[tnum]);
1580                     ptdet->decode=0;
1581                         ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=0;
1582                 }
1583         }
1584         //TRACEX((" ctcss_detect() thit %i %i\n",thit,pChan->rxCtcss->decode));
1585         return(0);
1586 }
1587 /*
1588         TxTestTone
1589 */
1590 static i16      TxTestTone(t_pmr_chan *pChan, i16 function)
1591 {
1592         if(function==1)
1593         {
1594                 pChan->spsSigGen1->enabled=1;
1595                 pChan->spsSigGen1->option=1;
1596                 pChan->spsSigGen1->outputGain=(.23125*M_Q8);   // to match *99 level
1597                 pChan->spsTx->source=pChan->spsSigGen1->sink;
1598         }
1599         else
1600         {
1601                 pChan->spsSigGen1->option=3;
1602         }
1603         return 0;
1604 }
1605 /*
1606         assumes:
1607         sampling rate is 48KS/s
1608         samples are all 16 bits
1609     samples are filtered and decimated by 1/6th
1610 */
1611 t_pmr_chan      *createPmrChannel(t_pmr_chan *tChan, i16 numSamples)
1612 {
1613         i16 i, *inputTmp;
1614         t_pmr_chan      *pChan;
1615         t_pmr_sps       *pSps;
1616         t_dec_ctcss     *pDecCtcss;
1617
1618         TRACEJ(1,("createPmrChannel(%p,%i)\n",tChan,numSamples));
1619
1620         pChan = (t_pmr_chan *)calloc(sizeof(t_pmr_chan),1);
1621         if(pChan==NULL)
1622         {
1623                 printf("createPmrChannel() failed\n");
1624                 return(NULL);
1625         }
1626
1627         #if XPMR_PPTP == 1
1628         pptp_init();
1629         #endif
1630
1631         pChan->index=pmrChanIndex++;
1632         pChan->nSamplesTx=pChan->nSamplesRx=numSamples;
1633
1634         pDecCtcss = (t_dec_ctcss *)calloc(sizeof(t_dec_ctcss),1);
1635         pChan->rxCtcss=pDecCtcss;
1636         pChan->rxctcssfreq[0]=0;
1637
1638         #ifdef HAVE_XPMRX
1639         if(tChan->rptnum>=LSD_CHAN_MAX)tChan->rptnum=0;
1640         #endif
1641
1642         if(tChan==NULL)
1643         {
1644                 printf("createPmrChannel() WARNING: NULL tChan!\n");
1645                 pChan->rxNoiseSquelchEnable=0;
1646                 pChan->rxHpfEnable=0;
1647                 pChan->rxDeEmpEnable=0;
1648                 pChan->rxCenterSlicerEnable=0;
1649                 pChan->rxCtcssDecodeEnable=0;
1650                 pChan->rxDcsDecodeEnable=0;
1651
1652                 pChan->rxCarrierPoint = 17000;
1653                 pChan->rxCarrierHyst = 2500;
1654
1655                 pChan->txHpfEnable=0;
1656                 pChan->txLimiterEnable=0;
1657                 pChan->txPreEmpEnable=0;
1658                 pChan->txLpfEnable=1;
1659                 pChan->txMixA=TX_OUT_VOICE;
1660                 pChan->txMixB=TX_OUT_LSD;
1661         }
1662         else
1663         {
1664                 pChan->rxDemod=tChan->rxDemod;
1665                 pChan->rxCdType=tChan->rxCdType;
1666                 pChan->rxSquelchPoint = tChan->rxSquelchPoint;
1667                 pChan->rxCarrierHyst = 3000;
1668                 pChan->rxSqVoxAdj=tChan->rxSqVoxAdj;
1669
1670                 pChan->txMod=tChan->txMod;
1671                 pChan->txHpfEnable=1;
1672                 pChan->txLpfEnable=1;
1673
1674                 pChan->pTxCodeDefault=tChan->pTxCodeDefault;
1675                 pChan->pRxCodeSrc=tChan->pRxCodeSrc;
1676                 pChan->pTxCodeSrc=tChan->pTxCodeSrc;
1677
1678                 pChan->txMixA=tChan->txMixA;
1679                 pChan->txMixB=tChan->txMixB;
1680                 pChan->radioDuplex=tChan->radioDuplex;
1681                 pChan->area=tChan->area;
1682                 pChan->rptnum=tChan->rptnum;
1683                 pChan->idleinterval=tChan->idleinterval;
1684                 pChan->turnoffs=tChan->turnoffs;
1685                 pChan->b.rxpolarity=tChan->b.rxpolarity;
1686                 pChan->b.txpolarity=tChan->b.txpolarity;
1687                 pChan->b.dcsrxpolarity=tChan->b.dcsrxpolarity;
1688                 pChan->b.dcstxpolarity=tChan->b.dcstxpolarity;
1689                 pChan->b.lsdrxpolarity=tChan->b.lsdrxpolarity;
1690                 pChan->b.lsdtxpolarity=tChan->b.lsdtxpolarity;
1691
1692                 pChan->txsettletime=tChan->txsettletime;
1693                 pChan->tracelevel=tChan->tracelevel;
1694                 pChan->tracetype=tChan->tracetype;
1695                 pChan->ukey=tChan->ukey;
1696                 pChan->name=tChan->name;
1697         }
1698
1699
1700         pChan->txHpfEnable=1;
1701         pChan->txLpfEnable=1;
1702
1703         if(pChan->rxCdType==CD_XPMR_NOISE) pChan->rxNoiseSquelchEnable=1;
1704
1705         if(pChan->rxDemod==RX_AUDIO_FLAT) pChan->rxDeEmpEnable=1;
1706
1707         pChan->rxCarrierPoint=(pChan->rxSquelchPoint*32767)/100;
1708         pChan->rxCarrierHyst = 3000; //pChan->rxCarrierPoint/15;
1709
1710         pChan->rxDcsDecodeEnable=0;
1711
1712         if(pChan->b.ctcssRxEnable || pChan->b.dcsRxEnable || pChan->b.lmrRxEnable)
1713         {
1714                 pChan->rxHpfEnable=1;
1715                 pChan->rxCenterSlicerEnable=1;
1716                 pChan->rxCtcssDecodeEnable=1;
1717         }
1718
1719         if(pChan->txMod){
1720                 pChan->txPreEmpEnable=1;
1721                 pChan->txLimiterEnable=1;
1722         }
1723
1724         pChan->dd.option=9;
1725         dedrift(pChan);
1726
1727         TRACEF(1,("calloc buffers \n"));
1728
1729         pChan->pRxDemod         = calloc(numSamples,2);
1730         pChan->pRxNoise         = calloc(numSamples,2);
1731         pChan->pRxBase          = calloc(numSamples,2);
1732         pChan->pRxHpf           = calloc(numSamples,2);
1733         pChan->pRxLsd           = calloc(numSamples,2);
1734         pChan->pRxSpeaker       = calloc(numSamples,2);
1735         pChan->pRxCtcss         = calloc(numSamples,2);
1736         pChan->pRxDcTrack       = calloc(numSamples,2);
1737         pChan->pRxLsdLimit      = calloc(numSamples,2);
1738
1739         pChan->pTxInput         = calloc(numSamples,2);
1740         pChan->pTxBase          = calloc(numSamples,2);
1741         pChan->pTxHpf           = calloc(numSamples,2);
1742         pChan->pTxPreEmp        = calloc(numSamples,2);
1743         pChan->pTxLimiter       = calloc(numSamples,2);
1744         pChan->pTxLsd           = calloc(numSamples,2);
1745         pChan->pTxLsdLpf    = calloc(numSamples,2);
1746         pChan->pTxComposite     = calloc(numSamples,2);
1747         pChan->pSigGen0         = calloc(numSamples,2);
1748     pChan->pSigGen1             = calloc(numSamples,2);
1749                 
1750         pChan->prxMeasure       = calloc(numSamples,2);
1751
1752         pChan->pTxOut           = calloc(numSamples,2*2*6);             // output buffer
1753     
1754 #ifdef HAVE_XPMRX
1755         pChan->pLsdEnc          = calloc(sizeof(t_encLsd),1);
1756 #endif
1757
1758         #if XPMR_DEBUG0 == 1
1759         TRACEF(1,("configure tracing\n"));
1760
1761         pChan->pTstTxOut        = calloc(numSamples,2);
1762         pChan->pRxLsdCen    = calloc(numSamples,2);
1763         pChan->prxDebug0        = calloc(numSamples,2);
1764         pChan->prxDebug1        = calloc(numSamples,2);
1765         pChan->prxDebug2        = calloc(numSamples,2);
1766         pChan->prxDebug3        = calloc(numSamples,2);
1767         pChan->ptxDebug0        = calloc(numSamples,2);
1768         pChan->ptxDebug1        = calloc(numSamples,2);
1769         pChan->ptxDebug2        = calloc(numSamples,2);
1770         pChan->ptxDebug3        = calloc(numSamples,2);
1771         pChan->pNull            = calloc(numSamples,2);
1772
1773         for(i=0;i<numSamples;i++)pChan->pNull[i]=((i%(numSamples/2))*8000)-4000;
1774
1775         pChan->rxCtcss->pDebug0=calloc(numSamples,2);
1776         pChan->rxCtcss->pDebug1=calloc(numSamples,2);
1777         pChan->rxCtcss->pDebug2=calloc(numSamples,2);
1778         pChan->rxCtcss->pDebug3=calloc(numSamples,2);
1779
1780         for(i=0;i<CTCSS_NUM_CODES;i++)
1781         {
1782                 pChan->rxCtcss->tdet[i].pDebug0=calloc(numSamples,2);
1783                 pChan->rxCtcss->tdet[i].pDebug1=calloc(numSamples,2);
1784                 pChan->rxCtcss->tdet[i].pDebug2=calloc(numSamples,2);
1785                 pChan->rxCtcss->tdet[i].pDebug3=calloc(numSamples,2);
1786         }
1787
1788         // buffer, 2 bytes per sample, and 16 channels
1789         pChan->prxDebug=calloc(numSamples*16,2);
1790         pChan->ptxDebug=calloc(numSamples*16,2);
1791
1792         // TSCOPE CONFIGURATION SETSCOPE configure debug traces and sources for each channel of the output
1793         pChan->sdbg                     = (t_sdbg *)calloc(sizeof(t_sdbg),1);
1794
1795         for(i=0;i<XPMR_DEBUG_CHANS;i++)pChan->sdbg->trace[i]=-1;        
1796
1797         TRACEF(1,("pChan->tracetype = %i\n",pChan->tracetype));
1798
1799         if(pChan->tracetype==1)                                                 // CTCSS DECODE
1800         {
1801                 pChan->sdbg->source [0]=pChan->pRxDemod;
1802                 pChan->sdbg->source [1]=pChan->pRxBase;
1803                 pChan->sdbg->source [2]=pChan->pRxNoise;
1804                 pChan->sdbg->trace  [3]=RX_NOISE_TRIG;
1805                 pChan->sdbg->source [4]=pChan->pRxLsd;
1806                 pChan->sdbg->source [5]=pChan->pRxLsdCen;
1807                 pChan->sdbg->source [6]=pChan->pRxLsdLimit;
1808                 pChan->sdbg->source [7]=pChan->rxCtcss->tdet[3].pDebug0;
1809                 pChan->sdbg->trace  [8]=RX_CTCSS_DECODE;
1810                 pChan->sdbg->trace  [9]=RX_SMODE;
1811         }
1812         if(pChan->tracetype==2)                                                 // CTCSS DECODE
1813         {
1814                 pChan->sdbg->source [0]=pChan->pRxDemod;
1815                 pChan->sdbg->source [1]=pChan->pRxBase;
1816                 pChan->sdbg->trace  [2]=RX_NOISE_TRIG;
1817                 pChan->sdbg->source [3]=pChan->pRxLsd;
1818                 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1819                 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1820                 pChan->sdbg->source [6]=pChan->pRxLsdLimit;
1821                 pChan->sdbg->source [7]=pChan->rxCtcss->tdet[3].pDebug0;
1822                 pChan->sdbg->source [8]=pChan->rxCtcss->tdet[3].pDebug1;
1823                 pChan->sdbg->source [9]=pChan->rxCtcss->tdet[3].pDebug2;
1824                 pChan->sdbg->source [10]=pChan->rxCtcss->tdet[3].pDebug3;
1825                 pChan->sdbg->trace  [11]=RX_CTCSS_DECODE;
1826                 pChan->sdbg->trace  [12]=RX_SMODE;
1827                 pChan->sdbg->trace  [13]=TX_PTT_IN;
1828                 pChan->sdbg->trace  [14]=TX_PTT_OUT;
1829                 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1830         }
1831         else if(pChan->tracetype==3)                                    // DCS DECODE
1832         {
1833                 pChan->sdbg->source [0]=pChan->pRxDemod;
1834                 pChan->sdbg->source [1]=pChan->pRxBase;
1835                 pChan->sdbg->trace  [2]=RX_NOISE_TRIG;
1836                 pChan->sdbg->source [3]=pChan->pRxLsd;
1837                 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1838                 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1839                 pChan->sdbg->trace  [6]=RX_DCS_CLK;
1840                 pChan->sdbg->trace  [7]=RX_DCS_DIN;
1841                 pChan->sdbg->trace  [8]=RX_DCS_DEC;
1842                 pChan->sdbg->trace  [9]=RX_SMODE;
1843                 pChan->sdbg->trace  [10]=TX_PTT_IN;
1844                 pChan->sdbg->trace  [11]=TX_PTT_OUT;
1845                 pChan->sdbg->trace  [12]=TX_LSD_CLK;
1846                 pChan->sdbg->trace  [13]=TX_LSD_DAT;
1847                 pChan->sdbg->trace  [14]=TX_LSD_GEN;
1848                 pChan->sdbg->source [14]=pChan->pTxLsd;
1849                 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1850         }
1851         else if(pChan->tracetype==4)                                    // LSD DECODE
1852         {
1853                 pChan->sdbg->source [0]=pChan->pRxDemod;
1854                 pChan->sdbg->source [1]=pChan->pRxBase;
1855                 pChan->sdbg->trace  [2]=RX_NOISE_TRIG;
1856                 pChan->sdbg->source [3]=pChan->pRxLsd;
1857                 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1858                 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1859                 pChan->sdbg->trace  [6]=RX_LSD_CLK;
1860                 pChan->sdbg->trace  [7]=RX_LSD_DAT;
1861                 pChan->sdbg->trace  [8]=RX_LSD_ERR;
1862                 pChan->sdbg->trace  [9]=RX_LSD_SYNC;
1863                 pChan->sdbg->trace  [10]=RX_SMODE;
1864                 pChan->sdbg->trace  [11]=TX_PTT_IN;
1865                 pChan->sdbg->trace  [12]=TX_PTT_OUT;
1866                 pChan->sdbg->trace  [13]=TX_LSD_CLK;
1867                 pChan->sdbg->trace  [14]=TX_LSD_DAT;
1868                 //pChan->sdbg->trace  [14]=TX_LSD_GEN;
1869                 //pChan->sdbg->source [14]=pChan->pTxLsd;
1870                 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1871         }
1872         else if(pChan->tracetype==5)                                            // LSD LOGIC
1873         {
1874                 pChan->sdbg->source [0]=pChan->pRxBase;
1875                 pChan->sdbg->trace  [1]=RX_NOISE_TRIG;
1876                 pChan->sdbg->source [2]=pChan->pRxDcTrack;
1877                 pChan->sdbg->trace  [3]=RX_LSD_SYNC;
1878                 pChan->sdbg->trace  [4]=RX_SMODE;
1879                 pChan->sdbg->trace  [5]=TX_PTT_IN;
1880                 pChan->sdbg->trace  [6]=TX_PTT_OUT;
1881                 pChan->sdbg->source [7]=pChan->pTxLsdLpf;
1882         }
1883         else if(pChan->tracetype==6)
1884         {
1885                 // tx clock skew and jitter buffer
1886                 pChan->sdbg->source [0]=pChan->pRxDemod;
1887                 pChan->sdbg->source  [5]=pChan->pTxBase;
1888                 pChan->sdbg->trace   [6]=TX_DEDRIFT_LEAD;
1889                 pChan->sdbg->trace   [7]=TX_DEDRIFT_ERR;
1890                 pChan->sdbg->trace   [8]=TX_DEDRIFT_FACTOR;
1891                 pChan->sdbg->trace   [9]=TX_DEDRIFT_DRIFT;
1892         }
1893         else if(pChan->tracetype==7)
1894         {
1895                 // tx path
1896                 pChan->sdbg->source [0]=pChan->pRxBase;
1897                 pChan->sdbg->trace  [1]=RX_NOISE_TRIG;
1898                 pChan->sdbg->source [2]=pChan->pRxLsd;
1899                 pChan->sdbg->trace  [3]=RX_CTCSS_DECODE;
1900                 pChan->sdbg->source [4]=pChan->pRxHpf;
1901
1902                 pChan->sdbg->trace  [5]=TX_PTT_IN;
1903                 pChan->sdbg->trace  [6]=TX_PTT_OUT;
1904
1905                 pChan->sdbg->source [7]=pChan->pTxBase;
1906                 pChan->sdbg->source [8]=pChan->pTxHpf;
1907                 pChan->sdbg->source [9]=pChan->pTxPreEmp;
1908                 pChan->sdbg->source [10]=pChan->pTxLimiter;
1909                 pChan->sdbg->source [11]=pChan->pTxComposite;
1910                 pChan->sdbg->source [12]=pChan->pTxLsdLpf;
1911         }
1912
1913         for(i=0;i<XPMR_DEBUG_CHANS;i++){
1914                 if(pChan->sdbg->trace[i]>=0)pChan->sdbg->point[pChan->sdbg->trace[i]]=i;        
1915         }
1916         pChan->sdbg->mode=1;
1917         #endif
1918
1919         #ifdef XPMRX_H
1920         // LSD GENERATOR
1921         pSps=pChan->spsLsdGen=createPmrSps(pChan);
1922         pSps->source=NULL;
1923         pSps->sink=pChan->pTxLsd;
1924         pSps->numChanOut=1;
1925         pSps->selChanOut=0;
1926         pSps->sigProc=LsdGen;
1927         pSps->nSamples=pChan->nSamplesTx;
1928         pSps->outputGain=(.25*M_Q8);
1929         pSps->option=0;
1930         pSps->interpolate=1;
1931         pSps->decimate=1;
1932         pSps->enabled=0;
1933         #endif
1934
1935         // General Purpose Function Generator
1936         pSps=pChan->spsSigGen1=createPmrSps(pChan);
1937         pSps->sink=pChan->pSigGen1;
1938         pSps->numChanOut=1;
1939         pSps->selChanOut=0;
1940         pSps->sigProc=SigGen;
1941         pSps->nSamples=pChan->nSamplesTx;
1942         pSps->sampleRate=SAMPLE_RATE_NETWORK;
1943         pSps->freq=10000;                                               // in increments of 0.1 Hz
1944         pSps->outputGain=(.25*M_Q8);
1945         pSps->option=0;
1946         pSps->interpolate=1;
1947         pSps->decimate=1;
1948         pSps->enabled=0;
1949
1950
1951         // CTCSS ENCODER
1952         pSps = pChan->spsSigGen0 = createPmrSps(pChan);
1953         pSps->sink=pChan->pTxLsd;
1954         pSps->sigProc=SigGen;
1955         pSps->numChanOut=1;
1956         pSps->selChanOut=0;
1957         pSps->nSamples=pChan->nSamplesTx;
1958         pSps->sampleRate=SAMPLE_RATE_NETWORK;
1959         pSps->freq=1000;                                                // in 0.1 Hz steps
1960         pSps->outputGain=(0.5*M_Q8);
1961         pSps->option=0;
1962         pSps->interpolate=1;
1963         pSps->decimate=1;
1964         pSps->enabled=0;
1965
1966         // Tx LSD Low Pass Filter
1967         pSps=pChan->spsTxLsdLpf=createPmrSps(pChan);
1968         pSps->source=pChan->pTxLsd;
1969         pSps->sink=pChan->pTxLsdLpf;
1970         pSps->sigProc=pmr_gp_fir;
1971         pSps->enabled=0;
1972         pSps->numChanOut=1;
1973         pSps->selChanOut=0;
1974         pSps->nSamples=pChan->nSamplesTx;
1975         pSps->decimator=pSps->decimate=1;
1976         pSps->interpolate=1;
1977         pSps->inputGain=(1*M_Q8);
1978         pSps->outputGain=(1*M_Q8);
1979          
1980         // configure the longer, lower cutoff filter by default
1981         pSps->ncoef=taps_fir_lpf_215_9_88;
1982         pSps->size_coef=2;
1983         pSps->coef=(void*)coef_fir_lpf_215_9_88;
1984         pSps->nx=taps_fir_lpf_215_9_88;
1985         pSps->size_x=2;
1986         pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
1987         pSps->calcAdjust=gain_fir_lpf_215_9_88;
1988
1989         pSps->inputGain=(1*M_Q8);
1990         pSps->outputGain=(1*M_Q8);
1991
1992         TRACEF(1,("spsTxLsdLpf = sps \n"));
1993
1994         if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
1995
1996
1997         // RX Process
1998         TRACEF(1,("create rx\n"));
1999         pSps = NULL;
2000
2001         // allocate space for first sps and set pointers
2002         pSps=pChan->spsRx=createPmrSps(pChan);
2003         pSps->source=NULL;                                      //set when called
2004         pSps->sink=pChan->pRxBase;
2005         pSps->sigProc=pmr_rx_frontend;
2006         pSps->enabled=1;
2007         pSps->decimator=pSps->decimate=6;
2008         pSps->interpolate=1;
2009         pSps->nSamples=pChan->nSamplesRx;
2010         pSps->ncoef=taps_fir_bpf_noise_1;
2011         pSps->size_coef=2;
2012         pSps->coef=(void*)coef_fir_lpf_3K_1;
2013         pSps->coef2=(void*)coef_fir_bpf_noise_1;
2014         pSps->nx=taps_fir_bpf_noise_1;
2015         pSps->size_x=2;
2016         pSps->x=(void*)(calloc(pSps->nx,pSps->size_coef));
2017         pSps->calcAdjust=(gain_fir_lpf_3K_1*256)/0x0100;
2018         pSps->outputGain=(1.0*M_Q8);
2019         pSps->discfactor=2;
2020         pSps->hyst=pChan->rxCarrierHyst;
2021         pSps->setpt=pChan->rxCarrierPoint;
2022         pChan->prxSquelchAdjust=&pSps->setpt;
2023         #if XPMR_DEBUG0 == 1
2024         pSps->debugBuff0=pChan->pRxDemod;
2025         pSps->debugBuff1=pChan->pRxNoise;
2026         pSps->debugBuff2=pChan->prxDebug0;
2027         #endif
2028
2029
2030         // allocate space for next sps and set pointers
2031         // Rx SubAudible Decoder Low Pass Filter
2032         pSps=pChan->spsRxLsd=pSps->nextSps=createPmrSps(pChan);
2033         pSps->source=pChan->pRxBase;
2034         pSps->sink=pChan->pRxLsd;
2035         pSps->sigProc=pmr_gp_fir;
2036         pSps->enabled=1;
2037         pSps->numChanOut=1;
2038         pSps->selChanOut=0;
2039         pSps->nSamples=pChan->nSamplesRx;
2040         pSps->decimator=pSps->decimate=1;
2041         pSps->interpolate=1;
2042
2043         // configure the the larger, lower cutoff filter by default
2044         pSps->ncoef=taps_fir_lpf_215_9_88;
2045         pSps->size_coef=2;
2046         pSps->coef=(void*)coef_fir_lpf_215_9_88;
2047         pSps->nx=taps_fir_lpf_215_9_88;
2048         pSps->size_x=2;
2049         pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2050         pSps->calcAdjust=gain_fir_lpf_215_9_88;
2051
2052         pSps->inputGain=(1*M_Q8);
2053         pSps->outputGain=(1*M_Q8);
2054         pChan->prxCtcssMeasure=pSps->sink;
2055         pChan->prxCtcssAdjust=&(pSps->outputGain);
2056
2057         // CTCSS CenterSlicer
2058         pSps=pChan->spsRxLsdNrz=pSps->nextSps=createPmrSps(pChan);
2059         pSps->source=pChan->pRxLsd;
2060         pSps->sink=pChan->pRxDcTrack;
2061         pSps->buff=pChan->pRxLsdLimit;
2062         pSps->sigProc=CenterSlicer;
2063         pSps->nSamples=pChan->nSamplesRx;
2064         pSps->discfactor=LSD_DFS;                               // centering time constant
2065         pSps->inputGain=(1*M_Q8);
2066         pSps->outputGain=(1*M_Q8);
2067         pSps->setpt=4900;                               // ptp clamp for DC centering
2068         pSps->inputGainB=625;                   // peak output limiter clip point
2069         pSps->enabled=0;
2070
2071
2072         // Rx HPF
2073         pSps=pSps->nextSps=createPmrSps(pChan);
2074         pChan->spsRxHpf=pSps;
2075         pSps->source=pChan->pRxBase;
2076         pSps->sink=pChan->pRxHpf;
2077         pSps->sigProc=pmr_gp_fir;
2078         pSps->enabled=1;
2079         pSps->numChanOut=1;
2080         pSps->selChanOut=0;
2081         pSps->nSamples=pChan->nSamplesRx;
2082         pSps->decimator=pSps->decimate=1;
2083         pSps->interpolate=1;
2084         pSps->ncoef=taps_fir_hpf_300_9_66;
2085         pSps->size_coef=2;
2086         pSps->coef=(void*)coef_fir_hpf_300_9_66;
2087         pSps->nx=taps_fir_hpf_300_9_66;
2088         pSps->size_x=2;
2089         pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2090         if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2091         pSps->calcAdjust=gain_fir_hpf_300_9_66;
2092         pSps->inputGain=(1*M_Q8);
2093         pSps->outputGain=(1*M_Q8);
2094         pChan->prxVoiceAdjust=&(pSps->outputGain);
2095         pChan->spsRxOut=pSps;
2096
2097         // allocate space for next sps and set pointers
2098         // Rx DeEmp
2099         if(pChan->rxDeEmpEnable){
2100                 pSps=pSps->nextSps=createPmrSps(pChan);
2101                 pChan->spsRxDeEmp=pSps;
2102                 pSps->source=pChan->pRxHpf;
2103                 pSps->sink=pChan->pRxSpeaker;
2104                 pChan->spsRxOut=pSps;                                    // OUTPUT STRUCTURE!
2105                 pSps->sigProc=gp_inte_00;
2106                 pSps->enabled=1;
2107                 pSps->nSamples=pChan->nSamplesRx;
2108
2109                 pSps->ncoef=taps_int_lpf_300_1_2;
2110                 pSps->size_coef=2;
2111                 pSps->coef=(void*)coef_int_lpf_300_1_2;
2112
2113                 pSps->nx=taps_int_lpf_300_1_2;
2114                 pSps->size_x=4;
2115                 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2116                 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2117                 pSps->calcAdjust=gain_int_lpf_300_1_2/2;
2118                 pSps->inputGain=(1.0*M_Q8);
2119                 pSps->outputGain=(1.0*M_Q8);
2120                 pChan->prxVoiceMeasure=pSps->sink;
2121                 pChan->prxVoiceAdjust=&(pSps->outputGain);
2122         }
2123
2124         if(pChan->rxDelayLineEnable)
2125         {
2126                 TRACEF(1,("create delayline\n"));
2127                 pSps=pChan->spsDelayLine=pSps->nextSps=createPmrSps(pChan);
2128                 pSps->sigProc=DelayLine;
2129                 pSps->source=pChan->pRxSpeaker;
2130                 pSps->sink=pChan->pRxSpeaker;
2131                 pSps->enabled=0;
2132                 pSps->inputGain=1*M_Q8;
2133                 pSps->outputGain=1*M_Q8;
2134                 pSps->nSamples=pChan->nSamplesRx;
2135                 pSps->buffSize=4096;
2136                 pSps->buff=calloc(4096,2);                      // one second maximum
2137                 pSps->buffLead = (SAMPLE_RATE_NETWORK*0.100);
2138                 pSps->buffOutIndex=0;
2139         }
2140
2141         if(pChan->rxCdType==CD_XPMR_VOX)
2142         {
2143                 TRACEF(1,("create vox measureblock\n"));
2144                 pChan->prxVoxMeas=calloc(pChan->nSamplesRx,2);
2145
2146                 pSps=pChan->spsRxVox=pSps->nextSps=createPmrSps(pChan);
2147                 pSps->sigProc=MeasureBlock;
2148                 pSps->parentChan=pChan;
2149                 pSps->source=pChan->pRxBase;
2150                 pSps->sink=pChan->prxVoxMeas;
2151                 pSps->inputGain=1*M_Q8;
2152                 pSps->outputGain=1*M_Q8;
2153                 pSps->nSamples=pChan->nSamplesRx;
2154                 pSps->discfactor=3;
2155                 if(pChan->rxSqVoxAdj==0)
2156                         pSps->setpt=(0.011*M_Q15);
2157                 else
2158                         pSps->setpt=(pChan->rxSqVoxAdj);
2159                 pSps->hyst=(pSps->setpt/10);
2160                 pSps->enabled=1;
2161         }
2162
2163         // tuning measure block
2164         pSps=pChan->spsMeasure=pSps->nextSps=createPmrSps(pChan);
2165         pSps->source=pChan->spsRx->sink;
2166         pSps->sink=pChan->prxMeasure;
2167         pSps->sigProc=MeasureBlock;
2168         pSps->enabled=0;
2169         pSps->nSamples=pChan->nSamplesRx;
2170         pSps->discfactor=10;
2171
2172         pSps->nextSps=NULL;             // last sps in chain RX
2173
2174
2175         // CREATE TRANSMIT CHAIN
2176         TRACEF(1,("create tx\n"));
2177         inputTmp=NULL;
2178         pSps = NULL;
2179
2180         // allocate space for first sps and set pointers
2181
2182         // Tx HPF SubAudible
2183         if(pChan->txHpfEnable)
2184         {
2185                 pSps=createPmrSps(pChan);
2186                 pChan->spsTx=pSps;
2187                 pSps->source=pChan->pTxBase;
2188                 pSps->sink=pChan->pTxHpf;
2189                 pSps->sigProc=pmr_gp_fir;
2190                 pSps->enabled=1;
2191                 pSps->numChanOut=1;
2192                 pSps->selChanOut=0;
2193                 pSps->nSamples=pChan->nSamplesTx;
2194                 pSps->decimator=pSps->decimate=1;
2195                 pSps->interpolate=1;
2196                 pSps->ncoef=taps_fir_hpf_300_9_66;
2197                 pSps->size_coef=2;
2198                 pSps->coef=(void*)coef_fir_hpf_300_9_66;
2199                 pSps->nx=taps_fir_hpf_300_9_66;
2200                 pSps->size_x=2;
2201                 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2202                 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2203                 pSps->calcAdjust=gain_fir_hpf_300_9_66;
2204                 pSps->inputGain=(1*M_Q8);
2205                 pSps->outputGain=(1*M_Q8);
2206                 inputTmp=pChan->pTxHpf;
2207         }
2208
2209         // Tx PreEmphasis
2210         if(pChan->txPreEmpEnable)
2211         {
2212                 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2213                 else pSps=pSps->nextSps=createPmrSps(pChan);
2214
2215                 pSps->source=inputTmp;
2216                 pSps->sink=pChan->pTxPreEmp;
2217
2218                 pSps->sigProc=gp_diff;
2219                 pSps->enabled=1;
2220                 pSps->nSamples=pChan->nSamplesTx;
2221
2222                 pSps->ncoef=taps_int_hpf_4000_1_2;
2223                 pSps->size_coef=2;
2224                 pSps->coef=(void*)coef_int_hpf_4000_1_2;
2225
2226                 pSps->nx=taps_int_hpf_4000_1_2;
2227                 pSps->size_x=2;
2228                 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2229                 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2230                  
2231                 pSps->calcAdjust=gain_int_hpf_4000_1_2;
2232                 pSps->inputGain=(1*M_Q8);
2233                 pSps->outputGain=(1*M_Q8);       // to match flat at 1KHz
2234                 inputTmp=pSps->sink;
2235         }
2236
2237         // Tx Limiter
2238         if(pChan->txLimiterEnable)
2239         {
2240                 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2241                 else pSps=pSps->nextSps=createPmrSps(pChan);
2242                 pSps->source=inputTmp;
2243                 pSps->sink=pChan->pTxLimiter;
2244                 pSps->sigProc=SoftLimiter;
2245                 pSps->enabled=1;
2246                 pSps->nSamples=pChan->nSamplesTx;
2247                 pSps->inputGain=(1*M_Q8);
2248                 pSps->outputGain=(1*M_Q8);
2249                 pSps->setpt=12000;
2250                 inputTmp=pSps->sink;
2251         }
2252
2253         // Composite Mix of Voice and LSD
2254         if((pChan->txMixA==TX_OUT_COMPOSITE)||(pChan->txMixB==TX_OUT_COMPOSITE))
2255         {
2256                 if(pSps==NULL)
2257                         pSps=pChan->spsTx=createPmrSps(pChan);
2258                 else
2259                         pSps=pSps->nextSps=createPmrSps(pChan);
2260                 pSps->source=inputTmp;
2261                 pSps->sourceB=pChan->pTxLsdLpf;          //asdf ??? !!! maw pTxLsdLpf
2262                 pSps->sink=pChan->pTxComposite;
2263                 pSps->sigProc=pmrMixer;
2264                 pSps->enabled=1;
2265                 pSps->nSamples=pChan->nSamplesTx;
2266                 pSps->inputGain=2*M_Q8;
2267                 pSps->inputGainB=1*M_Q8/8;
2268                 pSps->outputGain=1*M_Q8;
2269                 pSps->setpt=0;
2270                 inputTmp=pSps->sink;
2271                 pChan->ptxCtcssAdjust=&pSps->inputGainB;
2272         }
2273
2274         // Chan A Upsampler and Filter
2275         if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2276         else pSps=pSps->nextSps=createPmrSps(pChan);
2277
2278         pChan->spsTxOutA=pSps;
2279         if(!pChan->spsTx)pChan->spsTx=pSps;
2280
2281         if(pChan->txMixA==TX_OUT_COMPOSITE)
2282         {
2283                 pSps->source=pChan->pTxComposite;
2284         }
2285         else if(pChan->txMixA==TX_OUT_LSD)
2286         {
2287                 pSps->source=pChan->pTxLsdLpf;
2288         }
2289         else if(pChan->txMixA==TX_OUT_VOICE)
2290         {
2291                 pSps->source=pChan->pTxHpf;
2292         }
2293         else if (pChan->txMixA==TX_OUT_AUX)
2294         {
2295                 pSps->source=inputTmp;
2296         }
2297         else
2298         {
2299                 pSps->source=NULL;              // maw sph asdf !!!     no blow up
2300                 pSps->source=inputTmp;
2301         }
2302
2303         pSps->sink=pChan->pTxOut;
2304         pSps->sigProc=pmr_gp_fir;
2305         pSps->enabled=1;
2306         pSps->numChanOut=2;
2307         pSps->selChanOut=0;
2308         pSps->nSamples=pChan->nSamplesTx;
2309         pSps->interpolate=6;
2310         pSps->ncoef=taps_fir_lpf_3K_1;
2311         pSps->size_coef=2;
2312         pSps->coef=(void*)coef_fir_lpf_3K_1;
2313         pSps->nx=taps_fir_lpf_3K_1;
2314         pSps->size_x=2;
2315         pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2316         if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2317         pSps->calcAdjust=gain_fir_lpf_3K_1;
2318         pSps->inputGain=(1*M_Q8);
2319         pSps->outputGain=(1*M_Q8);
2320         if(pChan->txMixA==pChan->txMixB)pSps->monoOut=1;
2321         else pSps->monoOut=0;
2322
2323
2324         // Chan B Upsampler and Filter
2325         if((pChan->txMixA!=pChan->txMixB)&&(pChan->txMixB!=TX_OUT_OFF))
2326         {
2327                 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2328                 else pSps=pSps->nextSps=createPmrSps(pChan);
2329
2330                 pChan->spsTxOutB=pSps;
2331                 if(pChan->txMixB==TX_OUT_COMPOSITE)
2332                 {
2333                         pSps->source=pChan->pTxComposite;
2334                 }
2335                 else if(pChan->txMixB==TX_OUT_LSD)
2336                 {
2337                         pSps->source=pChan->pTxLsdLpf;
2338                         // pChan->ptxCtcssAdjust=&pSps->inputGain;
2339                 }
2340                 else if(pChan->txMixB==TX_OUT_VOICE)
2341                 {
2342                         pSps->source=inputTmp;
2343                 }
2344                 else if(pChan->txMixB==TX_OUT_AUX)
2345                 {
2346                         pSps->source=pChan->pTxHpf;
2347                 }
2348                 else
2349                 {
2350                         pSps->source=NULL;
2351                 }
2352
2353                 pSps->sink=pChan->pTxOut;
2354                 pSps->sigProc=pmr_gp_fir;
2355                 pSps->enabled=1;
2356                 pSps->numChanOut=2;
2357                 pSps->selChanOut=1;
2358                 pSps->mixOut=0;
2359                 pSps->nSamples=pChan->nSamplesTx;
2360                 pSps->interpolate=6;
2361                 pSps->ncoef=taps_fir_lpf_3K_1;
2362                 pSps->size_coef=2;
2363                 pSps->coef=(void*)coef_fir_lpf_3K_1;
2364                 pSps->nx=taps_fir_lpf_3K_1;
2365                 pSps->size_x=2;
2366                 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2367                 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2368                 pSps->calcAdjust=(gain_fir_lpf_3K_1);
2369                 pSps->inputGain=(1*M_Q8);
2370                 pSps->outputGain=(1*M_Q8);
2371         }
2372
2373         pSps->nextSps=NULL;
2374
2375         // Configure Coded Signaling
2376         code_string_parse(pChan);
2377
2378         pChan->smode=SMODE_NULL;
2379         pChan->smodewas=SMODE_NULL;
2380         pChan->smodetime=2500;
2381         pChan->smodetimer=0;
2382         pChan->b.smodeturnoff=0;
2383
2384         pChan->txsettletimer=0;
2385
2386         TRACEF(1,("createPmrChannel() end\n"));
2387
2388         return pChan;
2389 }
2390 /*
2391 */
2392 i16 destroyPmrChannel(t_pmr_chan *pChan)
2393 {
2394         #if XPMR_DEBUG0 == 1
2395         i16 i;
2396         #endif
2397         t_pmr_sps       *pmr_sps, *tmp_sps;
2398
2399         TRACEF(1,("destroyPmrChannel()\n"));
2400         
2401         free(pChan->pRxDemod);
2402         free(pChan->pRxNoise);
2403         free(pChan->pRxBase);
2404         free(pChan->pRxHpf);
2405         free(pChan->pRxLsd);
2406         free(pChan->pRxSpeaker);
2407         free(pChan->pRxDcTrack);
2408         if(pChan->pRxLsdLimit)free(pChan->pRxLsdLimit);
2409         free(pChan->pTxBase);
2410         free(pChan->pTxHpf);
2411         free(pChan->pTxPreEmp);
2412         free(pChan->pTxLimiter);
2413         free(pChan->pTxLsd);
2414         free(pChan->pTxLsdLpf);
2415         if(pChan->pTxComposite)free(pChan->pTxComposite);
2416         free(pChan->pTxOut);
2417
2418         if(pChan->prxMeasure)free(pChan->prxMeasure);
2419         if(pChan->pSigGen0)free(pChan->pSigGen0);
2420         if(pChan->pSigGen1)free(pChan->pSigGen1);
2421          
2422
2423         #if XPMR_DEBUG0 == 1
2424         //if(pChan->prxDebug)free(pChan->prxDebug);
2425         if(pChan->ptxDebug)free(pChan->ptxDebug);
2426         free(pChan->prxDebug0);
2427         free(pChan->prxDebug1);
2428         free(pChan->prxDebug2);
2429         free(pChan->prxDebug3);
2430
2431         free(pChan->ptxDebug0);
2432         free(pChan->ptxDebug1);
2433         free(pChan->ptxDebug2);
2434         free(pChan->ptxDebug3);
2435
2436         free(pChan->rxCtcss->pDebug0);
2437         free(pChan->rxCtcss->pDebug1);
2438
2439         for(i=0;i<CTCSS_NUM_CODES;i++)
2440         {
2441                 free(pChan->rxCtcss->tdet[i].pDebug0);
2442                 free(pChan->rxCtcss->tdet[i].pDebug1);
2443                 free(pChan->rxCtcss->tdet[i].pDebug2);
2444                 free(pChan->rxCtcss->tdet[i].pDebug3);
2445         }
2446         #endif
2447
2448         pChan->dd.option=8;
2449         dedrift(pChan);
2450
2451         free(pChan->pRxCtcss);
2452
2453         pmr_sps=pChan->spsRx;
2454
2455         if(pChan->sdbg)free(pChan->sdbg);
2456
2457         while(pmr_sps)
2458         {
2459                 tmp_sps = pmr_sps;
2460                 pmr_sps = tmp_sps->nextSps;
2461                 destroyPmrSps(tmp_sps);
2462         }
2463
2464         free(pChan);
2465
2466         return 0;
2467 }
2468 /*
2469 */
2470 t_pmr_sps *createPmrSps(t_pmr_chan *pChan)
2471 {
2472         t_pmr_sps  *pSps;
2473
2474         TRACEF(1,("createPmrSps()\n"));
2475
2476         pSps = (t_pmr_sps *)calloc(sizeof(t_pmr_sps),1);
2477
2478         if(!pSps)printf("Error: createPmrSps()\n");
2479
2480         pSps->parentChan=pChan;
2481         pSps->index=pChan->spsIndex++;
2482
2483         // pSps->x=calloc(pSps->nx,pSps->size_x);
2484
2485         return pSps;
2486 }
2487 /*
2488 */
2489 i16 destroyPmrSps(t_pmr_sps  *pSps)
2490 {
2491         TRACEJ(1,("destroyPmrSps(%i)\n",pSps->index));
2492
2493         if(pSps->x!=NULL)free(pSps->x);
2494         free(pSps);
2495         return 0;
2496 }
2497 /*
2498         PmrTx - takes data from network and holds it for PmrRx
2499 */
2500 i16 PmrTx(t_pmr_chan *pChan, i16 *input)
2501 {
2502         pChan->frameCountTx++;
2503
2504         TRACEF(5,("PmrTx() start %i\n",pChan->frameCountTx));
2505
2506         #if XPMR_PPTP == 99
2507         pptp_p2^=1;
2508         if(pptp_p2)ioctl(ppdrvdev,PPDRV_IOC_PINSET,LP_PIN02);
2509         else ioctl(ppdrvdev,PPDRV_IOC_PINCLEAR,LP_PIN02);
2510         #endif
2511
2512         if(pChan==NULL){
2513                 printf("PmrTx() pChan == NULL\n");
2514                 return 1;
2515         }
2516
2517         #if XPMR_DEBUG0 == 1
2518         if(pChan->b.rxCapture && pChan->tracetype==5)
2519         {
2520                 memcpy(pChan->pTxInput,input,pChan->nSamplesRx*2);
2521         }
2522         #endif
2523
2524         //if(pChan->b.radioactive)pChan->dd.debug=1;
2525         //else pChan->dd.debug=0;
2526
2527         dedrift_write(pChan,input);
2528
2529         return 0;
2530 }
2531 /*
2532         PmrRx handles a block of data from the usb audio device
2533 */
2534 i16 PmrRx(t_pmr_chan *pChan, i16 *input, i16 *outputrx, i16 *outputtx)
2535 {
2536         int i,hit;
2537         float f=0;
2538         t_pmr_sps *pmr_sps;
2539
2540         TRACEC(5,("PmrRx(%p %p %p %p)\n",pChan, input, outputrx, outputtx));
2541
2542     #if XPMR_PPTP == 1
2543         if(pChan->b.radioactive)
2544         {
2545                 pptp_write(1,pChan->frameCountRx&0x00000001);
2546         }
2547         #endif
2548
2549         if(pChan==NULL){
2550                 printf("PmrRx() pChan == NULL\n");
2551                 return 1;
2552         }
2553
2554         pChan->frameCountRx++;
2555
2556         #if XPMR_DEBUG0 == 1
2557         if(pChan->b.rxCapture)
2558         {
2559                 //if(pChan->prxDebug)memset((void *)pChan->prxDebug,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2560                 if(pChan->ptxDebug)memset((void *)pChan->ptxDebug,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2561                 if(pChan->sdbg->buffer)
2562                 {
2563                         memset((void *)pChan->sdbg->buffer,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2564                         pChan->prxDebug=pChan->sdbg->buffer;
2565                 }
2566         }
2567         #endif
2568
2569         pmr_sps=pChan->spsRx;           // first sps
2570         pmr_sps->source=input;
2571
2572         if(outputrx!=NULL)pChan->spsRxOut->sink=outputrx;        //last sps
2573
2574         #if 0
2575         if(pChan->inputBlanking>0)
2576         {
2577                 pChan->inputBlanking-=pChan->nSamplesRx;
2578                 if(pChan->inputBlanking<0)pChan->inputBlanking=0;
2579                 for(i=0;i<pChan->nSamplesRx*6;i++)
2580                         input[i]=0;
2581         }
2582         #endif
2583
2584         if( pChan->rxCpuSaver && !pChan->rxCarrierDetect && 
2585             pChan->smode==SMODE_NULL &&
2586            !pChan->txPttIn && !pChan->txPttOut)
2587         {
2588                 if(!pChan->b.rxhalted)
2589                 {
2590                         if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=0;
2591                         if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=0;
2592                         pChan->b.rxhalted=1;
2593                         TRACEC(1,("PmrRx() rx sps halted\n"));
2594                 }
2595         }
2596         else if(pChan->b.rxhalted)
2597         {
2598                 if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=1;
2599                 if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=1;
2600                 pChan->b.rxhalted=0;
2601                 TRACEC(1,("PmrRx() rx sps un-halted\n"));
2602         }
2603
2604         i=0;
2605         while(pmr_sps!=NULL && pmr_sps!=0)
2606         {
2607                 TRACEC(5,("PmrRx() sps %i\n",i++));
2608                 pmr_sps->sigProc(pmr_sps);
2609                 pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps);
2610                 //pmr_sps=NULL; // sph maw
2611         }
2612
2613         #define XPMR_VOX_HANGTIME       2000
2614
2615         if(pChan->rxCdType==CD_XPMR_VOX)
2616         {
2617                 if(pChan->spsRxVox->compOut)
2618                 {
2619                         pChan->rxVoxTimer=XPMR_VOX_HANGTIME;    //VOX HangTime in ms
2620                 }
2621                 if(pChan->rxVoxTimer>0)
2622                 {
2623                         pChan->rxVoxTimer-=MS_PER_FRAME;
2624                         pChan->rxCarrierDetect=1;
2625                 }
2626                 else
2627                 {
2628                         pChan->rxVoxTimer=0;
2629                         pChan->rxCarrierDetect=0;
2630                 }
2631         }
2632         else
2633         {
2634                 pChan->rxCarrierDetect=!pChan->spsRx->compOut;
2635         }
2636
2637         // stop and start these engines instead to eliminate falsing
2638         if( pChan->b.ctcssRxEnable && 
2639             ( (!pChan->b.rxhalted || 
2640                    pChan->rxCtcss->decode!=CTCSS_NULL || pChan->smode==SMODE_CTCSS) &&
2641                 (pChan->smode!=SMODE_DCS&&pChan->smode!=SMODE_LSD) ) 
2642           )
2643         {
2644                 ctcss_detect(pChan);
2645         }
2646
2647         #if 1
2648         if(pChan->txPttIn!=pChan->b.pttwas)
2649         {
2650                 pChan->b.pttwas=pChan->txPttIn;
2651                 TRACEC(1,("PmrRx() txPttIn=%i\n",pChan->b.pttwas));
2652         }
2653         #endif
2654
2655         #ifdef XPMRX_H
2656         xpmrx(pChan,XXO_RXDECODE);
2657         #endif
2658
2659         if(pChan->smodetimer>0 && !pChan->txPttIn)
2660         {
2661                 pChan->smodetimer-=MS_PER_FRAME;
2662                 
2663                 if(pChan->smodetimer<=0)
2664                 {
2665                         pChan->smodetimer=0;
2666                         pChan->smodewas=pChan->smode;
2667                         pChan->smode=SMODE_NULL;
2668                         pChan->b.smodeturnoff=1;
2669                         TRACEC(1,("smode timeout. smode was=%i\n",pChan->smodewas));
2670                 }
2671         }
2672
2673         if(pChan->rxCtcss->decode > CTCSS_NULL && 
2674            (pChan->smode==SMODE_NULL||pChan->smode==SMODE_CTCSS) )
2675         {
2676                 if(pChan->smode!=SMODE_CTCSS)
2677                 {
2678                         TRACEC(1,("smode set=%i  code=%i\n",pChan->smode,pChan->rxCtcss->decode));
2679                         pChan->smode=pChan->smodewas=SMODE_CTCSS;
2680                 }
2681                 pChan->smodetimer=pChan->smodetime;
2682         }
2683
2684         #ifdef HAVE_XPMRX
2685         xpmrx(pChan,XXO_LSDCTL);
2686         #endif
2687
2688         //TRACEX(("PmrRx() tx portion.\n"));
2689
2690         // handle radio transmitter ptt input
2691         hit=0;
2692         if( !(pChan->smode==SMODE_DCS||pChan->smode==SMODE_LSD) )
2693         {
2694          
2695         if( pChan->txPttIn && pChan->txState==CHAN_TXSTATE_IDLE )
2696         {
2697                 TRACEC(1,("txPttIn==1 from CHAN_TXSTATE_IDLE && !SMODE_LSD. codeindex=%i  %i \n",pChan->rxCtcss->decode, pChan->rxCtcssMap[pChan->rxCtcss->decode] ));
2698                 pChan->dd.b.doitnow=1;
2699
2700             if(pChan->smode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2701                 {
2702                         if(pChan->rxCtcss->decode>CTCSS_NULL)
2703                         {
2704                                 if(pChan->rxCtcssMap[pChan->rxCtcss->decode]!=CTCSS_RXONLY)
2705                                 {
2706                                         f=freq_ctcss[pChan->rxCtcssMap[pChan->rxCtcss->decode]];
2707                                 }
2708                         }
2709                         else
2710                         {
2711                                 f=pChan->txctcssdefault_value;  
2712                         }
2713                         TRACEC(1,("txPttIn - Start CTCSSGen  %f \n",f));
2714                         if(f)
2715                         {
2716                                 t_pmr_sps *pSps;
2717         
2718                                 pChan->spsSigGen0->freq=f*10;
2719                                 pSps=pChan->spsTxLsdLpf;
2720                                 pSps->enabled=1;
2721
2722                                 #if 0
2723                                 if(f>203.0)
2724                                 {
2725                                         pSps->ncoef=taps_fir_lpf_250_9_66;
2726                                         pSps->size_coef=2;
2727                                         pSps->coef=(void*)coef_fir_lpf_250_9_66;
2728                                         pSps->nx=taps_fir_lpf_250_9_66;
2729                                         pSps->size_x=2;
2730                                         pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2731                                         pSps->calcAdjust=gain_fir_lpf_250_9_66;
2732                                 }
2733                                 else
2734                                 {
2735                                         pSps->ncoef=taps_fir_lpf_215_9_88;
2736                                         pSps->size_coef=2;
2737                                         pSps->coef=(void*)coef_fir_lpf_215_9_88;
2738                                         pSps->nx=taps_fir_lpf_215_9_88;
2739                                         pSps->size_x=2;
2740                                         pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2741                                         pSps->calcAdjust=gain_fir_lpf_215_9_88;
2742                                 }
2743                                 #endif
2744
2745                                 pChan->spsSigGen0->option=1;
2746                                 pChan->spsSigGen0->enabled=1;
2747                             pChan->spsSigGen0->discounterl=0;
2748                     }
2749                 }
2750                 else if(pChan->smode==SMODE_NULL && pChan->txcodedefaultsmode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2751                 {
2752                     TRACEC(1,("txPtt Encode txcodedefaultsmode==SMODE_CTCSS %f\n",pChan->txctcssdefault_value));
2753                         pChan->spsSigGen0->freq=pChan->txctcssdefault_value*10;
2754                         pChan->spsSigGen0->option=1;
2755                     pChan->spsSigGen0->enabled=1;
2756                         pChan->spsSigGen0->discounterl=0;
2757                         pChan->smode=SMODE_CTCSS;
2758                         pChan->smodetimer=pChan->smodetime;
2759                 }
2760                 else if(pChan->txcodedefaultsmode==SMODE_NULL||pChan->b.txCtcssInhibit)
2761                 {
2762                         TRACEC(1,("txPtt Encode txcodedefaultsmode==SMODE_NULL\n"));
2763                 }
2764                 else
2765                 {
2766                         printf   ("ERROR: txPttIn=%i NOT HANDLED PROPERLY.\n",pChan->txPttIn);
2767                         TRACEC(1,("ERROR: txPttIn=%i NOT HANDLED PROPERLY.\n",pChan->txPttIn));
2768                 }
2769
2770                 pChan->txState = CHAN_TXSTATE_ACTIVE;
2771                 pChan->txPttOut=1;
2772
2773                 pChan->txsettletimer=pChan->txsettletime;
2774
2775                 if(pChan->spsTxOutA)pChan->spsTxOutA->enabled=1;
2776                 if(pChan->spsTxOutB)pChan->spsTxOutB->enabled=1;
2777                 if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->enabled=1;
2778                 if(pChan->txfreq)pChan->b.reprog=1;
2779                 TRACEC(1,("PmrRx() TxOn\n"));
2780         }
2781         else if(pChan->txPttIn && pChan->txState==CHAN_TXSTATE_ACTIVE)
2782         {
2783                 // pChan->smode=SMODE_CTCSS;
2784                 pChan->smodetimer=pChan->smodetime;
2785         }
2786         else if(!pChan->txPttIn && pChan->txState==CHAN_TXSTATE_ACTIVE)
2787         {
2788                 TRACEC(1,("txPttIn==0 from CHAN_TXSTATE_ACTIVE\n"));
2789                 if(pChan->smode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2790                 {
2791                         if( pChan->txTocType==TOC_NONE || !pChan->b.ctcssTxEnable )
2792                         {
2793                                 TRACEC(1,("Tx Off Immediate.\n"));
2794                                 pChan->spsSigGen0->option=3;
2795                                 pChan->txBufferClear=3;
2796                                 pChan->txState=CHAN_TXSTATE_FINISHING;
2797                 }
2798                         else if(pChan->txTocType==TOC_NOTONE)
2799                         {
2800                                 pChan->txState=CHAN_TXSTATE_TOC;
2801                                 pChan->txHangTime=TOC_NOTONE_TIME/MS_PER_FRAME;
2802                                 pChan->spsSigGen0->option=3;
2803                                 TRACEC(1,("Tx Turn Off No Tone Start.\n"));
2804                         }
2805                         else
2806                         {
2807                                 pChan->txState=CHAN_TXSTATE_TOC;
2808                                 pChan->txHangTime=0;
2809                                 pChan->spsSigGen0->option=2;
2810                                 TRACEC(1,("Tx Turn Off Phase Shift Start.\n"));
2811                         }
2812             }
2813                 else
2814                 {
2815                     pChan->txBufferClear=3;
2816                         pChan->txState=CHAN_TXSTATE_FINISHING;
2817                         TRACEC(1,("Tx Off No SMODE to Finish.\n"));
2818                 }
2819         }
2820         else if(pChan->txState==CHAN_TXSTATE_TOC)
2821         {
2822                 if( pChan->txPttIn && pChan->smode==SMODE_CTCSS )
2823                 {
2824                         TRACEC(1,("Tx Key During HangTime\n"));
2825                         pChan->txState = CHAN_TXSTATE_ACTIVE;
2826                         pChan->spsSigGen0->option=1;
2827                         pChan->spsSigGen0->enabled=1;
2828                         pChan->spsSigGen0->discounterl=0;
2829                         hit=0;
2830                 }
2831                 else if(pChan->txHangTime)
2832                 {
2833                         if(--pChan->txHangTime==0)pChan->txState=CHAN_TXSTATE_FINISHING;
2834                 }
2835                 else if(pChan->txHangTime<=0 && pChan->spsSigGen0->state==0)
2836                 {
2837                         pChan->txBufferClear=3;
2838                         pChan->txState=CHAN_TXSTATE_FINISHING;
2839                         TRACEC(1,("Tx Off TOC.\n"));
2840                 }
2841         }
2842         else if(pChan->txState==CHAN_TXSTATE_FINISHING)
2843         {
2844                 if(--pChan->txBufferClear<=0)
2845                         pChan->txState=CHAN_TXSTATE_COMPLETE;
2846         }
2847         else if(pChan->txState==CHAN_TXSTATE_COMPLETE)
2848         {
2849                 hit=1;  
2850         }
2851         }       // end of if SMODE==LSD
2852
2853         if(hit)
2854         {
2855                 pChan->txPttOut=0;
2856                 pChan->spsSigGen0->option=3;
2857                 pChan->txState=CHAN_TXSTATE_IDLE;
2858                 if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->option=3;
2859                 if(pChan->spsTxOutA)pChan->spsTxOutA->option=3;
2860                 if(pChan->spsTxOutB)pChan->spsTxOutB->option=3;
2861                 if(pChan->rxfreq||pChan->txfreq)pChan->b.reprog=1;
2862                 TRACEC(1,("Tx Off hit.\n"));
2863         }
2864                           
2865         if(pChan->b.reprog)
2866         {
2867                 pChan->b.reprog=0;      
2868                 progdtx(pChan);
2869         }
2870
2871         if(pChan->txsettletimer && pChan->txPttHid )
2872         {
2873                 pChan->txsettletimer-=MS_PER_FRAME;
2874                 if(pChan->txsettletimer<0)pChan->txsettletimer=0;
2875         }
2876
2877         // enable this after we know everything else is working
2878         if( pChan->txCpuSaver && 
2879             !pChan->txPttIn && !pChan->txPttOut && 
2880             pChan->txState==CHAN_TXSTATE_IDLE &&
2881             !pChan->dd.b.doitnow 
2882             ) 
2883         {
2884                 if(!pChan->b.txhalted)
2885                 {
2886                         pChan->b.txhalted=1;
2887                         TRACEC(1,("PmrRx() tx sps halted\n"));
2888                 }
2889         }
2890         else if(pChan->b.txhalted)
2891         {
2892                 pChan->dd.b.doitnow=1;
2893                 pChan->b.txhalted=0;
2894                 TRACEC(1,("PmrRx() tx sps un-halted\n"));
2895         }
2896
2897         if(pChan->b.txhalted)return(1);
2898
2899         if(pChan->b.startSpecialTone)
2900         {
2901                 pChan->b.startSpecialTone=0;
2902                 pChan->spsSigGen1->option=1;
2903                 pChan->spsSigGen1->enabled=1;
2904                 pChan->b.doingSpecialTone=1;
2905         } 
2906         else if(pChan->b.stopSpecialTone)
2907         {
2908                 pChan->b.stopSpecialTone=0;
2909                 pChan->spsSigGen1->option=0;
2910                 pChan->b.doingSpecialTone=0;
2911                 pChan->spsSigGen1->enabled=0;
2912         } 
2913         else if(pChan->b.doingSpecialTone)
2914         {
2915                 pChan->spsSigGen1->sink=outputtx;
2916                 pChan->spsSigGen1->sigProc(pChan->spsSigGen1);
2917                 for(i=0;i<(pChan->nSamplesTx*2*6);i+=2)outputtx[i+1]=outputtx[i];
2918                 return 0;
2919         }
2920
2921         if(pChan->spsSigGen0 && pChan->spsSigGen0->enabled )
2922         {
2923                 pChan->spsSigGen0->sigProc(pChan->spsSigGen0);
2924         }
2925
2926         if(pChan->spsSigGen1 && pChan->spsSigGen1->enabled)
2927         {
2928                 pChan->spsSigGen1->sigProc(pChan->spsSigGen1);
2929         }
2930
2931         #ifdef XPMRX_H
2932         pChan->spsLsdGen->sigProc(pChan->spsLsdGen);    // maw sph ???
2933         #endif
2934
2935         // Do Low Speed Data Low Pass Filter
2936         pChan->spsTxLsdLpf->sigProc(pChan->spsTxLsdLpf);
2937
2938         // Do Voice
2939         pmr_sps=pChan->spsTx;
2940
2941         // get tx data from de-drift process
2942         pChan->dd.option=0;
2943         pChan->dd.ptr=pChan->pTxBase;
2944         dedrift(pChan);
2945
2946         // tx process
2947         if(!pChan->spsSigGen1->enabled)
2948         {
2949                 pmr_sps->source=pChan->pTxBase;
2950         }
2951         else input=pmr_sps->source;
2952
2953         if(outputtx!=NULL)
2954         {
2955                 if(pChan->spsTxOutA)pChan->spsTxOutA->sink=outputtx;
2956                 if(pChan->spsTxOutB)pChan->spsTxOutB->sink=outputtx;
2957         }
2958
2959         i=0;
2960         while(pmr_sps!=NULL && pmr_sps!=0)
2961         {
2962                 //TRACEF(1,("PmrTx() sps %i\n",i++));
2963                 pmr_sps->sigProc(pmr_sps);
2964                 pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps);
2965         }
2966
2967         //TRACEF(1,("PmrTx() - outputs \n"));
2968         if(pChan->txMixA==TX_OUT_OFF || !pChan->txPttOut){
2969                 for(i=0;i<pChan->nSamplesTx*2*6;i+=2)outputtx[i]=0;
2970         }
2971
2972         if(pChan->txMixB==TX_OUT_OFF || !pChan->txPttOut ){
2973                 for(i=0;i<pChan->nSamplesTx*2*6;i+=2)outputtx[i+1]=0;
2974         }
2975
2976         #if XPMR_PPTP == 1
2977         if(     pChan->b.radioactive && pChan->b.pptp_p1!=pChan->txPttOut)
2978         {
2979                 pChan->b.pptp_p1=pChan->txPttOut;
2980                 pptp_write(0,pChan->b.pptp_p1);
2981         }
2982         #endif
2983
2984         #if XPMR_DEBUG0 == 1
2985         // TRACEF(1,("PmrRx() - debug outputs \n"));
2986         if(pChan->b.rxCapture){
2987                 for(i=0;i<pChan->nSamplesRx;i++)
2988                 {
2989                         pChan->pRxDemod[i]=input[i*2*6];
2990                         pChan->pTstTxOut[i]=outputtx[i*2*6+0]; // txa
2991                         //pChan->pTstTxOut[i]=outputtx[i*2*6+1]; // txb
2992                         TSCOPE((RX_NOISE_TRIG, pChan->sdbg, i, (pChan->rxCarrierDetect*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
2993                         TSCOPE((RX_CTCSS_DECODE, pChan->sdbg, i, pChan->rxCtcss->decode*(M_Q14/CTCSS_NUM_CODES)));
2994                         TSCOPE((RX_SMODE, pChan->sdbg, i, pChan->smode*(XPMR_TRACE_AMP/4)));
2995                         TSCOPE((TX_PTT_IN, pChan->sdbg, i, (pChan->txPttIn*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
2996                         TSCOPE((TX_PTT_OUT, pChan->sdbg, i, (pChan->txPttOut*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
2997                         TSCOPE((TX_DEDRIFT_LEAD, pChan->sdbg, i, pChan->dd.lead*8));
2998                         TSCOPE((TX_DEDRIFT_ERR, pChan->sdbg, i, pChan->dd.err*16));
2999                         TSCOPE((TX_DEDRIFT_FACTOR, pChan->sdbg, i, pChan->dd.factor*16));
3000                         TSCOPE((TX_DEDRIFT_DRIFT, pChan->sdbg, i, pChan->dd.drift*16));
3001                 }
3002     }
3003         #endif
3004
3005         strace2(pChan->sdbg);
3006         TRACEC(5,("PmrRx() return  cd=%i smode=%i  txPttIn=%i  txPttOut=%i \n",pChan->rxCarrierDetect,pChan->smode,pChan->txPttIn,pChan->txPttOut));
3007         return 0;
3008 }
3009 /*
3010         parallel binary programming of an RF Transceiver*/
3011
3012 void    ppbinout        (u8 chan)
3013 {
3014 #if(DTX_PROG == 1)
3015         i32     i;
3016
3017         if (ppdrvdev == 0)
3018         ppdrvdev = open("/dev/ppdrv_device", 0);
3019
3020     if (ppdrvdev < 0)
3021     {
3022         ast_log(LOG_ERROR, "open /dev/ppdrv_ppdrvdev returned %i\n",ppdrvdev);
3023                 return;
3024         }
3025
3026         i=0;
3027         if(chan&0x01)i|=BIN_PROG_0;
3028         if(chan&0x02)i|=BIN_PROG_1;
3029         if(chan&0x04)i|=BIN_PROG_2;
3030         if(chan&0x08)i|=BIN_PROG_3;
3031
3032         ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3033         //ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR,    BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3034         //ioctl(ppdrvdev, PPDRV_IOC_PINSET, i );
3035         ioctl(ppdrvdev, PPDRV_IOC_PINSET,    BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3036         ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, i );
3037
3038     // ioctl(ppdrvdev, PPDRV_IOC_PINSET, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0 ); 
3039     ast_log(LOG_NOTICE, "mask=%i 0x%x\n",i,i); 
3040 #endif
3041 }
3042 /*
3043         SPI Programming of an RF Transceiver
3044         need to add permissions check and mutex
3045 */
3046 /*
3047         need to add permissions check and mutex
3048 */
3049 void    ppspiout        (u32 spidata)
3050 {
3051 #if(DTX_PROG == 1)
3052         static char firstrun=0;
3053         i32     i,ii;
3054         u32     bitselect;
3055
3056     if (ppdrvdev < 0)
3057     {
3058         ast_log(LOG_ERROR, "no parallel port permission ppdrvdev %i\n",ppdrvdev);
3059                 exit(0);
3060         }
3061
3062         ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3063         ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3064
3065         if(firstrun==0)
3066         {
3067                 firstrun=1;
3068                 for(ii=0;ii<PP_BIT_TIME*200;ii++);      
3069         }
3070         else
3071         {
3072                 for(ii=0;ii<PP_BIT_TIME*4;ii++);
3073         }
3074
3075         bitselect=0x00080000;
3076
3077         for(i=0;i<(PP_REG_LEN-12);i++)
3078         {
3079                 if((bitselect&spidata))
3080                         ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_DATA );
3081                 else
3082                         ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_DATA );
3083
3084                 for(ii=0;ii<PP_BIT_TIME;ii++);
3085
3086                 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_CLK );
3087                 for(ii=0;ii<PP_BIT_TIME;ii++);
3088                 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK );
3089                 for(ii=0;ii<PP_BIT_TIME;ii++);
3090
3091                 bitselect=(bitselect>>1);
3092         }
3093         ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA );
3094         ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_ENABLE );
3095         for(ii=0;ii<PP_BIT_TIME;ii++);
3096         ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_ENABLE );
3097 #endif
3098 }
3099 /*
3100         mutex needed
3101         now assumes calling thread secures permissions
3102         could set up a separate thread to program the radio? yuck!
3103
3104 */
3105 void    progdtx(t_pmr_chan *pChan)
3106 {
3107 #if(DTX_PROG == 1)      
3108         //static u32    progcount=0;
3109
3110         u32 reffreq;
3111         u32 stepfreq;
3112         u32 rxiffreq;
3113         u32 synthfreq;
3114         u32 shiftreg;
3115         u32 tmp;
3116
3117         TRACEC(1,("\nprogdtx() %i %i %i\n",pChan->rxfreq,pChan->txfreq,0));
3118
3119         if (ppdrvdev == 0)
3120         ppdrvdev = open("/dev/ppdrv_device", 0);
3121
3122     if (ppdrvdev < 0)
3123     {
3124         ast_log(LOG_ERROR, "open /dev/ppdrv_ppdrvdev returned %i\n",ppdrvdev);
3125                 exit(0);
3126         }
3127
3128         if(pChan->rxfreq>200000000)
3129         {
3130                 reffreq=16012500;
3131                 stepfreq=12500;
3132                 rxiffreq=21400000;
3133         }
3134         else
3135         {
3136                 reffreq=16000000;
3137                 stepfreq=5000;
3138                 rxiffreq=10700000;
3139         }
3140
3141         shiftreg=(reffreq/stepfreq)<<1;
3142         shiftreg=shiftreg|0x00000001;
3143
3144         ppspiout(shiftreg);
3145
3146         if(pChan->txPttOut)
3147                 synthfreq=pChan->txfreq;
3148         else
3149                 synthfreq=pChan->rxfreq-rxiffreq;
3150
3151         shiftreg=(synthfreq/stepfreq)<<1;
3152         tmp=(shiftreg&0xFFFFFF80)<<1;
3153         shiftreg=tmp+(shiftreg&0x0000007F);
3154
3155         ppspiout(shiftreg);
3156
3157         ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3158         ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA | DTX_ENABLE );
3159
3160         if(pChan->txPttOut)
3161         {
3162                 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_TXPWR );
3163                 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_TX );
3164                 if(pChan->txpower && 0) ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_TXPWR );
3165         }
3166         else
3167         {
3168                 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_TX | DTX_TXPWR );
3169         }
3170 #endif
3171 }
3172
3173 /*      dedrift
3174         reconciles clock differences between the usb adapter and 
3175         asterisk's frame rate clock     
3176         take out all accumulated drift error on these events:
3177         before transmitter on
3178         when ptt release from mobile units detected
3179 */
3180 void dedrift(t_pmr_chan *pChan)
3181 {
3182         TRACEC(5,("dedrift()\n"));
3183
3184         if(pChan->dd.option==9)
3185         {
3186                 TRACEF(1,("dedrift(9)\n"));
3187                 pChan->dd.framesize=DDB_FRAME_SIZE;
3188                 pChan->dd.frames=DDB_FRAMES_IN_BUFF;
3189                 pChan->dd.buffersize = pChan->dd.frames * pChan->dd.framesize;
3190                 pChan->dd.buff=calloc(DDB_FRAME_SIZE*DDB_FRAMES_IN_BUFF,2);
3191                 pChan->dd.modulus=DDB_ERR_MODULUS;
3192                 pChan->dd.inputindex=0;
3193                 pChan->dd.outputindex=0;
3194                 pChan->dd.skew = pChan->dd.lead=0;
3195                 pChan->dd.z1=0;
3196                 pChan->dd.debug=0;
3197                 pChan->dd.debugcnt=0;
3198                 pChan->dd.lock=pChan->dd.b.txlock=pChan->dd.b.rxlock=0;
3199                 pChan->dd.initcnt=2;
3200                 pChan->dd.timer=10000/20;
3201                 pChan->dd.drift=0;
3202                 pChan->dd.factor=pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3203                 pChan->dd.txframecnt=pChan->dd.rxframecnt=0;
3204                 // clear the buffer too!
3205                 return;
3206         }
3207         else if(pChan->dd.option==8)
3208         {
3209                 free(pChan->dd.buff);
3210                 pChan->dd.lock=0;
3211                 pChan->dd.b.txlock=pChan->dd.b.rxlock=0;
3212                 return;
3213         }
3214         else if(pChan->dd.initcnt==0)
3215         {
3216                 const i32 a0 =  26231;
3217                 const i32 a1 =  26231;
3218                 const i32 b0 =  32768;
3219                 const i32 b1 = -32358;
3220                 const i32 dg =  128;
3221                 void *vptr;
3222                 i16 inputindex;
3223                 i16 indextweak;
3224             i32 accum;
3225
3226                 inputindex = pChan->dd.inputindex;
3227                 pChan->dd.skew = pChan->dd.txframecnt-pChan->dd.rxframecnt;
3228                 pChan->dd.rxframecnt++;
3229
3230                 // pull data from buffer
3231                 if( (pChan->dd.outputindex + pChan->dd.framesize) > pChan->dd.buffersize )