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