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