2 * xpmr.c - Xelatec Private Mobile Radio Processes
4 * All Rights Reserved. Copyright (C)2007, Xelatec, LLC
6 * 20070808 1235 Steven Henke, W9SH, sph@xelatec.com
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.
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.
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
22 * This version may be optionally licenced under the GNU LGPL licence.
24 * A license has been granted to Digium (via disclaimer) for the use of
27 * 20080118 0800 sph@xelatec.com major fixes and features
32 * \brief Private Land Mobile Radio Channel Voice and Signaling Processor
34 * \author Steven Henke, W9SH <sph@xelatec.com> Xelatec, LLC
37 FYI = For Your Information
38 PMR = Private Mobile Radio
41 CTCSS = Continuous Tone Coded Squelch System
43 LSD = Low Speed Data, subaudible signaling. May be tones or codes.
44 VOX = Voice Operated Transmit
45 DSP = Digital Signal Processing
47 FIR = Finite Impulse Response (Filter)
48 IIR = Infinite Impulse Response (Filter)
51 // XPMR_FILE_VERSION(__FILE__, "$Revision$")
58 #include <sys/ioctl.h>
68 #include "xpmr_coef.h"
71 static i16 pmrChanIndex=0; // count of created pmr instances
72 //static i16 pmrSpsIndex=0;
74 #if (DTX_PROG == 1) || XPMR_PPTP == 1
75 static int ppdrvdev=0;
81 void strace(i16 point, t_sdbg *sdbg, i16 idx, i16 value)
83 // make dbg_trace buffer in structure
84 if(!sdbg->mode || sdbg->point[point]<0){
87 sdbg->buffer[(idx*XPMR_DEBUG_CHANS) + sdbg->point[point]] = value;
93 void strace2(t_sdbg *sdbg)
96 for(i=0;i<XPMR_DEBUG_CHANS;i++)
101 for(ii=0;ii<SAMPLES_PER_BLOCK;ii++)
103 sdbg->buffer[ii*XPMR_DEBUG_CHANS + i] = sdbg->source[i][ii];
110 Hardware Trace Signals via the PC Parallel Port
112 void pptp_init (void)
115 ppdrvdev = open("/dev/ppdrv_device", 0);
119 ast_log(LOG_ERROR, "open /dev/ppdrv_ppdrvdev returned %i\n",ppdrvdev);
122 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX | DTX_TP1 | DTX_TP2);
123 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX | DTX_TP1 | DTX_TP2);
127 void pptp_write(i16 bit, i16 state)
131 if(state)ioctl(ppdrvdev,PPDRV_IOC_PINSET,DTX_TP1);
132 else ioctl(ppdrvdev,PPDRV_IOC_PINCLEAR,DTX_TP1);
136 if(state)ioctl(ppdrvdev,PPDRV_IOC_PINSET,DTX_TP2);
137 else ioctl(ppdrvdev,PPDRV_IOC_PINCLEAR,DTX_TP2);
142 take source string allocate and copy
143 copy is modified, delimiters are replaced with zeros to mark
146 string_parse( char *src, char *dest, char **sub)
148 i16 string_parse(char *src, char **dest, char ***ptrs)
154 TRACEJ(2,("string_parse(%s)\n",src));
157 TRACEJ(2,(" source len = %i\n",slen));
167 for(i=0;i<slen+1;i++)
169 TRACEJ(5,(" pd[%i] = %c\n",i,pd[i]));
171 if( p==0 && pd[i]!=',' && pd[i]!=' ' )
175 else if(pd[i]==',' || pd[i]==0 )
184 for(i=0;i<numsub;i++)
186 TRACEJ(5,(" ptstr[%i] = %p %s\n",i,ptstr[i],ptstr[i]));
189 if(*ptrs)free(*ptrs);
190 *ptrs=calloc(numsub,4);
191 for(i=0;i<numsub;i++)
194 TRACEJ(5,(" %i = %s\n",i,(*ptrs)[i]));
196 TRACEJ(5,("string_parse()=%i\n\n",numsub));
201 the parent program defines
202 pRxCodeSrc and pTxCodeSrc string pointers to the list of codes
203 pTxCodeDefault the default Tx Code.
206 i16 code_string_parse(t_pmr_chan *pChan)
210 float f, maxctcsstxfreq;
215 TRACEF(1,("code_string_parse(%i)\n",0));
216 TRACEF(1,("pChan->pRxCodeSrc %s \n",pChan->pRxCodeSrc));
217 TRACEF(1,("pChan->pTxCodeSrc %s \n",pChan->pTxCodeSrc));
218 TRACEF(1,("pChan->pTxCodeDefault %s \n",pChan->pTxCodeDefault));
220 //printf("code_string_parse() %s / %s / %s / %s \n",pChan->name, pChan->pTxCodeDefault,pChan->pTxCodeSrc,pChan->pRxCodeSrc);
222 maxctcssindex=CTCSS_NULL;
223 maxctcsstxfreq=CTCSS_NULL;
224 pChan->txctcssdefault_index=CTCSS_NULL;
225 pChan->txctcssdefault_value=CTCSS_NULL;
227 pChan->b.ctcssRxEnable=pChan->b.ctcssTxEnable=0;
228 pChan->b.dcsRxEnable=pChan->b.dcsTxEnable=0;
229 pChan->b.lmrRxEnable=pChan->b.lmrTxEnable=0;
230 pChan->b.mdcRxEnable=pChan->b.mdcTxEnable=0;
231 pChan->b.dstRxEnable=pChan->b.dstTxEnable=0;
232 pChan->b.p25RxEnable=pChan->b.p25TxEnable=0;
234 if(pChan->spsLsdGen){
235 pChan->spsLsdGen->enabled=0;
236 pChan->spsLsdGen->state=0;
239 TRACEF(1,("code_string_parse(%i) 05\n",0));
241 pChan->numrxcodes = string_parse( pChan->pRxCodeSrc, &(pChan->pRxCodeStr), &(pChan->pRxCode));
242 pChan->numtxcodes = string_parse( pChan->pTxCodeSrc, &(pChan->pTxCodeStr), &(pChan->pTxCode));
244 if(pChan->numrxcodes!=pChan->numtxcodes)printf("ERROR: numrxcodes != numtxcodes \n");
246 pChan->rxCtcss->enabled=0;
247 pChan->rxCtcss->gain=1*M_Q8;
248 pChan->rxCtcss->limit=8192;
249 pChan->rxCtcss->input=pChan->pRxLsdLimit;
250 pChan->rxCtcss->decode=CTCSS_NULL;
252 pChan->rxCtcss->testIndex=0;
253 if(!pChan->rxCtcss->testIndex)pChan->rxCtcss->testIndex=3;
255 pChan->rxctcssfreq[0]=0; // decode now CTCSS_RXONLY
257 for(i=0;i<CTCSS_NUM_CODES;i++)
261 pChan->rxCtcssMap[i]=CTCSS_NULL;
264 TRACEF(1,("code_string_parse(%i) 10\n",0));
267 xpmrx(pChan,XXO_LSDCODEPARSE);
270 // Do Receive Codes String
271 for(i=0;i<pChan->numrxcodes;i++)
276 p=pChan->pStr=pChan->pRxCode[i];
279 if(!xpmrx(pChan,XXO_LSDCODEPARSE_1))
282 sscanf(p, "%30f", &_f);
283 ri=CtcssFreqIndex(_f);
284 if(ri>maxctcssindex)maxctcssindex=ri;
286 sscanf(pChan->pTxCode[i], "%30f", &_f);
287 _ti=CtcssFreqIndex(_f);
288 if(_f>maxctcsstxfreq)maxctcsstxfreq=_f;
290 if(ri>CTCSS_NULL && _ti>CTCSS_NULL)
292 pChan->b.ctcssRxEnable=pChan->b.ctcssTxEnable=1;
293 pChan->rxCtcssMap[ri]=_ti;
294 pChan->numrxctcssfreqs++;
295 TRACEF(1,("pChan->rxctcss[%i]=%s pChan->rxCtcssMap[%i]=%i\n",i,pChan->rxctcss[i],ri,_ti));
297 else if(ri>CTCSS_NULL && _f==0)
299 pChan->b.ctcssRxEnable=1;
300 pChan->rxCtcssMap[ri]=CTCSS_RXONLY;
301 pChan->numrxctcssfreqs++;
302 TRACEF(1,("pChan->rxctcss[%i]=%s pChan->rxCtcssMap[%i]=%i RXONLY\n",i,pChan->rxctcss[i],ri,_ti));
307 pChan->numrxctcssfreqs=0;
308 for(_ii=0;_ii<CTCSS_NUM_CODES;_ii++) pChan->rxCtcssMap[_ii]=CTCSS_NULL;
309 TRACEF(1,("WARNING: Invalid Channel code detected and ignored. %i %s %s \n",i,pChan->pRxCode[i],pChan->pTxCode[i]));
314 TRACEF(1,("code_string_parse() CTCSS Init Struct %i %i\n",pChan->b.ctcssRxEnable,pChan->b.ctcssTxEnable));
315 if(pChan->b.ctcssRxEnable)
317 pChan->rxHpfEnable=1;
318 pChan->spsRxLsdNrz->enabled=pChan->rxCenterSlicerEnable=1;
319 pChan->rxCtcssDecodeEnable=1;
320 pChan->rxCtcss->enabled=1;
324 pChan->rxHpfEnable=1;
325 pChan->spsRxLsdNrz->enabled=pChan->rxCenterSlicerEnable=0;
326 pChan->rxCtcssDecodeEnable=0;
327 pChan->rxCtcss->enabled=0;
330 TRACEF(1,("code_string_parse() CTCSS Init Decoders \n"));
331 for(i=0;i<CTCSS_NUM_CODES;i++)
334 ptdet=&(pChan->rxCtcss->tdet[i]);
335 ptdet->counterFactor=coef_ctcss_div[i];
337 ptdet->setpt=(M_Q15*0.041); // 0.069
338 ptdet->hyst =(M_Q15*0.0130);
339 ptdet->binFactor=(M_Q15*0.135); // was 0.140
340 ptdet->fudgeFactor=8;
345 TRACEF(1,("code_string_parse() Default Tx Code %s \n",pChan->pTxCodeDefault));
346 pChan->txcodedefaultsmode=SMODE_NULL;
347 p=pChan->pStr=pChan->pTxCodeDefault;
350 if(!lsd_code_parse(pChan,3))
353 sscanf(p, "%30f", &f);
354 ti=CtcssFreqIndex(f);
355 if(f>maxctcsstxfreq)maxctcsstxfreq=f;
359 pChan->b.ctcssTxEnable=1;
360 pChan->txctcssdefault_index=ti;
361 pChan->txctcssdefault_value=f;
362 pChan->spsSigGen0->freq=f*10;
363 pChan->txcodedefaultsmode=SMODE_CTCSS;
364 TRACEF(1,("code_string_parse() Tx Default CTCSS = %s %i %f\n",p,ti,f));
369 // set x for maximum length and just change pointers
370 TRACEF(1,("code_string_parse() Filter Config \n"));
371 pSps=pChan->spsTxLsdLpf;
372 if(pSps->x)free(pSps->x);
373 if(maxctcsstxfreq>203.5)
375 pSps->ncoef=taps_fir_lpf_250_9_66;
377 pSps->coef=(void*)coef_fir_lpf_250_9_66;
378 pSps->nx=taps_fir_lpf_250_9_66;
380 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
381 pSps->calcAdjust=gain_fir_lpf_250_9_66;
382 TRACEF(1,("code_string_parse() Tx Filter Freq High\n"));
386 pSps->ncoef=taps_fir_lpf_215_9_88;
388 pSps->coef=(void*)coef_fir_lpf_215_9_88;
389 pSps->nx=taps_fir_lpf_215_9_88;
391 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
392 pSps->calcAdjust=gain_fir_lpf_215_9_88;
393 TRACEF(1,("code_string_parse() Tx Filter Freq Low\n"));
396 // CTCSS Rx Decoder Low Pass Filter
398 ii= CtcssFreqIndex(203.5);
399 for(i=ii;i<CTCSS_NUM_CODES;i++)
401 if(pChan->rxCtcssMap[i]>CTCSS_NULL)hit=1;
404 pSps=pChan->spsRxLsd;
405 if(pSps->x)free(pSps->x);
408 pSps->ncoef=taps_fir_lpf_250_9_66;
410 pSps->coef=(void*)coef_fir_lpf_250_9_66;
411 pSps->nx=taps_fir_lpf_250_9_66;
413 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
414 pSps->calcAdjust=gain_fir_lpf_250_9_66;
415 TRACEF(1,("code_string_parse() Rx Filter Freq High\n"));
419 pSps->ncoef=taps_fir_lpf_215_9_88;
421 pSps->coef=(void*)coef_fir_lpf_215_9_88;
422 pSps->nx=taps_fir_lpf_215_9_88;
424 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
425 pSps->calcAdjust=gain_fir_lpf_215_9_88;
426 TRACEF(1,("code_string_parse() Rx Filter Freq Low\n"));
429 if(pChan->b.ctcssRxEnable || pChan->b.dcsRxEnable || pChan->b.lmrRxEnable)
431 pChan->rxCenterSlicerEnable=1;
436 pChan->rxCenterSlicerEnable=0;
441 TRACEF(2,("code_string_parse() ctcssRxEnable = %i \n",pChan->b.ctcssRxEnable));
442 TRACEF(2,(" ctcssTxEnable = %i \n",pChan->b.ctcssTxEnable));
443 TRACEF(2,(" dcsRxEnable = %i \n",pChan->b.dcsRxEnable));
444 TRACEF(2,(" lmrRxEnable = %i \n",pChan->b.lmrRxEnable));
445 TRACEF(2,(" txcodedefaultsmode = %i \n",pChan->txcodedefaultsmode));
446 for(i=0;i<CTCSS_NUM_CODES;i++)
448 TRACEF(2,("rxCtcssMap[%i] = %i \n",i,pChan->rxCtcssMap[i]));
453 lsd_code_parse(pChan,5);
456 TRACEF(1,("code_string_parse(%i) end\n",0));
461 Convert a Frequency in Hz to a zero based CTCSS Table index
463 i16 CtcssFreqIndex(float freq)
465 i16 i,hit=CTCSS_NULL;
467 for(i=0;i<CTCSS_NUM_CODES;i++){
468 if(freq==freq_ctcss[i])hit=i;
474 Takes a block of data and low pass filters it.
475 Determines the amplitude of high frequency noise for carrier detect.
476 Decimates input data to change the rate.
478 i16 pmr_rx_frontend(t_pmr_sps *mySps)
480 #define DCgainBpfNoise 65536
482 i16 samples,iOutput, *input, *output, *noutput;
484 i32 i, naccum, outputGain, calcAdjust;
486 i16 nx, hyst, setpt, compOut;
487 i16 amax, amin, apeak, discounteru, discounterl, discfactor;
488 i16 decimator, decimate, doNoise;
490 TRACEJ(5,("pmr_rx_frontend()\n"));
492 if(!mySps->enabled)return(1);
494 decimator = mySps->decimator;
495 decimate = mySps->decimate;
497 input = mySps->source;
498 output = mySps->sink;
499 noutput = mySps->parentChan->pRxNoise;
504 calcAdjust = mySps->calcAdjust;
505 outputGain = mySps->outputGain;
510 discounteru=mySps->discounteru;
511 discounterl=mySps->discounterl;
512 discfactor=mySps->discfactor;
515 compOut=mySps->compOut;
517 samples=mySps->nSamples*decimate;
521 if(mySps->parentChan->rxCdType!=CD_XPMR_VOX)doNoise=1;
524 for(i=0;i<samples;i++)
528 //shift the old samples
529 for(n=nx-1; n>0; n--)
544 y=((y/calcAdjust)*outputGain)/M_Q8;
547 else if(y<-32767)y=-32767;
549 output[iOutput]=y; // Rx Baseband decimated
550 noutput[iOutput++] = apeak; // Rx Noise
555 // calculate noise output
558 naccum += coef_fir_bpf_noise_1[n] * x[n];
560 naccum /= DCgainBpfNoise;
565 discounteru=discfactor;
567 else if(--discounteru<=0)
569 discounteru=discfactor;
570 amax=(i32)((amax*32700)/32768);
576 discounterl=discfactor;
578 else if(--discounterl<=0)
580 discounterl=discfactor;
581 amin=(i32)((amin*32700)/32768);
591 ((t_pmr_chan *)(mySps->parentChan))->rxRssi=apeak;
593 if(apeak>setpt || (compOut&&(apeak>(setpt-hyst)))) compOut=1;
595 mySps->compOut=compOut;
599 mySps->discounteru=discounteru;
600 mySps->discounterl=discounterl;
606 pmr general purpose fir
607 works on a block of samples
609 i16 pmr_gp_fir(t_pmr_sps *mySps)
611 i32 nsamples,inputGain,outputGain,calcAdjust;
615 i16 nx, hyst, setpt, compOut;
616 i16 amax, amin, apeak=0, discounteru=0, discounterl=0, discfactor;
617 i16 decimator, decimate, interpolate;
618 i16 numChanOut, selChanOut, mixOut, monoOut;
620 TRACEJ(5,("pmr_gp_fir() %i %i\n",mySps->index, mySps->enabled));
622 if(!mySps->enabled)return(1);
624 inputGain = mySps->inputGain;
625 calcAdjust = mySps->calcAdjust;
626 outputGain = mySps->outputGain;
628 input = mySps->source;
629 output = mySps->sink;
634 decimator = mySps->decimator;
635 decimate = mySps->decimate;
636 interpolate = mySps->interpolate;
638 setpt = mySps->setpt;
639 compOut = mySps->compOut;
641 inputGain = mySps->inputGain;
642 outputGain = mySps->outputGain;
643 numChanOut = mySps->numChanOut;
644 selChanOut = mySps->selChanOut;
645 mixOut = mySps->mixOut;
646 monoOut = mySps->monoOut;
651 discfactor=mySps->discfactor;
654 nsamples=mySps->nSamples;
660 for(i=0;i<nsamples;i++)
663 output[(i*2)]=output[(i*2)+1]=0;
665 output[(i*numChanOut)+selChanOut]=0;
671 for(i=0;i<nsamples;i++)
682 for(ix=0;ix<interpolate;ix++)
687 for(n=nx-1; n>0; n--)
689 x[0] = (input[i]*inputGain)/M_Q8;
705 y=((y/calcAdjust)*outputGain)/M_Q8;
709 output[(ii*2)]=output[(ii*2)+1]+=y;
712 output[(ii*numChanOut)+selChanOut]+=y;
717 output[(ii*2)]=output[(ii*2)+1]=y;
720 output[(ii*numChanOut)+selChanOut]=y;
727 // amplitude detector
735 discounteru=discfactor;
737 else if(--discounteru<=0)
739 discounteru=discfactor;
740 amax=(i32)((amax*32700)/32768);
746 discounterl=discfactor;
748 else if(--discounterl<=0)
750 discounterl=discfactor;
751 amin=(i32)((amin*32700)/32768);
754 apeak = (i32)(amax-amin)/2;
756 if(apeak>setpt)compOut=1;
757 else if(compOut&&(apeak<(setpt-hyst)))compOut=0;
761 mySps->decimator = decimator;
766 mySps->discounteru=discounteru;
767 mySps->discounterl=discounterl;
769 mySps->compOut=compOut;
774 general purpose integrator lpf
776 i16 gp_inte_00(t_pmr_sps *mySps)
786 i16 coeff00, coeff01;
788 TRACEJ(5,("gp_inte_00() %i\n",mySps->enabled));
789 if(!mySps->enabled)return(1);
791 input = mySps->source;
792 output = mySps->sink;
794 npoints=mySps->nSamples;
796 outputGain=mySps->outputGain;
798 coeff00=((i16*)mySps->coef)[0];
799 coeff01=((i16*)mySps->coef)[1];
800 state00=((i32*)mySps->x)[0];
802 // note fixed gain of 2 to compensate for attenuation
805 for(i=0;i<npoints;i++)
808 state00 = accum + (state00*coeff01)/M_Q15;
809 accum = (state00*coeff00)/(M_Q15/4);
810 output[i]=(accum*outputGain)/M_Q8;
813 ((i32*)(mySps->x))[0]=state00;
818 general purpose differentiator hpf
820 i16 gp_diff(t_pmr_sps *mySps)
824 i32 outputGain, calcAdjust;
833 input = mySps->source;
834 output = mySps->sink;
836 npoints=mySps->nSamples;
838 outputGain=mySps->outputGain;
839 calcAdjust=mySps->calcAdjust;
841 coef=(i16*)(mySps->coef);
848 TRACEJ(5,("gp_diff()\n"));
850 for (i=0;i<npoints;i++)
854 temp1 = input[i] * a0;
855 _y0 = (temp0 + temp1)/calcAdjust;
856 _y0 = (_y0*outputGain)/M_Q8;
858 if(_y0>32766)_y0=32766;
859 else if(_y0<-32766)_y0=-32766;
867 /* ----------------------------------------------------------------------
870 i16 CenterSlicer(t_pmr_sps *mySps)
872 i16 npoints/*, lhit, uhit*/;
873 i16 *input, *output, *buff;
879 i32 amax; // buffer amplitude maximum
880 i32 amin; // buffer amplitude minimum
881 i32 apeak; // buffer amplitude peak
883 i32 setpt; // amplitude set point for peak tracking
885 i32 discounteru; // amplitude detector integrator discharge counter upper
886 i32 discounterl; // amplitude detector integrator discharge counter lower
887 i32 discfactor; // amplitude detector integrator discharge factor
889 TRACEJ(5,("CenterSlicer() %i\n",mySps->enabled));
890 if(!mySps->enabled)return(1);
892 input = mySps->source;
893 output = mySps->sink; // limited output
896 npoints=mySps->nSamples;
898 inputGainB=mySps->inputGainB;
904 discounteru=mySps->discounteru;
905 discounterl=mySps->discounterl;
907 discfactor=mySps->discfactor;
908 npoints=mySps->nSamples;
910 for(i=0;i<npoints;i++)
923 if(amin<(amax-setpt))
933 if(amax>(amin+setpt))
940 if((discounteru-=1)<=0 && amax>amin)
942 if((amax-=10)<amin)amax=amin;
946 if((discounterl-=1)<=0 && amin<amax)
948 if((amin+=10)>amax)amin=amax;
951 if(uhit)discounteru=discfactor;
952 if(lhit)discounterl=discfactor;
956 if((amax-=discfactor)<amin)amax=amin;
957 if((amin+=discfactor)>amax)amin=amax;
961 apeak = (amax-amin)/2;
962 center = (amax+amin)/2;
963 accum = accum - center;
965 output[i]=accum; // sink output unlimited/centered.
967 // do limiter function
968 if(accum>inputGainB)accum=inputGainB;
969 else if(accum<-inputGainB)accum=-inputGainB;
974 mySps->parentChan->pRxLsdCen[i]=center; // trace center ref
976 if((tfx++/8)&1) // trace min/max levels
977 mySps->parentChan->pRxLsdCen[i]=amax;
979 mySps->parentChan->pRxLsdCen[i]=amin;
982 if(mySps->parentChan->frameCountRx&0x01) mySps->parentChan->prxDebug1[i]=amax;
983 else mySps->parentChan->prxDebug1[i]=amin;
991 mySps->discounteru=discounteru;
992 mySps->discounterl=discounterl;
996 /* ----------------------------------------------------------------------
998 determine peak amplitude
1000 i16 MeasureBlock(t_pmr_sps *mySps)
1003 i16 *input, *output;
1008 i16 amax; // buffer amplitude maximum
1009 i16 amin; // buffer amplitude minimum
1010 i16 apeak=0; // buffer amplitude peak (peak to peak)/2
1011 i16 setpt; // amplitude set point for amplitude comparator
1013 i32 discounteru; // amplitude detector integrator discharge counter upper
1014 i32 discounterl; // amplitude detector integrator discharge counter lower
1015 i32 discfactor; // amplitude detector integrator discharge factor
1017 TRACEJ(5,("MeasureBlock() %i\n",mySps->enabled));
1019 if(!mySps->enabled)return 1;
1021 if(mySps->option==3)
1023 mySps->amax = mySps->amin = mySps->apeak = \
1024 mySps->discounteru = mySps->discounterl = \
1029 input = mySps->source;
1030 output = mySps->sink;
1032 npoints=mySps->nSamples;
1037 discounteru=mySps->discounteru;
1038 discounterl=mySps->discounterl;
1040 discfactor=mySps->discfactor;
1041 npoints=mySps->nSamples;
1043 for(i=0;i<npoints;i++)
1050 discounteru=discfactor;
1052 else if(--discounteru<=0)
1054 discounteru=discfactor;
1055 amax=(i32)((amax*32700)/32768);
1061 discounterl=discfactor;
1063 else if(--discounterl<=0)
1065 discounterl=discfactor;
1066 amin=(i32)((amin*32700)/32768);
1069 apeak = (i32)(amax-amin)/2;
1070 if(output)output[i]=apeak;
1076 mySps->discounteru=discounteru;
1077 mySps->discounterl=discounterl;
1078 if(apeak>=setpt) mySps->compOut=1;
1079 else mySps->compOut=0;
1081 //TRACEX((" -MeasureBlock()=%i\n",mySps->apeak));
1087 i16 SoftLimiter(t_pmr_sps *mySps)
1090 //i16 samples, lhit,uhit;
1091 i16 *input, *output;
1093 i32 /*inputGain, */outputGain;
1098 i32 amax; // buffer amplitude maximum
1099 i32 amin; // buffer amplitude minimum
1100 //i32 apeak; // buffer amplitude peak
1101 i32 setpt; // amplitude set point for amplitude comparator
1103 input = mySps->source;
1104 output = mySps->sink;
1106 /* inputGain=mySps->inputGain; */
1107 outputGain=mySps->outputGain;
1109 npoints=mySps->nSamples;
1112 amax=(setpt*124)/128;
1115 TRACEJ(5,("SoftLimiter() %i %i %i) \n",amin, amax,setpt));
1117 for(i=0;i<npoints;i++)
1120 //accum=input[i]*mySps->inputGain/256;
1124 tmp=((accum-setpt)*4)/128;
1126 if(accum>amax)accum=amax;
1129 else if(accum<-setpt)
1131 tmp=((accum+setpt)*4)/128;
1133 if(accum<amin)accum=amin;
1137 output[i]=(accum*outputGain)/M_Q8;
1143 SigGen() - sine, square function generator
1144 sps overloaded values
1145 discfactor = phase factor
1146 discfactoru = phase index
1147 if source is not NULL then mix it in!
1149 sign table and output gain are in Q15 format (32767=.999)
1151 i16 SigGen(t_pmr_sps *mySps)
1153 #define PH_FRACT_FACT 128
1156 i16 i,outputgain,waveform,numChanOut,selChanOut;
1160 pChan=mySps->parentChan;
1161 TRACEC(5,("SigGen(%i %i %i)\n",mySps->option,mySps->enabled,mySps->state));
1163 if(!mySps->freq ||!mySps->enabled)return 0;
1165 outputgain=mySps->outputGain;
1167 numChanOut=mySps->numChanOut;
1168 selChanOut=mySps->selChanOut;
1170 if(mySps->option==1)
1175 (SAMPLES_PER_SINE*mySps->freq*PH_FRACT_FACT)/mySps->sampleRate/10;
1177 TRACEF(5,(" SigGen() discfactor = %i\n",mySps->discfactor));
1178 if(mySps->discounterl)mySps->state=2;
1180 else if(mySps->option==2)
1182 i16 shiftfactor=CTCSS_TURN_OFF_SHIFT;
1183 // phase shift request
1186 mySps->discounterl=CTCSS_TURN_OFF_TIME-(2*MS_PER_FRAME); //
1188 mySps->discounteru = \
1189 (mySps->discounteru + (((SAMPLES_PER_SINE*shiftfactor)/360)*PH_FRACT_FACT)) % (SAMPLES_PER_SINE*PH_FRACT_FACT);
1190 //printf("shiftfactor = %i\n",shiftfactor);
1193 else if(mySps->option==3)
1195 // stop it and clear the output buffer
1199 for(i=0;i<mySps->nSamples;i++)
1200 mySps->sink[(i*numChanOut)+selChanOut]=0;
1203 else if(mySps->state==2)
1206 mySps->discounterl-=MS_PER_FRAME;
1207 if(mySps->discounterl<=0)
1213 else if(mySps->state==0)
1218 ph=mySps->discounteru;
1220 for(i=0;i<mySps->nSamples;i++)
1225 //tmp=(sinetablex[ph/PH_FRACT_FACT]*amplitude)/M_Q16;
1226 accum=sinetablex[ph/PH_FRACT_FACT];
1227 accum=(accum*outputgain)/M_Q8;
1232 if(ph>SAMPLES_PER_SINE/2)
1233 accum=outputgain/M_Q8;
1235 accum=-outputgain/M_Q8;
1238 if(mySps->source)accum+=mySps->source[i];
1240 mySps->sink[(i*numChanOut)+selChanOut]=accum;
1242 ph=(ph+mySps->discfactor)%(SAMPLES_PER_SINE*PH_FRACT_FACT);
1245 mySps->discounteru=ph;
1251 takes existing buffer and adds source buffer to destination buffer
1252 sink buffer = (sink buffer * gain) + source buffer
1254 i16 pmrMixer(t_pmr_sps *mySps)
1257 i16 i, *input, *inputB, *output;
1258 i16 inputGain, inputGainB; // apply to input data in Q7.8 format
1259 i16 outputGain; // apply to output data in Q7.8 format
1260 i16 discounteru,discounterl,amax,amin,setpt,discfactor;
1261 i16 npoints,uhit,lhit,apeak,measPeak;
1264 pChan=mySps->parentChan;
1265 TRACEF(5,("pmrMixer()\n"));
1267 input = mySps->source;
1268 inputB = mySps->sourceB;
1269 output = mySps->sink;
1271 inputGain=mySps->inputGain;
1272 inputGainB=mySps->inputGainB;
1273 outputGain=mySps->outputGain;
1278 discounteru=mySps->discounteru;
1279 discounterl=mySps->discounteru;
1281 discfactor=mySps->discfactor;
1282 npoints=mySps->nSamples;
1283 measPeak=mySps->measPeak;
1285 for(i=0;i<npoints;i++)
1287 accum = ((input[i]*inputGain)/M_Q8) +
1288 ((inputB[i]*inputGainB)/M_Q8);
1290 accum=(accum*outputGain)/M_Q8;
1299 if(amin<(amax-setpt)){
1304 else if(accum<amin){
1307 if(amax>(amin+setpt)){
1313 if(--discounteru<=0 && amax>0){
1318 if(--discounterl<=0 && amin<0){
1323 if(uhit)discounteru=discfactor;
1324 if(lhit)discounterl=discfactor;
1329 apeak = (amax-amin)/2;
1333 mySps->discounteru=discounteru;
1334 mySps->discounterl=discounterl;
1342 i16 DelayLine(t_pmr_sps *mySps)
1344 i16 *input, *output, *buff;
1345 i16 i, npoints,buffsize,inindex,outindex;
1348 pChan=mySps->parentChan;
1349 TRACEF(5,(" DelayLine() %i\n",mySps->enabled));
1351 input = mySps->source;
1352 output = mySps->sink;
1353 buff = (i16*)(mySps->buff);
1354 buffsize = mySps->buffSize;
1355 npoints = mySps->nSamples;
1357 outindex = mySps->buffOutIndex;
1358 inindex = outindex + mySps->buffLead;
1360 for(i=0;i<npoints;i++)
1362 inindex %= buffsize;
1363 outindex %= buffsize;
1365 buff[inindex]=input[i];
1366 output[i]=buff[outindex];
1370 mySps->buffOutIndex=outindex;
1375 Continuous Tone Coded Squelch (CTCSS) Detector
1377 i16 ctcss_detect(t_pmr_chan *pChan)
1379 i16 i,points2do,*pInput,hit,thit,relax;
1380 i16 tnum, tmp,indexNow,diffpeak;
1382 i16 tv0,tv1,tv2,tv3,indexDebug;
1386 TRACEF(5,("ctcss_detect(%p) %i %i %i %i\n",pChan,
1387 pChan->rxCtcss->enabled,
1389 pChan->rxCtcss->testIndex,
1390 pChan->rxCtcss->decode));
1392 if(!pChan->rxCtcss->enabled)return(1);
1394 relax = pChan->rxCtcss->relax;
1395 pInput = pChan->rxCtcss->input;
1398 if(relax) difftrig=(-0.1*M_Q15);
1399 else difftrig=(-0.05*M_Q15);
1404 //TRACEX((" ctcss_detect() %i %i %i %i\n", CTCSS_NUM_CODES,0,0,0));
1406 for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++)
1413 TRACEF(6,(" ctcss_detect() tnum=%i %i\n",tnum,pChan->rxCtcssMap[tnum]));
1414 //if(tnum==14)printf("ctcss_detect() %i %i %i\n",tnum,pChan->rxCtcssMap[tnum], pChan->rxCtcss->decode );
1416 if( (pChan->rxCtcssMap[tnum]==CTCSS_NULL) ||
1417 (pChan->rxCtcss->decode>CTCSS_NULL && (tnum!= pChan->rxCtcss->decode))
1421 TRACEF(6,(" ctcss_detect() tnum=%i\n",tnum));
1423 ptdet=&(pChan->rxCtcss->tdet[tnum]);
1425 points=points2do=pChan->nSamplesRx;
1426 fudgeFactor=ptdet->fudgeFactor;
1427 binFactor=ptdet->binFactor;
1429 while(ptdet->counter < (points2do*CTCSS_SCOUNT_MUL))
1431 tmp=(ptdet->counter/CTCSS_SCOUNT_MUL)+1;
1432 ptdet->counter-=(tmp*CTCSS_SCOUNT_MUL);
1434 indexNow=points-points2do;
1436 ptdet->counter += ptdet->counterFactor;
1438 accum = pInput[indexNow-1]; // duuuude's major bug fix!
1440 ptdet->z[ptdet->zIndex]+=
1441 (((accum - ptdet->z[ptdet->zIndex])*binFactor)/M_Q15);
1443 peak = abs(ptdet->z[0]-ptdet->z[2]) + abs(ptdet->z[1]-ptdet->z[3]);
1445 if (ptdet->peak < peak)
1446 ptdet->peak += ( ((peak-ptdet->peak)*binFactor)/M_Q15);
1451 static const i16 a0=13723;
1452 static const i16 a1=-13723;
1459 ptdet->zd = ptdet->peak;
1460 temp1 = ptdet->peak * a0;
1461 diffpeak = (temp0 + temp1)/1024;
1464 if(diffpeak<(-0.03*M_Q15))ptdet->dvd-=4;
1465 else if(ptdet->dvd<0)ptdet->dvd++;
1467 if((ptdet->dvd < -12) && diffpeak > (-0.02*M_Q15))ptdet->dvu+=2;
1468 else if(ptdet->dvu)ptdet->dvu--;
1471 if(pChan->rxCtcss->decode==tnum)
1473 if(relax)tmp=(tmp*55)/100;
1474 else tmp=(tmp*80)/100;
1477 if(ptdet->peak > tmp)
1479 if(ptdet->decode<(fudgeFactor*32))ptdet->decode++;
1481 else if(pChan->rxCtcss->decode==tnum)
1483 if(ptdet->peak > ptdet->hyst)ptdet->decode--;
1484 else if(relax) ptdet->decode--;
1485 else ptdet->decode-=4;
1492 if((pChan->rxCtcss->decode==tnum) && !relax && (ptdet->dvu > (0.00075*M_Q15)))
1495 ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=ptdet->dvu=0;
1496 TRACEF(4,("ctcss_detect() turnoff detected by dvdt for tnum = %i.\n",tnum));
1499 if(ptdet->decode<0 || !pChan->rxCarrierDetect)ptdet->decode=0;
1501 if(ptdet->decode>=fudgeFactor)
1504 if(pChan->rxCtcss->decode!=tnum)
1506 ptdet->zd=ptdet->dvu=ptdet->dvd=0;
1510 #if XPMR_DEBUG0 == 1
1511 if(thit>=0 && thit==tnum)
1512 TRACEF(6,(" ctcss_detect() %i %i %i %i \n",tnum,ptdet->peak,ptdet->setpt,ptdet->hyst));
1523 ptdet->lasttv0=ptdet->pDebug0[points-1];
1524 ptdet->lasttv1=ptdet->pDebug1[points-1];
1525 ptdet->lasttv2=ptdet->pDebug2[points-1];
1526 ptdet->lasttv3=ptdet->pDebug3[points-1];
1529 while(indexDebug<indexNow)
1531 ptdet->pDebug0[indexDebug]=ptdet->lasttv0;
1532 ptdet->pDebug1[indexDebug]=ptdet->lasttv1;
1533 ptdet->pDebug2[indexDebug]=ptdet->lasttv2;
1534 ptdet->pDebug3[indexDebug]=ptdet->lasttv3;
1544 ptdet->zIndex=(ptdet->zIndex + 1) % 4;
1546 ptdet->counter-=(points2do*CTCSS_SCOUNT_MUL);
1548 #if XPMR_DEBUG0 == 1
1549 for(i=indexWas;i<points;i++)
1551 ptdet->pDebug0[i]=ptdet->lasttv0;
1552 ptdet->pDebug1[i]=ptdet->lasttv1;
1553 ptdet->pDebug2[i]=ptdet->lasttv2;
1554 ptdet->pDebug3[i]=ptdet->lasttv3;
1559 //TRACEX((" ctcss_detect() thit %i\n",thit));
1561 if(pChan->rxCtcss->BlankingTimer>0)pChan->rxCtcss->BlankingTimer-=points;
1562 if(pChan->rxCtcss->BlankingTimer<0)pChan->rxCtcss->BlankingTimer=0;
1564 if(thit>CTCSS_NULL && pChan->rxCtcss->decode<=CTCSS_NULL && !pChan->rxCtcss->BlankingTimer)
1566 pChan->rxCtcss->decode=thit;
1567 sprintf(pChan->rxctcssfreq,"%.1f",freq_ctcss[thit]);
1568 TRACEC(1,("ctcss decode %i %.1f\n",thit,freq_ctcss[thit]));
1570 else if(thit<=CTCSS_NULL && pChan->rxCtcss->decode>CTCSS_NULL)
1572 pChan->rxCtcss->BlankingTimer=SAMPLE_RATE_NETWORK/5;
1573 pChan->rxCtcss->decode=CTCSS_NULL;
1574 strcpy(pChan->rxctcssfreq,"0");
1575 TRACEC(1,("ctcss decode NULL\n"));
1576 for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++)
1579 ptdet=&(pChan->rxCtcss->tdet[tnum]);
1581 ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=0;
1584 //TRACEX((" ctcss_detect() thit %i %i\n",thit,pChan->rxCtcss->decode));
1590 static i16 TxTestTone(t_pmr_chan *pChan, i16 function)
1594 pChan->spsSigGen1->enabled=1;
1595 pChan->spsSigGen1->option=1;
1596 pChan->spsSigGen1->outputGain=(.23125*M_Q8); // to match *99 level
1597 pChan->spsTx->source=pChan->spsSigGen1->sink;
1601 pChan->spsSigGen1->option=3;
1607 sampling rate is 48KS/s
1608 samples are all 16 bits
1609 samples are filtered and decimated by 1/6th
1611 t_pmr_chan *createPmrChannel(t_pmr_chan *tChan, i16 numSamples)
1616 t_dec_ctcss *pDecCtcss;
1618 TRACEJ(1,("createPmrChannel(%p,%i)\n",tChan,numSamples));
1620 pChan = (t_pmr_chan *)calloc(sizeof(t_pmr_chan),1);
1623 printf("createPmrChannel() failed\n");
1631 pChan->index=pmrChanIndex++;
1632 pChan->nSamplesTx=pChan->nSamplesRx=numSamples;
1634 pDecCtcss = (t_dec_ctcss *)calloc(sizeof(t_dec_ctcss),1);
1635 pChan->rxCtcss=pDecCtcss;
1636 pChan->rxctcssfreq[0]=0;
1639 if(tChan->rptnum>=LSD_CHAN_MAX)tChan->rptnum=0;
1644 printf("createPmrChannel() WARNING: NULL tChan!\n");
1645 pChan->rxNoiseSquelchEnable=0;
1646 pChan->rxHpfEnable=0;
1647 pChan->rxDeEmpEnable=0;
1648 pChan->rxCenterSlicerEnable=0;
1649 pChan->rxCtcssDecodeEnable=0;
1650 pChan->rxDcsDecodeEnable=0;
1652 pChan->rxCarrierPoint = 17000;
1653 pChan->rxCarrierHyst = 2500;
1655 pChan->txHpfEnable=0;
1656 pChan->txLimiterEnable=0;
1657 pChan->txPreEmpEnable=0;
1658 pChan->txLpfEnable=1;
1659 pChan->txMixA=TX_OUT_VOICE;
1660 pChan->txMixB=TX_OUT_LSD;
1664 pChan->rxDemod=tChan->rxDemod;
1665 pChan->rxCdType=tChan->rxCdType;
1666 pChan->rxSquelchPoint = tChan->rxSquelchPoint;
1667 pChan->rxCarrierHyst = 3000;
1668 pChan->rxSqVoxAdj=tChan->rxSqVoxAdj;
1670 pChan->txMod=tChan->txMod;
1671 pChan->txHpfEnable=1;
1672 pChan->txLpfEnable=1;
1674 pChan->pTxCodeDefault=tChan->pTxCodeDefault;
1675 pChan->pRxCodeSrc=tChan->pRxCodeSrc;
1676 pChan->pTxCodeSrc=tChan->pTxCodeSrc;
1678 pChan->txMixA=tChan->txMixA;
1679 pChan->txMixB=tChan->txMixB;
1680 pChan->radioDuplex=tChan->radioDuplex;
1681 pChan->area=tChan->area;
1682 pChan->rptnum=tChan->rptnum;
1683 pChan->idleinterval=tChan->idleinterval;
1684 pChan->turnoffs=tChan->turnoffs;
1685 pChan->b.rxpolarity=tChan->b.rxpolarity;
1686 pChan->b.txpolarity=tChan->b.txpolarity;
1687 pChan->b.dcsrxpolarity=tChan->b.dcsrxpolarity;
1688 pChan->b.dcstxpolarity=tChan->b.dcstxpolarity;
1689 pChan->b.lsdrxpolarity=tChan->b.lsdrxpolarity;
1690 pChan->b.lsdtxpolarity=tChan->b.lsdtxpolarity;
1692 pChan->txsettletime=tChan->txsettletime;
1693 pChan->tracelevel=tChan->tracelevel;
1694 pChan->tracetype=tChan->tracetype;
1695 pChan->ukey=tChan->ukey;
1696 pChan->name=tChan->name;
1700 pChan->txHpfEnable=1;
1701 pChan->txLpfEnable=1;
1703 if(pChan->rxCdType==CD_XPMR_NOISE) pChan->rxNoiseSquelchEnable=1;
1705 if(pChan->rxDemod==RX_AUDIO_FLAT) pChan->rxDeEmpEnable=1;
1707 pChan->rxCarrierPoint=(pChan->rxSquelchPoint*32767)/100;
1708 pChan->rxCarrierHyst = 3000; //pChan->rxCarrierPoint/15;
1710 pChan->rxDcsDecodeEnable=0;
1712 if(pChan->b.ctcssRxEnable || pChan->b.dcsRxEnable || pChan->b.lmrRxEnable)
1714 pChan->rxHpfEnable=1;
1715 pChan->rxCenterSlicerEnable=1;
1716 pChan->rxCtcssDecodeEnable=1;
1720 pChan->txPreEmpEnable=1;
1721 pChan->txLimiterEnable=1;
1727 TRACEF(1,("calloc buffers \n"));
1729 pChan->pRxDemod = calloc(numSamples,2);
1730 pChan->pRxNoise = calloc(numSamples,2);
1731 pChan->pRxBase = calloc(numSamples,2);
1732 pChan->pRxHpf = calloc(numSamples,2);
1733 pChan->pRxLsd = calloc(numSamples,2);
1734 pChan->pRxSpeaker = calloc(numSamples,2);
1735 pChan->pRxCtcss = calloc(numSamples,2);
1736 pChan->pRxDcTrack = calloc(numSamples,2);
1737 pChan->pRxLsdLimit = calloc(numSamples,2);
1739 pChan->pTxInput = calloc(numSamples,2);
1740 pChan->pTxBase = calloc(numSamples,2);
1741 pChan->pTxHpf = calloc(numSamples,2);
1742 pChan->pTxPreEmp = calloc(numSamples,2);
1743 pChan->pTxLimiter = calloc(numSamples,2);
1744 pChan->pTxLsd = calloc(numSamples,2);
1745 pChan->pTxLsdLpf = calloc(numSamples,2);
1746 pChan->pTxComposite = calloc(numSamples,2);
1747 pChan->pSigGen0 = calloc(numSamples,2);
1748 pChan->pSigGen1 = calloc(numSamples,2);
1750 pChan->prxMeasure = calloc(numSamples,2);
1752 pChan->pTxOut = calloc(numSamples,2*2*6); // output buffer
1755 pChan->pLsdEnc = calloc(sizeof(t_encLsd),1);
1758 #if XPMR_DEBUG0 == 1
1759 TRACEF(1,("configure tracing\n"));
1761 pChan->pTstTxOut = calloc(numSamples,2);
1762 pChan->pRxLsdCen = calloc(numSamples,2);
1763 pChan->prxDebug0 = calloc(numSamples,2);
1764 pChan->prxDebug1 = calloc(numSamples,2);
1765 pChan->prxDebug2 = calloc(numSamples,2);
1766 pChan->prxDebug3 = calloc(numSamples,2);
1767 pChan->ptxDebug0 = calloc(numSamples,2);
1768 pChan->ptxDebug1 = calloc(numSamples,2);
1769 pChan->ptxDebug2 = calloc(numSamples,2);
1770 pChan->ptxDebug3 = calloc(numSamples,2);
1771 pChan->pNull = calloc(numSamples,2);
1773 for(i=0;i<numSamples;i++)pChan->pNull[i]=((i%(numSamples/2))*8000)-4000;
1775 pChan->rxCtcss->pDebug0=calloc(numSamples,2);
1776 pChan->rxCtcss->pDebug1=calloc(numSamples,2);
1777 pChan->rxCtcss->pDebug2=calloc(numSamples,2);
1778 pChan->rxCtcss->pDebug3=calloc(numSamples,2);
1780 for(i=0;i<CTCSS_NUM_CODES;i++)
1782 pChan->rxCtcss->tdet[i].pDebug0=calloc(numSamples,2);
1783 pChan->rxCtcss->tdet[i].pDebug1=calloc(numSamples,2);
1784 pChan->rxCtcss->tdet[i].pDebug2=calloc(numSamples,2);
1785 pChan->rxCtcss->tdet[i].pDebug3=calloc(numSamples,2);
1788 // buffer, 2 bytes per sample, and 16 channels
1789 pChan->prxDebug=calloc(numSamples*16,2);
1790 pChan->ptxDebug=calloc(numSamples*16,2);
1792 // TSCOPE CONFIGURATION SETSCOPE configure debug traces and sources for each channel of the output
1793 pChan->sdbg = (t_sdbg *)calloc(sizeof(t_sdbg),1);
1795 for(i=0;i<XPMR_DEBUG_CHANS;i++)pChan->sdbg->trace[i]=-1;
1797 TRACEF(1,("pChan->tracetype = %i\n",pChan->tracetype));
1799 if(pChan->tracetype==1) // CTCSS DECODE
1801 pChan->sdbg->source [0]=pChan->pRxDemod;
1802 pChan->sdbg->source [1]=pChan->pRxBase;
1803 pChan->sdbg->source [2]=pChan->pRxNoise;
1804 pChan->sdbg->trace [3]=RX_NOISE_TRIG;
1805 pChan->sdbg->source [4]=pChan->pRxLsd;
1806 pChan->sdbg->source [5]=pChan->pRxLsdCen;
1807 pChan->sdbg->source [6]=pChan->pRxLsdLimit;
1808 pChan->sdbg->source [7]=pChan->rxCtcss->tdet[3].pDebug0;
1809 pChan->sdbg->trace [8]=RX_CTCSS_DECODE;
1810 pChan->sdbg->trace [9]=RX_SMODE;
1812 if(pChan->tracetype==2) // CTCSS DECODE
1814 pChan->sdbg->source [0]=pChan->pRxDemod;
1815 pChan->sdbg->source [1]=pChan->pRxBase;
1816 pChan->sdbg->trace [2]=RX_NOISE_TRIG;
1817 pChan->sdbg->source [3]=pChan->pRxLsd;
1818 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1819 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1820 pChan->sdbg->source [6]=pChan->pRxLsdLimit;
1821 pChan->sdbg->source [7]=pChan->rxCtcss->tdet[3].pDebug0;
1822 pChan->sdbg->source [8]=pChan->rxCtcss->tdet[3].pDebug1;
1823 pChan->sdbg->source [9]=pChan->rxCtcss->tdet[3].pDebug2;
1824 pChan->sdbg->source [10]=pChan->rxCtcss->tdet[3].pDebug3;
1825 pChan->sdbg->trace [11]=RX_CTCSS_DECODE;
1826 pChan->sdbg->trace [12]=RX_SMODE;
1827 pChan->sdbg->trace [13]=TX_PTT_IN;
1828 pChan->sdbg->trace [14]=TX_PTT_OUT;
1829 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1831 else if(pChan->tracetype==3) // DCS DECODE
1833 pChan->sdbg->source [0]=pChan->pRxDemod;
1834 pChan->sdbg->source [1]=pChan->pRxBase;
1835 pChan->sdbg->trace [2]=RX_NOISE_TRIG;
1836 pChan->sdbg->source [3]=pChan->pRxLsd;
1837 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1838 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1839 pChan->sdbg->trace [6]=RX_DCS_CLK;
1840 pChan->sdbg->trace [7]=RX_DCS_DIN;
1841 pChan->sdbg->trace [8]=RX_DCS_DEC;
1842 pChan->sdbg->trace [9]=RX_SMODE;
1843 pChan->sdbg->trace [10]=TX_PTT_IN;
1844 pChan->sdbg->trace [11]=TX_PTT_OUT;
1845 pChan->sdbg->trace [12]=TX_LSD_CLK;
1846 pChan->sdbg->trace [13]=TX_LSD_DAT;
1847 pChan->sdbg->trace [14]=TX_LSD_GEN;
1848 pChan->sdbg->source [14]=pChan->pTxLsd;
1849 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1851 else if(pChan->tracetype==4) // LSD DECODE
1853 pChan->sdbg->source [0]=pChan->pRxDemod;
1854 pChan->sdbg->source [1]=pChan->pRxBase;
1855 pChan->sdbg->trace [2]=RX_NOISE_TRIG;
1856 pChan->sdbg->source [3]=pChan->pRxLsd;
1857 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1858 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1859 pChan->sdbg->trace [6]=RX_LSD_CLK;
1860 pChan->sdbg->trace [7]=RX_LSD_DAT;
1861 pChan->sdbg->trace [8]=RX_LSD_ERR;
1862 pChan->sdbg->trace [9]=RX_LSD_SYNC;
1863 pChan->sdbg->trace [10]=RX_SMODE;
1864 pChan->sdbg->trace [11]=TX_PTT_IN;
1865 pChan->sdbg->trace [12]=TX_PTT_OUT;
1866 pChan->sdbg->trace [13]=TX_LSD_CLK;
1867 pChan->sdbg->trace [14]=TX_LSD_DAT;
1868 //pChan->sdbg->trace [14]=TX_LSD_GEN;
1869 //pChan->sdbg->source [14]=pChan->pTxLsd;
1870 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1872 else if(pChan->tracetype==5) // LSD LOGIC
1874 pChan->sdbg->source [0]=pChan->pRxBase;
1875 pChan->sdbg->trace [1]=RX_NOISE_TRIG;
1876 pChan->sdbg->source [2]=pChan->pRxDcTrack;
1877 pChan->sdbg->trace [3]=RX_LSD_SYNC;
1878 pChan->sdbg->trace [4]=RX_SMODE;
1879 pChan->sdbg->trace [5]=TX_PTT_IN;
1880 pChan->sdbg->trace [6]=TX_PTT_OUT;
1881 pChan->sdbg->source [7]=pChan->pTxLsdLpf;
1883 else if(pChan->tracetype==6)
1885 // tx clock skew and jitter buffer
1886 pChan->sdbg->source [0]=pChan->pRxDemod;
1887 pChan->sdbg->source [5]=pChan->pTxBase;
1888 pChan->sdbg->trace [6]=TX_DEDRIFT_LEAD;
1889 pChan->sdbg->trace [7]=TX_DEDRIFT_ERR;
1890 pChan->sdbg->trace [8]=TX_DEDRIFT_FACTOR;
1891 pChan->sdbg->trace [9]=TX_DEDRIFT_DRIFT;
1893 else if(pChan->tracetype==7)
1896 pChan->sdbg->source [0]=pChan->pRxBase;
1897 pChan->sdbg->trace [1]=RX_NOISE_TRIG;
1898 pChan->sdbg->source [2]=pChan->pRxLsd;
1899 pChan->sdbg->trace [3]=RX_CTCSS_DECODE;
1900 pChan->sdbg->source [4]=pChan->pRxHpf;
1902 pChan->sdbg->trace [5]=TX_PTT_IN;
1903 pChan->sdbg->trace [6]=TX_PTT_OUT;
1905 pChan->sdbg->source [7]=pChan->pTxBase;
1906 pChan->sdbg->source [8]=pChan->pTxHpf;
1907 pChan->sdbg->source [9]=pChan->pTxPreEmp;
1908 pChan->sdbg->source [10]=pChan->pTxLimiter;
1909 pChan->sdbg->source [11]=pChan->pTxComposite;
1910 pChan->sdbg->source [12]=pChan->pTxLsdLpf;
1913 for(i=0;i<XPMR_DEBUG_CHANS;i++){
1914 if(pChan->sdbg->trace[i]>=0)pChan->sdbg->point[pChan->sdbg->trace[i]]=i;
1916 pChan->sdbg->mode=1;
1921 pSps=pChan->spsLsdGen=createPmrSps(pChan);
1923 pSps->sink=pChan->pTxLsd;
1926 pSps->sigProc=LsdGen;
1927 pSps->nSamples=pChan->nSamplesTx;
1928 pSps->outputGain=(.25*M_Q8);
1930 pSps->interpolate=1;
1935 // General Purpose Function Generator
1936 pSps=pChan->spsSigGen1=createPmrSps(pChan);
1937 pSps->sink=pChan->pSigGen1;
1940 pSps->sigProc=SigGen;
1941 pSps->nSamples=pChan->nSamplesTx;
1942 pSps->sampleRate=SAMPLE_RATE_NETWORK;
1943 pSps->freq=10000; // in increments of 0.1 Hz
1944 pSps->outputGain=(.25*M_Q8);
1946 pSps->interpolate=1;
1952 pSps = pChan->spsSigGen0 = createPmrSps(pChan);
1953 pSps->sink=pChan->pTxLsd;
1954 pSps->sigProc=SigGen;
1957 pSps->nSamples=pChan->nSamplesTx;
1958 pSps->sampleRate=SAMPLE_RATE_NETWORK;
1959 pSps->freq=1000; // in 0.1 Hz steps
1960 pSps->outputGain=(0.5*M_Q8);
1962 pSps->interpolate=1;
1966 // Tx LSD Low Pass Filter
1967 pSps=pChan->spsTxLsdLpf=createPmrSps(pChan);
1968 pSps->source=pChan->pTxLsd;
1969 pSps->sink=pChan->pTxLsdLpf;
1970 pSps->sigProc=pmr_gp_fir;
1974 pSps->nSamples=pChan->nSamplesTx;
1975 pSps->decimator=pSps->decimate=1;
1976 pSps->interpolate=1;
1977 pSps->inputGain=(1*M_Q8);
1978 pSps->outputGain=(1*M_Q8);
1980 // configure the longer, lower cutoff filter by default
1981 pSps->ncoef=taps_fir_lpf_215_9_88;
1983 pSps->coef=(void*)coef_fir_lpf_215_9_88;
1984 pSps->nx=taps_fir_lpf_215_9_88;
1986 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
1987 pSps->calcAdjust=gain_fir_lpf_215_9_88;
1989 pSps->inputGain=(1*M_Q8);
1990 pSps->outputGain=(1*M_Q8);
1992 TRACEF(1,("spsTxLsdLpf = sps \n"));
1994 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
1998 TRACEF(1,("create rx\n"));
2001 // allocate space for first sps and set pointers
2002 pSps=pChan->spsRx=createPmrSps(pChan);
2003 pSps->source=NULL; //set when called
2004 pSps->sink=pChan->pRxBase;
2005 pSps->sigProc=pmr_rx_frontend;
2007 pSps->decimator=pSps->decimate=6;
2008 pSps->interpolate=1;
2009 pSps->nSamples=pChan->nSamplesRx;
2010 pSps->ncoef=taps_fir_bpf_noise_1;
2012 pSps->coef=(void*)coef_fir_lpf_3K_1;
2013 pSps->coef2=(void*)coef_fir_bpf_noise_1;
2014 pSps->nx=taps_fir_bpf_noise_1;
2016 pSps->x=(void*)(calloc(pSps->nx,pSps->size_coef));
2017 pSps->calcAdjust=(gain_fir_lpf_3K_1*256)/0x0100;
2018 pSps->outputGain=(1.0*M_Q8);
2020 pSps->hyst=pChan->rxCarrierHyst;
2021 pSps->setpt=pChan->rxCarrierPoint;
2022 pChan->prxSquelchAdjust=&pSps->setpt;
2023 #if XPMR_DEBUG0 == 1
2024 pSps->debugBuff0=pChan->pRxDemod;
2025 pSps->debugBuff1=pChan->pRxNoise;
2026 pSps->debugBuff2=pChan->prxDebug0;
2030 // allocate space for next sps and set pointers
2031 // Rx SubAudible Decoder Low Pass Filter
2032 pSps=pChan->spsRxLsd=pSps->nextSps=createPmrSps(pChan);
2033 pSps->source=pChan->pRxBase;
2034 pSps->sink=pChan->pRxLsd;
2035 pSps->sigProc=pmr_gp_fir;
2039 pSps->nSamples=pChan->nSamplesRx;
2040 pSps->decimator=pSps->decimate=1;
2041 pSps->interpolate=1;
2043 // configure the the larger, lower cutoff filter by default
2044 pSps->ncoef=taps_fir_lpf_215_9_88;
2046 pSps->coef=(void*)coef_fir_lpf_215_9_88;
2047 pSps->nx=taps_fir_lpf_215_9_88;
2049 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2050 pSps->calcAdjust=gain_fir_lpf_215_9_88;
2052 pSps->inputGain=(1*M_Q8);
2053 pSps->outputGain=(1*M_Q8);
2054 pChan->prxCtcssMeasure=pSps->sink;
2055 pChan->prxCtcssAdjust=&(pSps->outputGain);
2057 // CTCSS CenterSlicer
2058 pSps=pChan->spsRxLsdNrz=pSps->nextSps=createPmrSps(pChan);
2059 pSps->source=pChan->pRxLsd;
2060 pSps->sink=pChan->pRxDcTrack;
2061 pSps->buff=pChan->pRxLsdLimit;
2062 pSps->sigProc=CenterSlicer;
2063 pSps->nSamples=pChan->nSamplesRx;
2064 pSps->discfactor=LSD_DFS; // centering time constant
2065 pSps->inputGain=(1*M_Q8);
2066 pSps->outputGain=(1*M_Q8);
2067 pSps->setpt=4900; // ptp clamp for DC centering
2068 pSps->inputGainB=625; // peak output limiter clip point
2073 pSps=pSps->nextSps=createPmrSps(pChan);
2074 pChan->spsRxHpf=pSps;
2075 pSps->source=pChan->pRxBase;
2076 pSps->sink=pChan->pRxHpf;
2077 pSps->sigProc=pmr_gp_fir;
2081 pSps->nSamples=pChan->nSamplesRx;
2082 pSps->decimator=pSps->decimate=1;
2083 pSps->interpolate=1;
2084 pSps->ncoef=taps_fir_hpf_300_9_66;
2086 pSps->coef=(void*)coef_fir_hpf_300_9_66;
2087 pSps->nx=taps_fir_hpf_300_9_66;
2089 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2090 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2091 pSps->calcAdjust=gain_fir_hpf_300_9_66;
2092 pSps->inputGain=(1*M_Q8);
2093 pSps->outputGain=(1*M_Q8);
2094 pChan->prxVoiceAdjust=&(pSps->outputGain);
2095 pChan->spsRxOut=pSps;
2097 // allocate space for next sps and set pointers
2099 if(pChan->rxDeEmpEnable){
2100 pSps=pSps->nextSps=createPmrSps(pChan);
2101 pChan->spsRxDeEmp=pSps;
2102 pSps->source=pChan->pRxHpf;
2103 pSps->sink=pChan->pRxSpeaker;
2104 pChan->spsRxOut=pSps; // OUTPUT STRUCTURE!
2105 pSps->sigProc=gp_inte_00;
2107 pSps->nSamples=pChan->nSamplesRx;
2109 pSps->ncoef=taps_int_lpf_300_1_2;
2111 pSps->coef=(void*)coef_int_lpf_300_1_2;
2113 pSps->nx=taps_int_lpf_300_1_2;
2115 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2116 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2117 pSps->calcAdjust=gain_int_lpf_300_1_2/2;
2118 pSps->inputGain=(1.0*M_Q8);
2119 pSps->outputGain=(1.0*M_Q8);
2120 pChan->prxVoiceMeasure=pSps->sink;
2121 pChan->prxVoiceAdjust=&(pSps->outputGain);
2124 if(pChan->rxDelayLineEnable)
2126 TRACEF(1,("create delayline\n"));
2127 pSps=pChan->spsDelayLine=pSps->nextSps=createPmrSps(pChan);
2128 pSps->sigProc=DelayLine;
2129 pSps->source=pChan->pRxSpeaker;
2130 pSps->sink=pChan->pRxSpeaker;
2132 pSps->inputGain=1*M_Q8;
2133 pSps->outputGain=1*M_Q8;
2134 pSps->nSamples=pChan->nSamplesRx;
2135 pSps->buffSize=4096;
2136 pSps->buff=calloc(4096,2); // one second maximum
2137 pSps->buffLead = (SAMPLE_RATE_NETWORK*0.100);
2138 pSps->buffOutIndex=0;
2141 if(pChan->rxCdType==CD_XPMR_VOX)
2143 TRACEF(1,("create vox measureblock\n"));
2144 pChan->prxVoxMeas=calloc(pChan->nSamplesRx,2);
2146 pSps=pChan->spsRxVox=pSps->nextSps=createPmrSps(pChan);
2147 pSps->sigProc=MeasureBlock;
2148 pSps->parentChan=pChan;
2149 pSps->source=pChan->pRxBase;
2150 pSps->sink=pChan->prxVoxMeas;
2151 pSps->inputGain=1*M_Q8;
2152 pSps->outputGain=1*M_Q8;
2153 pSps->nSamples=pChan->nSamplesRx;
2155 if(pChan->rxSqVoxAdj==0)
2156 pSps->setpt=(0.011*M_Q15);
2158 pSps->setpt=(pChan->rxSqVoxAdj);
2159 pSps->hyst=(pSps->setpt/10);
2163 // tuning measure block
2164 pSps=pChan->spsMeasure=pSps->nextSps=createPmrSps(pChan);
2165 pSps->source=pChan->spsRx->sink;
2166 pSps->sink=pChan->prxMeasure;
2167 pSps->sigProc=MeasureBlock;
2169 pSps->nSamples=pChan->nSamplesRx;
2170 pSps->discfactor=10;
2172 pSps->nextSps=NULL; // last sps in chain RX
2175 // CREATE TRANSMIT CHAIN
2176 TRACEF(1,("create tx\n"));
2180 // allocate space for first sps and set pointers
2182 // Tx HPF SubAudible
2183 if(pChan->txHpfEnable)
2185 pSps=createPmrSps(pChan);
2187 pSps->source=pChan->pTxBase;
2188 pSps->sink=pChan->pTxHpf;
2189 pSps->sigProc=pmr_gp_fir;
2193 pSps->nSamples=pChan->nSamplesTx;
2194 pSps->decimator=pSps->decimate=1;
2195 pSps->interpolate=1;
2196 pSps->ncoef=taps_fir_hpf_300_9_66;
2198 pSps->coef=(void*)coef_fir_hpf_300_9_66;
2199 pSps->nx=taps_fir_hpf_300_9_66;
2201 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2202 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2203 pSps->calcAdjust=gain_fir_hpf_300_9_66;
2204 pSps->inputGain=(1*M_Q8);
2205 pSps->outputGain=(1*M_Q8);
2206 inputTmp=pChan->pTxHpf;
2210 if(pChan->txPreEmpEnable)
2212 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2213 else pSps=pSps->nextSps=createPmrSps(pChan);
2215 pSps->source=inputTmp;
2216 pSps->sink=pChan->pTxPreEmp;
2218 pSps->sigProc=gp_diff;
2220 pSps->nSamples=pChan->nSamplesTx;
2222 pSps->ncoef=taps_int_hpf_4000_1_2;
2224 pSps->coef=(void*)coef_int_hpf_4000_1_2;
2226 pSps->nx=taps_int_hpf_4000_1_2;
2228 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2229 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2231 pSps->calcAdjust=gain_int_hpf_4000_1_2;
2232 pSps->inputGain=(1*M_Q8);
2233 pSps->outputGain=(1*M_Q8); // to match flat at 1KHz
2234 inputTmp=pSps->sink;
2238 if(pChan->txLimiterEnable)
2240 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2241 else pSps=pSps->nextSps=createPmrSps(pChan);
2242 pSps->source=inputTmp;
2243 pSps->sink=pChan->pTxLimiter;
2244 pSps->sigProc=SoftLimiter;
2246 pSps->nSamples=pChan->nSamplesTx;
2247 pSps->inputGain=(1*M_Q8);
2248 pSps->outputGain=(1*M_Q8);
2250 inputTmp=pSps->sink;
2253 // Composite Mix of Voice and LSD
2254 if((pChan->txMixA==TX_OUT_COMPOSITE)||(pChan->txMixB==TX_OUT_COMPOSITE))
2257 pSps=pChan->spsTx=createPmrSps(pChan);
2259 pSps=pSps->nextSps=createPmrSps(pChan);
2260 pSps->source=inputTmp;
2261 pSps->sourceB=pChan->pTxLsdLpf; //asdf ??? !!! maw pTxLsdLpf
2262 pSps->sink=pChan->pTxComposite;
2263 pSps->sigProc=pmrMixer;
2265 pSps->nSamples=pChan->nSamplesTx;
2266 pSps->inputGain=2*M_Q8;
2267 pSps->inputGainB=1*M_Q8/8;
2268 pSps->outputGain=1*M_Q8;
2270 inputTmp=pSps->sink;
2271 pChan->ptxCtcssAdjust=&pSps->inputGainB;
2274 // Chan A Upsampler and Filter
2275 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2276 else pSps=pSps->nextSps=createPmrSps(pChan);
2278 pChan->spsTxOutA=pSps;
2279 if(!pChan->spsTx)pChan->spsTx=pSps;
2281 if(pChan->txMixA==TX_OUT_COMPOSITE)
2283 pSps->source=pChan->pTxComposite;
2285 else if(pChan->txMixA==TX_OUT_LSD)
2287 pSps->source=pChan->pTxLsdLpf;
2289 else if(pChan->txMixA==TX_OUT_VOICE)
2291 pSps->source=pChan->pTxHpf;
2293 else if (pChan->txMixA==TX_OUT_AUX)
2295 pSps->source=inputTmp;
2299 pSps->source=NULL; // maw sph asdf !!! no blow up
2300 pSps->source=inputTmp;
2303 pSps->sink=pChan->pTxOut;
2304 pSps->sigProc=pmr_gp_fir;
2308 pSps->nSamples=pChan->nSamplesTx;
2309 pSps->interpolate=6;
2310 pSps->ncoef=taps_fir_lpf_3K_1;
2312 pSps->coef=(void*)coef_fir_lpf_3K_1;
2313 pSps->nx=taps_fir_lpf_3K_1;
2315 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2316 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2317 pSps->calcAdjust=gain_fir_lpf_3K_1;
2318 pSps->inputGain=(1*M_Q8);
2319 pSps->outputGain=(1*M_Q8);
2320 if(pChan->txMixA==pChan->txMixB)pSps->monoOut=1;
2321 else pSps->monoOut=0;
2324 // Chan B Upsampler and Filter
2325 if((pChan->txMixA!=pChan->txMixB)&&(pChan->txMixB!=TX_OUT_OFF))
2327 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2328 else pSps=pSps->nextSps=createPmrSps(pChan);
2330 pChan->spsTxOutB=pSps;
2331 if(pChan->txMixB==TX_OUT_COMPOSITE)
2333 pSps->source=pChan->pTxComposite;
2335 else if(pChan->txMixB==TX_OUT_LSD)
2337 pSps->source=pChan->pTxLsdLpf;
2338 // pChan->ptxCtcssAdjust=&pSps->inputGain;
2340 else if(pChan->txMixB==TX_OUT_VOICE)
2342 pSps->source=inputTmp;
2344 else if(pChan->txMixB==TX_OUT_AUX)
2346 pSps->source=pChan->pTxHpf;
2353 pSps->sink=pChan->pTxOut;
2354 pSps->sigProc=pmr_gp_fir;
2359 pSps->nSamples=pChan->nSamplesTx;
2360 pSps->interpolate=6;
2361 pSps->ncoef=taps_fir_lpf_3K_1;
2363 pSps->coef=(void*)coef_fir_lpf_3K_1;
2364 pSps->nx=taps_fir_lpf_3K_1;
2366 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2367 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2368 pSps->calcAdjust=(gain_fir_lpf_3K_1);
2369 pSps->inputGain=(1*M_Q8);
2370 pSps->outputGain=(1*M_Q8);
2375 // Configure Coded Signaling
2376 code_string_parse(pChan);
2378 pChan->smode=SMODE_NULL;
2379 pChan->smodewas=SMODE_NULL;
2380 pChan->smodetime=2500;
2381 pChan->smodetimer=0;
2382 pChan->b.smodeturnoff=0;
2384 pChan->txsettletimer=0;
2386 TRACEF(1,("createPmrChannel() end\n"));
2392 i16 destroyPmrChannel(t_pmr_chan *pChan)
2394 #if XPMR_DEBUG0 == 1
2397 t_pmr_sps *pmr_sps, *tmp_sps;
2399 TRACEF(1,("destroyPmrChannel()\n"));
2401 free(pChan->pRxDemod);
2402 free(pChan->pRxNoise);
2403 free(pChan->pRxBase);
2404 free(pChan->pRxHpf);
2405 free(pChan->pRxLsd);
2406 free(pChan->pRxSpeaker);
2407 free(pChan->pRxDcTrack);
2408 if(pChan->pRxLsdLimit)free(pChan->pRxLsdLimit);
2409 free(pChan->pTxBase);
2410 free(pChan->pTxHpf);
2411 free(pChan->pTxPreEmp);
2412 free(pChan->pTxLimiter);
2413 free(pChan->pTxLsd);
2414 free(pChan->pTxLsdLpf);
2415 if(pChan->pTxComposite)free(pChan->pTxComposite);
2416 free(pChan->pTxOut);
2418 if(pChan->prxMeasure)free(pChan->prxMeasure);
2419 if(pChan->pSigGen0)free(pChan->pSigGen0);
2420 if(pChan->pSigGen1)free(pChan->pSigGen1);
2423 #if XPMR_DEBUG0 == 1
2424 //if(pChan->prxDebug)free(pChan->prxDebug);
2425 if(pChan->ptxDebug)free(pChan->ptxDebug);
2426 free(pChan->prxDebug0);
2427 free(pChan->prxDebug1);
2428 free(pChan->prxDebug2);
2429 free(pChan->prxDebug3);
2431 free(pChan->ptxDebug0);
2432 free(pChan->ptxDebug1);
2433 free(pChan->ptxDebug2);
2434 free(pChan->ptxDebug3);
2436 free(pChan->rxCtcss->pDebug0);
2437 free(pChan->rxCtcss->pDebug1);
2439 for(i=0;i<CTCSS_NUM_CODES;i++)
2441 free(pChan->rxCtcss->tdet[i].pDebug0);
2442 free(pChan->rxCtcss->tdet[i].pDebug1);
2443 free(pChan->rxCtcss->tdet[i].pDebug2);
2444 free(pChan->rxCtcss->tdet[i].pDebug3);
2451 free(pChan->pRxCtcss);
2453 pmr_sps=pChan->spsRx;
2455 if(pChan->sdbg)free(pChan->sdbg);
2460 pmr_sps = tmp_sps->nextSps;
2461 destroyPmrSps(tmp_sps);
2470 t_pmr_sps *createPmrSps(t_pmr_chan *pChan)
2474 TRACEF(1,("createPmrSps()\n"));
2476 pSps = (t_pmr_sps *)calloc(sizeof(t_pmr_sps),1);
2478 if(!pSps)printf("Error: createPmrSps()\n");
2480 pSps->parentChan=pChan;
2481 pSps->index=pChan->spsIndex++;
2483 // pSps->x=calloc(pSps->nx,pSps->size_x);
2489 i16 destroyPmrSps(t_pmr_sps *pSps)
2491 TRACEJ(1,("destroyPmrSps(%i)\n",pSps->index));
2493 if(pSps->x!=NULL)free(pSps->x);
2498 PmrTx - takes data from network and holds it for PmrRx
2500 i16 PmrTx(t_pmr_chan *pChan, i16 *input)
2502 pChan->frameCountTx++;
2504 TRACEF(5,("PmrTx() start %i\n",pChan->frameCountTx));
2508 if(pptp_p2)ioctl(ppdrvdev,PPDRV_IOC_PINSET,LP_PIN02);
2509 else ioctl(ppdrvdev,PPDRV_IOC_PINCLEAR,LP_PIN02);
2513 printf("PmrTx() pChan == NULL\n");
2517 #if XPMR_DEBUG0 == 1
2518 if(pChan->b.rxCapture && pChan->tracetype==5)
2520 memcpy(pChan->pTxInput,input,pChan->nSamplesRx*2);
2524 //if(pChan->b.radioactive)pChan->dd.debug=1;
2525 //else pChan->dd.debug=0;
2527 dedrift_write(pChan,input);
2532 PmrRx handles a block of data from the usb audio device
2534 i16 PmrRx(t_pmr_chan *pChan, i16 *input, i16 *outputrx, i16 *outputtx)
2540 TRACEC(5,("PmrRx(%p %p %p %p)\n",pChan, input, outputrx, outputtx));
2543 if(pChan->b.radioactive)
2545 pptp_write(1,pChan->frameCountRx&0x00000001);
2550 printf("PmrRx() pChan == NULL\n");
2554 pChan->frameCountRx++;
2556 #if XPMR_DEBUG0 == 1
2557 if(pChan->b.rxCapture)
2559 //if(pChan->prxDebug)memset((void *)pChan->prxDebug,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2560 if(pChan->ptxDebug)memset((void *)pChan->ptxDebug,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2561 if(pChan->sdbg->buffer)
2563 memset((void *)pChan->sdbg->buffer,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2564 pChan->prxDebug=pChan->sdbg->buffer;
2569 pmr_sps=pChan->spsRx; // first sps
2570 pmr_sps->source=input;
2572 if(outputrx!=NULL)pChan->spsRxOut->sink=outputrx; //last sps
2575 if(pChan->inputBlanking>0)
2577 pChan->inputBlanking-=pChan->nSamplesRx;
2578 if(pChan->inputBlanking<0)pChan->inputBlanking=0;
2579 for(i=0;i<pChan->nSamplesRx*6;i++)
2584 if( pChan->rxCpuSaver && !pChan->rxCarrierDetect &&
2585 pChan->smode==SMODE_NULL &&
2586 !pChan->txPttIn && !pChan->txPttOut)
2588 if(!pChan->b.rxhalted)
2590 if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=0;
2591 if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=0;
2592 pChan->b.rxhalted=1;
2593 TRACEC(1,("PmrRx() rx sps halted\n"));
2596 else if(pChan->b.rxhalted)
2598 if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=1;
2599 if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=1;
2600 pChan->b.rxhalted=0;
2601 TRACEC(1,("PmrRx() rx sps un-halted\n"));
2605 while(pmr_sps!=NULL && pmr_sps!=0)
2607 TRACEC(5,("PmrRx() sps %i\n",i++));
2608 pmr_sps->sigProc(pmr_sps);
2609 pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps);
2610 //pmr_sps=NULL; // sph maw
2613 #define XPMR_VOX_HANGTIME 2000
2615 if(pChan->rxCdType==CD_XPMR_VOX)
2617 if(pChan->spsRxVox->compOut)
2619 pChan->rxVoxTimer=XPMR_VOX_HANGTIME; //VOX HangTime in ms
2621 if(pChan->rxVoxTimer>0)
2623 pChan->rxVoxTimer-=MS_PER_FRAME;
2624 pChan->rxCarrierDetect=1;
2628 pChan->rxVoxTimer=0;
2629 pChan->rxCarrierDetect=0;
2634 pChan->rxCarrierDetect=!pChan->spsRx->compOut;
2637 // stop and start these engines instead to eliminate falsing
2638 if( pChan->b.ctcssRxEnable &&
2639 ( (!pChan->b.rxhalted ||
2640 pChan->rxCtcss->decode!=CTCSS_NULL || pChan->smode==SMODE_CTCSS) &&
2641 (pChan->smode!=SMODE_DCS&&pChan->smode!=SMODE_LSD) )
2644 ctcss_detect(pChan);
2648 if(pChan->txPttIn!=pChan->b.pttwas)
2650 pChan->b.pttwas=pChan->txPttIn;
2651 TRACEC(1,("PmrRx() txPttIn=%i\n",pChan->b.pttwas));
2656 xpmrx(pChan,XXO_RXDECODE);
2659 if(pChan->smodetimer>0 && !pChan->txPttIn)
2661 pChan->smodetimer-=MS_PER_FRAME;
2663 if(pChan->smodetimer<=0)
2665 pChan->smodetimer=0;
2666 pChan->smodewas=pChan->smode;
2667 pChan->smode=SMODE_NULL;
2668 pChan->b.smodeturnoff=1;
2669 TRACEC(1,("smode timeout. smode was=%i\n",pChan->smodewas));
2673 if(pChan->rxCtcss->decode > CTCSS_NULL &&
2674 (pChan->smode==SMODE_NULL||pChan->smode==SMODE_CTCSS) )
2676 if(pChan->smode!=SMODE_CTCSS)
2678 TRACEC(1,("smode set=%i code=%i\n",pChan->smode,pChan->rxCtcss->decode));
2679 pChan->smode=pChan->smodewas=SMODE_CTCSS;
2681 pChan->smodetimer=pChan->smodetime;
2685 xpmrx(pChan,XXO_LSDCTL);
2688 //TRACEX(("PmrRx() tx portion.\n"));
2690 // handle radio transmitter ptt input
2692 if( !(pChan->smode==SMODE_DCS||pChan->smode==SMODE_LSD) )
2695 if( pChan->txPttIn && pChan->txState==CHAN_TXSTATE_IDLE )
2697 TRACEC(1,("txPttIn==1 from CHAN_TXSTATE_IDLE && !SMODE_LSD. codeindex=%i %i \n",pChan->rxCtcss->decode, pChan->rxCtcssMap[pChan->rxCtcss->decode] ));
2698 pChan->dd.b.doitnow=1;
2700 if(pChan->smode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2702 if(pChan->rxCtcss->decode>CTCSS_NULL)
2704 if(pChan->rxCtcssMap[pChan->rxCtcss->decode]!=CTCSS_RXONLY)
2706 f=freq_ctcss[pChan->rxCtcssMap[pChan->rxCtcss->decode]];
2711 f=pChan->txctcssdefault_value;
2713 TRACEC(1,("txPttIn - Start CTCSSGen %f \n",f));
2718 pChan->spsSigGen0->freq=f*10;
2719 pSps=pChan->spsTxLsdLpf;
2725 pSps->ncoef=taps_fir_lpf_250_9_66;
2727 pSps->coef=(void*)coef_fir_lpf_250_9_66;
2728 pSps->nx=taps_fir_lpf_250_9_66;
2730 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2731 pSps->calcAdjust=gain_fir_lpf_250_9_66;
2735 pSps->ncoef=taps_fir_lpf_215_9_88;
2737 pSps->coef=(void*)coef_fir_lpf_215_9_88;
2738 pSps->nx=taps_fir_lpf_215_9_88;
2740 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2741 pSps->calcAdjust=gain_fir_lpf_215_9_88;
2745 pChan->spsSigGen0->option=1;
2746 pChan->spsSigGen0->enabled=1;
2747 pChan->spsSigGen0->discounterl=0;
2750 else if(pChan->smode==SMODE_NULL && pChan->txcodedefaultsmode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2752 TRACEC(1,("txPtt Encode txcodedefaultsmode==SMODE_CTCSS %f\n",pChan->txctcssdefault_value));
2753 pChan->spsSigGen0->freq=pChan->txctcssdefault_value*10;
2754 pChan->spsSigGen0->option=1;
2755 pChan->spsSigGen0->enabled=1;
2756 pChan->spsSigGen0->discounterl=0;
2757 pChan->smode=SMODE_CTCSS;
2758 pChan->smodetimer=pChan->smodetime;
2760 else if(pChan->txcodedefaultsmode==SMODE_NULL||pChan->b.txCtcssInhibit)
2762 TRACEC(1,("txPtt Encode txcodedefaultsmode==SMODE_NULL\n"));
2766 printf ("ERROR: txPttIn=%i NOT HANDLED PROPERLY.\n",pChan->txPttIn);
2767 TRACEC(1,("ERROR: txPttIn=%i NOT HANDLED PROPERLY.\n",pChan->txPttIn));
2770 pChan->txState = CHAN_TXSTATE_ACTIVE;
2773 pChan->txsettletimer=pChan->txsettletime;
2775 if(pChan->spsTxOutA)pChan->spsTxOutA->enabled=1;
2776 if(pChan->spsTxOutB)pChan->spsTxOutB->enabled=1;
2777 if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->enabled=1;
2778 if(pChan->txfreq)pChan->b.reprog=1;
2779 TRACEC(1,("PmrRx() TxOn\n"));
2781 else if(pChan->txPttIn && pChan->txState==CHAN_TXSTATE_ACTIVE)
2783 // pChan->smode=SMODE_CTCSS;
2784 pChan->smodetimer=pChan->smodetime;
2786 else if(!pChan->txPttIn && pChan->txState==CHAN_TXSTATE_ACTIVE)
2788 TRACEC(1,("txPttIn==0 from CHAN_TXSTATE_ACTIVE\n"));
2789 if(pChan->smode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2791 if( pChan->txTocType==TOC_NONE || !pChan->b.ctcssTxEnable )
2793 TRACEC(1,("Tx Off Immediate.\n"));
2794 pChan->spsSigGen0->option=3;
2795 pChan->txBufferClear=3;
2796 pChan->txState=CHAN_TXSTATE_FINISHING;
2798 else if(pChan->txTocType==TOC_NOTONE)
2800 pChan->txState=CHAN_TXSTATE_TOC;
2801 pChan->txHangTime=TOC_NOTONE_TIME/MS_PER_FRAME;
2802 pChan->spsSigGen0->option=3;
2803 TRACEC(1,("Tx Turn Off No Tone Start.\n"));
2807 pChan->txState=CHAN_TXSTATE_TOC;
2808 pChan->txHangTime=0;
2809 pChan->spsSigGen0->option=2;
2810 TRACEC(1,("Tx Turn Off Phase Shift Start.\n"));
2815 pChan->txBufferClear=3;
2816 pChan->txState=CHAN_TXSTATE_FINISHING;
2817 TRACEC(1,("Tx Off No SMODE to Finish.\n"));
2820 else if(pChan->txState==CHAN_TXSTATE_TOC)
2822 if( pChan->txPttIn && pChan->smode==SMODE_CTCSS )
2824 TRACEC(1,("Tx Key During HangTime\n"));
2825 pChan->txState = CHAN_TXSTATE_ACTIVE;
2826 pChan->spsSigGen0->option=1;
2827 pChan->spsSigGen0->enabled=1;
2828 pChan->spsSigGen0->discounterl=0;
2831 else if(pChan->txHangTime)
2833 if(--pChan->txHangTime==0)pChan->txState=CHAN_TXSTATE_FINISHING;
2835 else if(pChan->txHangTime<=0 && pChan->spsSigGen0->state==0)
2837 pChan->txBufferClear=3;
2838 pChan->txState=CHAN_TXSTATE_FINISHING;
2839 TRACEC(1,("Tx Off TOC.\n"));
2842 else if(pChan->txState==CHAN_TXSTATE_FINISHING)
2844 if(--pChan->txBufferClear<=0)
2845 pChan->txState=CHAN_TXSTATE_COMPLETE;
2847 else if(pChan->txState==CHAN_TXSTATE_COMPLETE)
2851 } // end of if SMODE==LSD
2856 pChan->spsSigGen0->option=3;
2857 pChan->txState=CHAN_TXSTATE_IDLE;
2858 if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->option=3;
2859 if(pChan->spsTxOutA)pChan->spsTxOutA->option=3;
2860 if(pChan->spsTxOutB)pChan->spsTxOutB->option=3;
2861 if(pChan->rxfreq||pChan->txfreq)pChan->b.reprog=1;
2862 TRACEC(1,("Tx Off hit.\n"));
2871 if(pChan->txsettletimer && pChan->txPttHid )
2873 pChan->txsettletimer-=MS_PER_FRAME;
2874 if(pChan->txsettletimer<0)pChan->txsettletimer=0;
2877 // enable this after we know everything else is working
2878 if( pChan->txCpuSaver &&
2879 !pChan->txPttIn && !pChan->txPttOut &&
2880 pChan->txState==CHAN_TXSTATE_IDLE &&
2881 !pChan->dd.b.doitnow
2884 if(!pChan->b.txhalted)
2886 pChan->b.txhalted=1;
2887 TRACEC(1,("PmrRx() tx sps halted\n"));
2890 else if(pChan->b.txhalted)
2892 pChan->dd.b.doitnow=1;
2893 pChan->b.txhalted=0;
2894 TRACEC(1,("PmrRx() tx sps un-halted\n"));
2897 if(pChan->b.txhalted)return(1);
2899 if(pChan->b.startSpecialTone)
2901 pChan->b.startSpecialTone=0;
2902 pChan->spsSigGen1->option=1;
2903 pChan->spsSigGen1->enabled=1;
2904 pChan->b.doingSpecialTone=1;
2906 else if(pChan->b.stopSpecialTone)
2908 pChan->b.stopSpecialTone=0;
2909 pChan->spsSigGen1->option=0;
2910 pChan->b.doingSpecialTone=0;
2911 pChan->spsSigGen1->enabled=0;
2913 else if(pChan->b.doingSpecialTone)
2915 pChan->spsSigGen1->sink=outputtx;
2916 pChan->spsSigGen1->sigProc(pChan->spsSigGen1);
2917 for(i=0;i<(pChan->nSamplesTx*2*6);i+=2)outputtx[i+1]=outputtx[i];
2921 if(pChan->spsSigGen0 && pChan->spsSigGen0->enabled )
2923 pChan->spsSigGen0->sigProc(pChan->spsSigGen0);
2926 if(pChan->spsSigGen1 && pChan->spsSigGen1->enabled)
2928 pChan->spsSigGen1->sigProc(pChan->spsSigGen1);
2932 pChan->spsLsdGen->sigProc(pChan->spsLsdGen); // maw sph ???
2935 // Do Low Speed Data Low Pass Filter
2936 pChan->spsTxLsdLpf->sigProc(pChan->spsTxLsdLpf);
2939 pmr_sps=pChan->spsTx;
2941 // get tx data from de-drift process
2943 pChan->dd.ptr=pChan->pTxBase;
2947 if(!pChan->spsSigGen1->enabled)
2949 pmr_sps->source=pChan->pTxBase;
2951 else input=pmr_sps->source;
2955 if(pChan->spsTxOutA)pChan->spsTxOutA->sink=outputtx;
2956 if(pChan->spsTxOutB)pChan->spsTxOutB->sink=outputtx;
2960 while(pmr_sps!=NULL && pmr_sps!=0)
2962 //TRACEF(1,("PmrTx() sps %i\n",i++));
2963 pmr_sps->sigProc(pmr_sps);
2964 pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps);
2967 //TRACEF(1,("PmrTx() - outputs \n"));
2968 if(pChan->txMixA==TX_OUT_OFF || !pChan->txPttOut){
2969 for(i=0;i<pChan->nSamplesTx*2*6;i+=2)outputtx[i]=0;
2972 if(pChan->txMixB==TX_OUT_OFF || !pChan->txPttOut ){
2973 for(i=0;i<pChan->nSamplesTx*2*6;i+=2)outputtx[i+1]=0;
2977 if( pChan->b.radioactive && pChan->b.pptp_p1!=pChan->txPttOut)
2979 pChan->b.pptp_p1=pChan->txPttOut;
2980 pptp_write(0,pChan->b.pptp_p1);
2984 #if XPMR_DEBUG0 == 1
2985 // TRACEF(1,("PmrRx() - debug outputs \n"));
2986 if(pChan->b.rxCapture){
2987 for(i=0;i<pChan->nSamplesRx;i++)
2989 pChan->pRxDemod[i]=input[i*2*6];
2990 pChan->pTstTxOut[i]=outputtx[i*2*6+0]; // txa
2991 //pChan->pTstTxOut[i]=outputtx[i*2*6+1]; // txb
2992 TSCOPE((RX_NOISE_TRIG, pChan->sdbg, i, (pChan->rxCarrierDetect*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
2993 TSCOPE((RX_CTCSS_DECODE, pChan->sdbg, i, pChan->rxCtcss->decode*(M_Q14/CTCSS_NUM_CODES)));
2994 TSCOPE((RX_SMODE, pChan->sdbg, i, pChan->smode*(XPMR_TRACE_AMP/4)));
2995 TSCOPE((TX_PTT_IN, pChan->sdbg, i, (pChan->txPttIn*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
2996 TSCOPE((TX_PTT_OUT, pChan->sdbg, i, (pChan->txPttOut*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
2997 TSCOPE((TX_DEDRIFT_LEAD, pChan->sdbg, i, pChan->dd.lead*8));
2998 TSCOPE((TX_DEDRIFT_ERR, pChan->sdbg, i, pChan->dd.err*16));
2999 TSCOPE((TX_DEDRIFT_FACTOR, pChan->sdbg, i, pChan->dd.factor*16));
3000 TSCOPE((TX_DEDRIFT_DRIFT, pChan->sdbg, i, pChan->dd.drift*16));
3005 strace2(pChan->sdbg);
3006 TRACEC(5,("PmrRx() return cd=%i smode=%i txPttIn=%i txPttOut=%i \n",pChan->rxCarrierDetect,pChan->smode,pChan->txPttIn,pChan->txPttOut));
3010 parallel binary programming of an RF Transceiver*/
3012 void ppbinout (u8 chan)
3018 ppdrvdev = open("/dev/ppdrv_device", 0);
3022 ast_log(LOG_ERROR, "open /dev/ppdrv_ppdrvdev returned %i\n",ppdrvdev);
3027 if(chan&0x01)i|=BIN_PROG_0;
3028 if(chan&0x02)i|=BIN_PROG_1;
3029 if(chan&0x04)i|=BIN_PROG_2;
3030 if(chan&0x08)i|=BIN_PROG_3;
3032 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3033 //ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3034 //ioctl(ppdrvdev, PPDRV_IOC_PINSET, i );
3035 ioctl(ppdrvdev, PPDRV_IOC_PINSET, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3036 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, i );
3038 // ioctl(ppdrvdev, PPDRV_IOC_PINSET, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0 );
3039 ast_log(LOG_NOTICE, "mask=%i 0x%x\n",i,i);
3043 SPI Programming of an RF Transceiver
3044 need to add permissions check and mutex
3047 need to add permissions check and mutex
3049 void ppspiout (u32 spidata)
3052 static char firstrun=0;
3058 ast_log(LOG_ERROR, "no parallel port permission ppdrvdev %i\n",ppdrvdev);
3062 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3063 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3068 for(ii=0;ii<PP_BIT_TIME*200;ii++);
3072 for(ii=0;ii<PP_BIT_TIME*4;ii++);
3075 bitselect=0x00080000;
3077 for(i=0;i<(PP_REG_LEN-12);i++)
3079 if((bitselect&spidata))
3080 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_DATA );
3082 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_DATA );
3084 for(ii=0;ii<PP_BIT_TIME;ii++);
3086 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_CLK );
3087 for(ii=0;ii<PP_BIT_TIME;ii++);
3088 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK );
3089 for(ii=0;ii<PP_BIT_TIME;ii++);
3091 bitselect=(bitselect>>1);
3093 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA );
3094 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_ENABLE );
3095 for(ii=0;ii<PP_BIT_TIME;ii++);
3096 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_ENABLE );
3101 now assumes calling thread secures permissions
3102 could set up a separate thread to program the radio? yuck!
3105 void progdtx(t_pmr_chan *pChan)
3108 //static u32 progcount=0;
3117 TRACEC(1,("\nprogdtx() %i %i %i\n",pChan->rxfreq,pChan->txfreq,0));
3120 ppdrvdev = open("/dev/ppdrv_device", 0);
3124 ast_log(LOG_ERROR, "open /dev/ppdrv_ppdrvdev returned %i\n",ppdrvdev);
3128 if(pChan->rxfreq>200000000)
3141 shiftreg=(reffreq/stepfreq)<<1;
3142 shiftreg=shiftreg|0x00000001;
3147 synthfreq=pChan->txfreq;
3149 synthfreq=pChan->rxfreq-rxiffreq;
3151 shiftreg=(synthfreq/stepfreq)<<1;
3152 tmp=(shiftreg&0xFFFFFF80)<<1;
3153 shiftreg=tmp+(shiftreg&0x0000007F);
3157 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3158 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA | DTX_ENABLE );
3162 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_TXPWR );
3163 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_TX );
3164 if(pChan->txpower && 0) ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_TXPWR );
3168 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_TX | DTX_TXPWR );
3174 reconciles clock differences between the usb adapter and
3175 asterisk's frame rate clock
3176 take out all accumulated drift error on these events:
3177 before transmitter on
3178 when ptt release from mobile units detected
3180 void dedrift(t_pmr_chan *pChan)
3182 TRACEC(5,("dedrift()\n"));
3184 if(pChan->dd.option==9)
3186 TRACEF(1,("dedrift(9)\n"));
3187 pChan->dd.framesize=DDB_FRAME_SIZE;
3188 pChan->dd.frames=DDB_FRAMES_IN_BUFF;
3189 pChan->dd.buffersize = pChan->dd.frames * pChan->dd.framesize;
3190 pChan->dd.buff=calloc(DDB_FRAME_SIZE*DDB_FRAMES_IN_BUFF,2);
3191 pChan->dd.modulus=DDB_ERR_MODULUS;
3192 pChan->dd.inputindex=0;
3193 pChan->dd.outputindex=0;
3194 pChan->dd.skew = pChan->dd.lead=0;
3197 pChan->dd.debugcnt=0;
3198 pChan->dd.lock=pChan->dd.b.txlock=pChan->dd.b.rxlock=0;
3199 pChan->dd.initcnt=2;
3200 pChan->dd.timer=10000/20;
3202 pChan->dd.factor=pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3203 pChan->dd.txframecnt=pChan->dd.rxframecnt=0;
3204 // clear the buffer too!
3207 else if(pChan->dd.option==8)
3209 free(pChan->dd.buff);
3211 pChan->dd.b.txlock=pChan->dd.b.rxlock=0;
3214 else if(pChan->dd.initcnt==0)
3216 const i32 a0 = 26231;
3217 const i32 a1 = 26231;
3218 const i32 b0 = 32768;
3219 const i32 b1 = -32358;
3226 inputindex = pChan->dd.inputindex;
3227 pChan->dd.skew = pChan->dd.txframecnt-pChan->dd.rxframecnt;
3228 pChan->dd.rxframecnt++;
3230 // pull data from buffer
3231 if( (pChan->dd.outputindex + pChan->dd.framesize) > pChan->dd.buffersize )
3235 dofirst = pChan->dd.buffersize - pChan->dd.outputindex;
3236 donext = pChan->dd.framesize - dofirst;
3237 vptr = (void*)(pChan->dd.ptr);
3238 memcpy(vptr,(void*)(pChan->dd.buff + pChan->dd.outputindex),dofirst*2);
3239 vptr=(void*)(pChan->dd.ptr + dofirst);
3240 memcpy(vptr,(void*)(pChan->dd.buff),donext*2);
3244 memcpy(pChan->dd.ptr,(void*)(pChan->dd.buff + pChan->dd.outputindex),pChan->dd.framesize*2);
3247 // compute clock error and correction factor
3248 if(pChan->dd.outputindex > inputindex)
3250 pChan->dd.lead = (inputindex + pChan->dd.buffersize) - pChan->dd.outputindex;
3254 pChan->dd.lead = inputindex - pChan->dd.outputindex;
3256 pChan->dd.err = pChan->dd.lead - (pChan->dd.buffersize/2);
3258 // WinFilter, IIR Fs=50, Fc=0.1
3259 pChan->dd.x1 = pChan->dd.x0;
3260 pChan->dd.y1 = pChan->dd.y0;
3261 pChan->dd.x0 = pChan->dd.err;
3262 pChan->dd.y0 = a0 * pChan->dd.x0;
3263 pChan->dd.y0 += (a1 * pChan->dd.x1 - (b1 * pChan->dd.y1));
3265 accum = pChan->dd.y0/dg;
3267 pChan->dd.factor=accum;
3271 // event sync'd correction
3272 if(pChan->dd.b.doitnow)
3274 pChan->dd.b.doitnow=0;
3275 indextweak=pChan->dd.factor;
3276 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3277 pChan->dd.timer=20000/MS_PER_FRAME;
3279 // coarse lead adjustment if really far out of range
3280 else if( pChan->dd.lead >= pChan->dd.framesize*(DDB_FRAMES_IN_BUFF-2) )
3282 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3283 indextweak += (pChan->dd.framesize*5/4);
3285 else if(pChan->dd.lead <= pChan->dd.framesize*2 )
3287 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3288 indextweak -= (pChan->dd.framesize*5/4);
3293 if(pChan->dd.timer>0)pChan->dd.timer--;
3294 if(pChan->dd.timer==0 && abs(pChan->dd.factor)>=16)
3296 indextweak=pChan->dd.factor;
3297 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3298 pChan->dd.timer=20000/MS_PER_FRAME;
3302 #if XPMR_DEBUG0 == 1
3303 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));
3306 // set the output index based on lead and clock offset
3307 pChan->dd.outputindex = (pChan->dd.outputindex + pChan->dd.framesize + indextweak)%pChan->dd.buffersize;
3312 void dedrift_write(t_pmr_chan *pChan, i16 *src )
3316 TRACEF(5,("dedrift_write()\n"));
3317 vptr = pChan->dd.buff + pChan->dd.inputindex;
3318 memcpy(vptr, src, pChan->dd.framesize*2);
3319 pChan->dd.inputindex = (pChan->dd.inputindex + pChan->dd.framesize) % pChan->dd.buffersize;
3320 pChan->dd.txframecnt++;
3321 if(pChan->dd.initcnt!=0)pChan->dd.initcnt--;
3322 pChan->dd.accum+=pChan->dd.framesize;