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