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;
483 i16 *x, *coef, *coef2;
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;
503 coef2 = mySps->coef2;
505 calcAdjust = mySps->calcAdjust;
506 outputGain = mySps->outputGain;
511 discounteru=mySps->discounteru;
512 discounterl=mySps->discounterl;
513 discfactor=mySps->discfactor;
516 compOut=mySps->compOut;
518 samples=mySps->nSamples*decimate;
522 if(mySps->parentChan->rxCdType!=CD_XPMR_VOX)doNoise=1;
525 for(i=0;i<samples;i++)
529 //shift the old samples
530 for(n=nx-1; n>0; n--)
545 y=((y/calcAdjust)*outputGain)/M_Q8;
548 else if(y<-32767)y=-32767;
550 output[iOutput]=y; // Rx Baseband decimated
551 noutput[iOutput++] = apeak; // Rx Noise
556 // calculate noise output
559 naccum += coef_fir_bpf_noise_1[n] * x[n];
561 naccum /= DCgainBpfNoise;
566 discounteru=discfactor;
568 else if(--discounteru<=0)
570 discounteru=discfactor;
571 amax=(i32)((amax*32700)/32768);
577 discounterl=discfactor;
579 else if(--discounterl<=0)
581 discounterl=discfactor;
582 amin=(i32)((amin*32700)/32768);
592 ((t_pmr_chan *)(mySps->parentChan))->rxRssi=apeak;
594 if(apeak>setpt || (compOut&&(apeak>(setpt-hyst)))) compOut=1;
596 mySps->compOut=compOut;
600 mySps->discounteru=discounteru;
601 mySps->discounterl=discounterl;
607 pmr general purpose fir
608 works on a block of samples
610 i16 pmr_gp_fir(t_pmr_sps *mySps)
612 i32 nsamples,inputGain,outputGain,calcAdjust;
616 i16 nx, hyst, setpt, compOut;
617 i16 amax, amin, apeak=0, discounteru=0, discounterl=0, discfactor;
618 i16 decimator, decimate, interpolate;
619 i16 numChanOut, selChanOut, mixOut, monoOut;
621 TRACEJ(5,("pmr_gp_fir() %i %i\n",mySps->index, mySps->enabled));
623 if(!mySps->enabled)return(1);
625 inputGain = mySps->inputGain;
626 calcAdjust = mySps->calcAdjust;
627 outputGain = mySps->outputGain;
629 input = mySps->source;
630 output = mySps->sink;
635 decimator = mySps->decimator;
636 decimate = mySps->decimate;
637 interpolate = mySps->interpolate;
639 setpt = mySps->setpt;
640 compOut = mySps->compOut;
642 inputGain = mySps->inputGain;
643 outputGain = mySps->outputGain;
644 numChanOut = mySps->numChanOut;
645 selChanOut = mySps->selChanOut;
646 mixOut = mySps->mixOut;
647 monoOut = mySps->monoOut;
652 discfactor=mySps->discfactor;
655 nsamples=mySps->nSamples;
661 for(i=0;i<nsamples;i++)
664 output[(i*2)]=output[(i*2)+1]=0;
666 output[(i*numChanOut)+selChanOut]=0;
672 for(i=0;i<nsamples;i++)
683 for(ix=0;ix<interpolate;ix++)
688 for(n=nx-1; n>0; n--)
690 x[0] = (input[i]*inputGain)/M_Q8;
706 y=((y/calcAdjust)*outputGain)/M_Q8;
710 output[(ii*2)]=output[(ii*2)+1]+=y;
713 output[(ii*numChanOut)+selChanOut]+=y;
718 output[(ii*2)]=output[(ii*2)+1]=y;
721 output[(ii*numChanOut)+selChanOut]=y;
728 // amplitude detector
736 discounteru=discfactor;
738 else if(--discounteru<=0)
740 discounteru=discfactor;
741 amax=(i32)((amax*32700)/32768);
747 discounterl=discfactor;
749 else if(--discounterl<=0)
751 discounterl=discfactor;
752 amin=(i32)((amin*32700)/32768);
755 apeak = (i32)(amax-amin)/2;
757 if(apeak>setpt)compOut=1;
758 else if(compOut&&(apeak<(setpt-hyst)))compOut=0;
762 mySps->decimator = decimator;
767 mySps->discounteru=discounteru;
768 mySps->discounterl=discounterl;
770 mySps->compOut=compOut;
775 general purpose integrator lpf
777 i16 gp_inte_00(t_pmr_sps *mySps)
782 i32 inputGain, outputGain,calcAdjust;
787 i16 coeff00, coeff01;
789 TRACEJ(5,("gp_inte_00() %i\n",mySps->enabled));
790 if(!mySps->enabled)return(1);
792 input = mySps->source;
793 output = mySps->sink;
795 npoints=mySps->nSamples;
797 inputGain=mySps->inputGain;
798 outputGain=mySps->outputGain;
799 calcAdjust=mySps->calcAdjust;
801 coeff00=((i16*)mySps->coef)[0];
802 coeff01=((i16*)mySps->coef)[1];
803 state00=((i32*)mySps->x)[0];
805 // note fixed gain of 2 to compensate for attenuation
808 for(i=0;i<npoints;i++)
811 state00 = accum + (state00*coeff01)/M_Q15;
812 accum = (state00*coeff00)/(M_Q15/4);
813 output[i]=(accum*outputGain)/M_Q8;
816 ((i32*)(mySps->x))[0]=state00;
821 general purpose differentiator hpf
823 i16 gp_diff(t_pmr_sps *mySps)
827 i32 inputGain, outputGain, calcAdjust;
837 input = mySps->source;
838 output = mySps->sink;
840 npoints=mySps->nSamples;
842 inputGain=mySps->inputGain;
843 outputGain=mySps->outputGain;
844 calcAdjust=mySps->calcAdjust;
846 coef=(i16*)(mySps->coef);
854 TRACEJ(5,("gp_diff()\n"));
856 for (i=0;i<npoints;i++)
860 temp1 = input[i] * a0;
861 _y0 = (temp0 + temp1)/calcAdjust;
862 _y0 = (_y0*outputGain)/M_Q8;
864 if(_y0>32766)_y0=32766;
865 else if(_y0<-32766)_y0=-32766;
873 /* ----------------------------------------------------------------------
876 i16 CenterSlicer(t_pmr_sps *mySps)
878 i16 npoints,lhit,uhit;
879 i16 *input, *output, *buff;
881 i32 inputGain, outputGain, inputGainB;
885 i32 amax; // buffer amplitude maximum
886 i32 amin; // buffer amplitude minimum
887 i32 apeak; // buffer amplitude peak
889 i32 setpt; // amplitude set point for peak tracking
891 i32 discounteru; // amplitude detector integrator discharge counter upper
892 i32 discounterl; // amplitude detector integrator discharge counter lower
893 i32 discfactor; // amplitude detector integrator discharge factor
895 TRACEJ(5,("CenterSlicer() %i\n",mySps->enabled));
896 if(!mySps->enabled)return(1);
898 input = mySps->source;
899 output = mySps->sink; // limited output
902 npoints=mySps->nSamples;
904 inputGain=mySps->inputGain;
905 outputGain=mySps->outputGain;
906 inputGainB=mySps->inputGainB;
912 discounteru=mySps->discounteru;
913 discounterl=mySps->discounterl;
915 discfactor=mySps->discfactor;
916 npoints=mySps->nSamples;
918 for(i=0;i<npoints;i++)
931 if(amin<(amax-setpt))
941 if(amax>(amin+setpt))
948 if((discounteru-=1)<=0 && amax>amin)
950 if((amax-=10)<amin)amax=amin;
954 if((discounterl-=1)<=0 && amin<amax)
956 if((amin+=10)>amax)amin=amax;
959 if(uhit)discounteru=discfactor;
960 if(lhit)discounterl=discfactor;
964 if((amax-=discfactor)<amin)amax=amin;
965 if((amin+=discfactor)>amax)amin=amax;
969 apeak = (amax-amin)/2;
970 center = (amax+amin)/2;
971 accum = accum - center;
973 output[i]=accum; // sink output unlimited/centered.
975 // do limiter function
976 if(accum>inputGainB)accum=inputGainB;
977 else if(accum<-inputGainB)accum=-inputGainB;
982 mySps->parentChan->pRxLsdCen[i]=center; // trace center ref
984 if((tfx++/8)&1) // trace min/max levels
985 mySps->parentChan->pRxLsdCen[i]=amax;
987 mySps->parentChan->pRxLsdCen[i]=amin;
990 if(mySps->parentChan->frameCountRx&0x01) mySps->parentChan->prxDebug1[i]=amax;
991 else mySps->parentChan->prxDebug1[i]=amin;
999 mySps->discounteru=discounteru;
1000 mySps->discounterl=discounterl;
1004 /* ----------------------------------------------------------------------
1006 determine peak amplitude
1008 i16 MeasureBlock(t_pmr_sps *mySps)
1011 i16 *input, *output;
1013 i32 inputGain, outputGain;
1017 i16 amax; // buffer amplitude maximum
1018 i16 amin; // buffer amplitude minimum
1019 i16 apeak=0; // buffer amplitude peak (peak to peak)/2
1020 i16 setpt; // amplitude set point for amplitude comparator
1022 i32 discounteru; // amplitude detector integrator discharge counter upper
1023 i32 discounterl; // amplitude detector integrator discharge counter lower
1024 i32 discfactor; // amplitude detector integrator discharge factor
1026 TRACEJ(5,("MeasureBlock() %i\n",mySps->enabled));
1028 if(!mySps->enabled)return 1;
1030 if(mySps->option==3)
1032 mySps->amax = mySps->amin = mySps->apeak = \
1033 mySps->discounteru = mySps->discounterl = \
1038 input = mySps->source;
1039 output = mySps->sink;
1041 npoints=mySps->nSamples;
1043 inputGain=mySps->inputGain;
1044 outputGain=mySps->outputGain;
1049 discounteru=mySps->discounteru;
1050 discounterl=mySps->discounterl;
1052 discfactor=mySps->discfactor;
1053 npoints=mySps->nSamples;
1055 for(i=0;i<npoints;i++)
1062 discounteru=discfactor;
1064 else if(--discounteru<=0)
1066 discounteru=discfactor;
1067 amax=(i32)((amax*32700)/32768);
1073 discounterl=discfactor;
1075 else if(--discounterl<=0)
1077 discounterl=discfactor;
1078 amin=(i32)((amin*32700)/32768);
1081 apeak = (i32)(amax-amin)/2;
1082 if(output)output[i]=apeak;
1088 mySps->discounteru=discounteru;
1089 mySps->discounterl=discounterl;
1090 if(apeak>=setpt) mySps->compOut=1;
1091 else mySps->compOut=0;
1093 //TRACEX((" -MeasureBlock()=%i\n",mySps->apeak));
1099 i16 SoftLimiter(t_pmr_sps *mySps)
1102 //i16 samples, lhit,uhit;
1103 i16 *input, *output;
1105 i32 inputGain, outputGain;
1110 i32 amax; // buffer amplitude maximum
1111 i32 amin; // buffer amplitude minimum
1112 //i32 apeak; // buffer amplitude peak
1113 i32 setpt; // amplitude set point for amplitude comparator
1114 i16 compOut; // amplitude comparator output
1116 input = mySps->source;
1117 output = mySps->sink;
1119 inputGain=mySps->inputGain;
1120 outputGain=mySps->outputGain;
1122 npoints=mySps->nSamples;
1125 amax=(setpt*124)/128;
1128 TRACEJ(5,("SoftLimiter() %i %i %i) \n",amin, amax,setpt));
1130 for(i=0;i<npoints;i++)
1133 //accum=input[i]*mySps->inputGain/256;
1137 tmp=((accum-setpt)*4)/128;
1139 if(accum>amax)accum=amax;
1143 else if(accum<-setpt)
1145 tmp=((accum+setpt)*4)/128;
1147 if(accum<amin)accum=amin;
1152 output[i]=(accum*outputGain)/M_Q8;
1158 SigGen() - sine, square function generator
1159 sps overloaded values
1160 discfactor = phase factor
1161 discfactoru = phase index
1162 if source is not NULL then mix it in!
1164 sign table and output gain are in Q15 format (32767=.999)
1166 i16 SigGen(t_pmr_sps *mySps)
1168 #define PH_FRACT_FACT 128
1171 i16 i,outputgain,waveform,numChanOut,selChanOut;
1175 pChan=mySps->parentChan;
1176 TRACEC(5,("SigGen(%i %i %i)\n",mySps->option,mySps->enabled,mySps->state));
1178 if(!mySps->freq ||!mySps->enabled)return 0;
1180 outputgain=mySps->outputGain;
1182 numChanOut=mySps->numChanOut;
1183 selChanOut=mySps->selChanOut;
1185 if(mySps->option==1)
1190 (SAMPLES_PER_SINE*mySps->freq*PH_FRACT_FACT)/mySps->sampleRate/10;
1192 TRACEF(5,(" SigGen() discfactor = %i\n",mySps->discfactor));
1193 if(mySps->discounterl)mySps->state=2;
1195 else if(mySps->option==2)
1197 i16 shiftfactor=CTCSS_TURN_OFF_SHIFT;
1198 // phase shift request
1201 mySps->discounterl=CTCSS_TURN_OFF_TIME-(2*MS_PER_FRAME); //
1203 mySps->discounteru = \
1204 (mySps->discounteru + (((SAMPLES_PER_SINE*shiftfactor)/360)*PH_FRACT_FACT)) % (SAMPLES_PER_SINE*PH_FRACT_FACT);
1205 //printf("shiftfactor = %i\n",shiftfactor);
1208 else if(mySps->option==3)
1210 // stop it and clear the output buffer
1214 for(i=0;i<mySps->nSamples;i++)
1215 mySps->sink[(i*numChanOut)+selChanOut]=0;
1218 else if(mySps->state==2)
1221 mySps->discounterl-=MS_PER_FRAME;
1222 if(mySps->discounterl<=0)
1228 else if(mySps->state==0)
1233 ph=mySps->discounteru;
1235 for(i=0;i<mySps->nSamples;i++)
1240 //tmp=(sinetablex[ph/PH_FRACT_FACT]*amplitude)/M_Q16;
1241 accum=sinetablex[ph/PH_FRACT_FACT];
1242 accum=(accum*outputgain)/M_Q8;
1247 if(ph>SAMPLES_PER_SINE/2)
1248 accum=outputgain/M_Q8;
1250 accum=-outputgain/M_Q8;
1253 if(mySps->source)accum+=mySps->source[i];
1255 mySps->sink[(i*numChanOut)+selChanOut]=accum;
1257 ph=(ph+mySps->discfactor)%(SAMPLES_PER_SINE*PH_FRACT_FACT);
1260 mySps->discounteru=ph;
1266 takes existing buffer and adds source buffer to destination buffer
1267 sink buffer = (sink buffer * gain) + source buffer
1269 i16 pmrMixer(t_pmr_sps *mySps)
1272 i16 i, *input, *inputB, *output;
1273 i16 inputGain, inputGainB; // apply to input data in Q7.8 format
1274 i16 outputGain; // apply to output data in Q7.8 format
1275 i16 discounteru,discounterl,amax,amin,setpt,discfactor;
1276 i16 npoints,uhit,lhit,apeak,measPeak;
1279 pChan=mySps->parentChan;
1280 TRACEF(5,("pmrMixer()\n"));
1282 input = mySps->source;
1283 inputB = mySps->sourceB;
1284 output = mySps->sink;
1286 inputGain=mySps->inputGain;
1287 inputGainB=mySps->inputGainB;
1288 outputGain=mySps->outputGain;
1293 discounteru=mySps->discounteru;
1294 discounterl=mySps->discounteru;
1296 discfactor=mySps->discfactor;
1297 npoints=mySps->nSamples;
1298 measPeak=mySps->measPeak;
1300 for(i=0;i<npoints;i++)
1302 accum = ((input[i]*inputGain)/M_Q8) +
1303 ((inputB[i]*inputGainB)/M_Q8);
1305 accum=(accum*outputGain)/M_Q8;
1314 if(amin<(amax-setpt)){
1319 else if(accum<amin){
1322 if(amax>(amin+setpt)){
1328 if(--discounteru<=0 && amax>0){
1333 if(--discounterl<=0 && amin<0){
1338 if(uhit)discounteru=discfactor;
1339 if(lhit)discounterl=discfactor;
1344 apeak = (amax-amin)/2;
1348 mySps->discounteru=discounteru;
1349 mySps->discounterl=discounterl;
1357 i16 DelayLine(t_pmr_sps *mySps)
1359 i16 *input, *output, *buff;
1360 i16 i, npoints,buffsize,inindex,outindex;
1363 pChan=mySps->parentChan;
1364 TRACEF(5,(" DelayLine() %i\n",mySps->enabled));
1366 input = mySps->source;
1367 output = mySps->sink;
1368 buff = (i16*)(mySps->buff);
1369 buffsize = mySps->buffSize;
1370 npoints = mySps->nSamples;
1372 outindex = mySps->buffOutIndex;
1373 inindex = outindex + mySps->buffLead;
1375 for(i=0;i<npoints;i++)
1377 inindex %= buffsize;
1378 outindex %= buffsize;
1380 buff[inindex]=input[i];
1381 output[i]=buff[outindex];
1385 mySps->buffOutIndex=outindex;
1390 Continuous Tone Coded Squelch (CTCSS) Detector
1392 i16 ctcss_detect(t_pmr_chan *pChan)
1394 i16 i,points2do,*pInput,hit,thit,relax;
1395 i16 tnum, tmp,indexNow,gain,diffpeak;
1397 i16 tv0,tv1,tv2,tv3,indexDebug;
1401 TRACEF(5,("ctcss_detect(%p) %i %i %i %i\n",pChan,
1402 pChan->rxCtcss->enabled,
1404 pChan->rxCtcss->testIndex,
1405 pChan->rxCtcss->decode));
1407 if(!pChan->rxCtcss->enabled)return(1);
1409 relax = pChan->rxCtcss->relax;
1410 pInput = pChan->rxCtcss->input;
1411 gain = pChan->rxCtcss->gain;
1413 if(relax) difftrig=(-0.1*M_Q15);
1414 else difftrig=(-0.05*M_Q15);
1418 //TRACEX((" ctcss_detect() %i %i %i %i\n", CTCSS_NUM_CODES,0,0,0));
1420 for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++)
1427 TRACEF(6,(" ctcss_detect() tnum=%i %i\n",tnum,pChan->rxCtcssMap[tnum]));
1428 //if(tnum==14)printf("ctcss_detect() %i %i %i\n",tnum,pChan->rxCtcssMap[tnum], pChan->rxCtcss->decode );
1430 if( (pChan->rxCtcssMap[tnum]==CTCSS_NULL) ||
1431 (pChan->rxCtcss->decode>CTCSS_NULL && (tnum!= pChan->rxCtcss->decode))
1435 TRACEF(6,(" ctcss_detect() tnum=%i\n",tnum));
1437 ptdet=&(pChan->rxCtcss->tdet[tnum]);
1439 points=points2do=pChan->nSamplesRx;
1440 fudgeFactor=ptdet->fudgeFactor;
1441 binFactor=ptdet->binFactor;
1443 while(ptdet->counter < (points2do*CTCSS_SCOUNT_MUL))
1445 tmp=(ptdet->counter/CTCSS_SCOUNT_MUL)+1;
1446 ptdet->counter-=(tmp*CTCSS_SCOUNT_MUL);
1448 indexNow=points-points2do;
1450 ptdet->counter += ptdet->counterFactor;
1452 accum = pInput[indexNow-1]; // duuuude's major bug fix!
1454 ptdet->z[ptdet->zIndex]+=
1455 (((accum - ptdet->z[ptdet->zIndex])*binFactor)/M_Q15);
1457 peak = abs(ptdet->z[0]-ptdet->z[2]) + abs(ptdet->z[1]-ptdet->z[3]);
1459 if (ptdet->peak < peak)
1460 ptdet->peak += ( ((peak-ptdet->peak)*binFactor)/M_Q15);
1465 static const i16 a0=13723;
1466 static const i16 a1=-13723;
1473 ptdet->zd = ptdet->peak;
1474 temp1 = ptdet->peak * a0;
1475 diffpeak = (temp0 + temp1)/1024;
1478 if(diffpeak<(-0.03*M_Q15))ptdet->dvd-=4;
1479 else if(ptdet->dvd<0)ptdet->dvd++;
1481 if((ptdet->dvd < -12) && diffpeak > (-0.02*M_Q15))ptdet->dvu+=2;
1482 else if(ptdet->dvu)ptdet->dvu--;
1485 if(pChan->rxCtcss->decode==tnum)
1487 if(relax)tmp=(tmp*55)/100;
1488 else tmp=(tmp*80)/100;
1491 if(ptdet->peak > tmp)
1493 if(ptdet->decode<(fudgeFactor*32))ptdet->decode++;
1495 else if(pChan->rxCtcss->decode==tnum)
1497 if(ptdet->peak > ptdet->hyst)ptdet->decode--;
1498 else if(relax) ptdet->decode--;
1499 else ptdet->decode-=4;
1506 if((pChan->rxCtcss->decode==tnum) && !relax && (ptdet->dvu > (0.00075*M_Q15)))
1509 ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=ptdet->dvu=0;
1510 TRACEF(4,("ctcss_detect() turnoff detected by dvdt for tnum = %i.\n",tnum));
1513 if(ptdet->decode<0 || !pChan->rxCarrierDetect)ptdet->decode=0;
1515 if(ptdet->decode>=fudgeFactor)
1518 if(pChan->rxCtcss->decode!=tnum)
1520 ptdet->zd=ptdet->dvu=ptdet->dvd=0;
1524 #if XPMR_DEBUG0 == 1
1525 if(thit>=0 && thit==tnum)
1526 TRACEF(6,(" ctcss_detect() %i %i %i %i \n",tnum,ptdet->peak,ptdet->setpt,ptdet->hyst));
1537 ptdet->lasttv0=ptdet->pDebug0[points-1];
1538 ptdet->lasttv1=ptdet->pDebug1[points-1];
1539 ptdet->lasttv2=ptdet->pDebug2[points-1];
1540 ptdet->lasttv3=ptdet->pDebug3[points-1];
1543 while(indexDebug<indexNow)
1545 ptdet->pDebug0[indexDebug]=ptdet->lasttv0;
1546 ptdet->pDebug1[indexDebug]=ptdet->lasttv1;
1547 ptdet->pDebug2[indexDebug]=ptdet->lasttv2;
1548 ptdet->pDebug3[indexDebug]=ptdet->lasttv3;
1558 ptdet->zIndex=(ptdet->zIndex + 1) % 4;
1560 ptdet->counter-=(points2do*CTCSS_SCOUNT_MUL);
1562 #if XPMR_DEBUG0 == 1
1563 for(i=indexWas;i<points;i++)
1565 ptdet->pDebug0[i]=ptdet->lasttv0;
1566 ptdet->pDebug1[i]=ptdet->lasttv1;
1567 ptdet->pDebug2[i]=ptdet->lasttv2;
1568 ptdet->pDebug3[i]=ptdet->lasttv3;
1573 //TRACEX((" ctcss_detect() thit %i\n",thit));
1575 if(pChan->rxCtcss->BlankingTimer>0)pChan->rxCtcss->BlankingTimer-=points;
1576 if(pChan->rxCtcss->BlankingTimer<0)pChan->rxCtcss->BlankingTimer=0;
1578 if(thit>CTCSS_NULL && pChan->rxCtcss->decode<=CTCSS_NULL && !pChan->rxCtcss->BlankingTimer)
1580 pChan->rxCtcss->decode=thit;
1581 sprintf(pChan->rxctcssfreq,"%.1f",freq_ctcss[thit]);
1582 TRACEC(1,("ctcss decode %i %.1f\n",thit,freq_ctcss[thit]));
1584 else if(thit<=CTCSS_NULL && pChan->rxCtcss->decode>CTCSS_NULL)
1586 pChan->rxCtcss->BlankingTimer=SAMPLE_RATE_NETWORK/5;
1587 pChan->rxCtcss->decode=CTCSS_NULL;
1588 strcpy(pChan->rxctcssfreq,"0");
1589 TRACEC(1,("ctcss decode NULL\n"));
1590 for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++)
1593 ptdet=&(pChan->rxCtcss->tdet[tnum]);
1595 ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=0;
1598 //TRACEX((" ctcss_detect() thit %i %i\n",thit,pChan->rxCtcss->decode));
1604 static i16 TxTestTone(t_pmr_chan *pChan, i16 function)
1608 pChan->spsSigGen1->enabled=1;
1609 pChan->spsSigGen1->option=1;
1610 pChan->spsSigGen1->outputGain=(.23125*M_Q8); // to match *99 level
1611 pChan->spsTx->source=pChan->spsSigGen1->sink;
1615 pChan->spsSigGen1->option=3;
1621 sampling rate is 48KS/s
1622 samples are all 16 bits
1623 samples are filtered and decimated by 1/6th
1625 t_pmr_chan *createPmrChannel(t_pmr_chan *tChan, i16 numSamples)
1630 t_dec_ctcss *pDecCtcss;
1632 TRACEJ(1,("createPmrChannel(%p,%i)\n",tChan,numSamples));
1634 pChan = (t_pmr_chan *)calloc(sizeof(t_pmr_chan),1);
1637 printf("createPmrChannel() failed\n");
1645 pChan->index=pmrChanIndex++;
1646 pChan->nSamplesTx=pChan->nSamplesRx=numSamples;
1648 pDecCtcss = (t_dec_ctcss *)calloc(sizeof(t_dec_ctcss),1);
1649 pChan->rxCtcss=pDecCtcss;
1650 pChan->rxctcssfreq[0]=0;
1653 if(tChan->rptnum>=LSD_CHAN_MAX)tChan->rptnum=0;
1658 printf("createPmrChannel() WARNING: NULL tChan!\n");
1659 pChan->rxNoiseSquelchEnable=0;
1660 pChan->rxHpfEnable=0;
1661 pChan->rxDeEmpEnable=0;
1662 pChan->rxCenterSlicerEnable=0;
1663 pChan->rxCtcssDecodeEnable=0;
1664 pChan->rxDcsDecodeEnable=0;
1666 pChan->rxCarrierPoint = 17000;
1667 pChan->rxCarrierHyst = 2500;
1669 pChan->txHpfEnable=0;
1670 pChan->txLimiterEnable=0;
1671 pChan->txPreEmpEnable=0;
1672 pChan->txLpfEnable=1;
1673 pChan->txMixA=TX_OUT_VOICE;
1674 pChan->txMixB=TX_OUT_LSD;
1678 pChan->rxDemod=tChan->rxDemod;
1679 pChan->rxCdType=tChan->rxCdType;
1680 pChan->rxSquelchPoint = tChan->rxSquelchPoint;
1681 pChan->rxCarrierHyst = 3000;
1682 pChan->rxSqVoxAdj=tChan->rxSqVoxAdj;
1684 pChan->txMod=tChan->txMod;
1685 pChan->txHpfEnable=1;
1686 pChan->txLpfEnable=1;
1688 pChan->pTxCodeDefault=tChan->pTxCodeDefault;
1689 pChan->pRxCodeSrc=tChan->pRxCodeSrc;
1690 pChan->pTxCodeSrc=tChan->pTxCodeSrc;
1692 pChan->txMixA=tChan->txMixA;
1693 pChan->txMixB=tChan->txMixB;
1694 pChan->radioDuplex=tChan->radioDuplex;
1695 pChan->area=tChan->area;
1696 pChan->rptnum=tChan->rptnum;
1697 pChan->idleinterval=tChan->idleinterval;
1698 pChan->turnoffs=tChan->turnoffs;
1699 pChan->b.rxpolarity=tChan->b.rxpolarity;
1700 pChan->b.txpolarity=tChan->b.txpolarity;
1701 pChan->b.dcsrxpolarity=tChan->b.dcsrxpolarity;
1702 pChan->b.dcstxpolarity=tChan->b.dcstxpolarity;
1703 pChan->b.lsdrxpolarity=tChan->b.lsdrxpolarity;
1704 pChan->b.lsdtxpolarity=tChan->b.lsdtxpolarity;
1706 pChan->txsettletime=tChan->txsettletime;
1707 pChan->tracelevel=tChan->tracelevel;
1708 pChan->tracetype=tChan->tracetype;
1709 pChan->ukey=tChan->ukey;
1710 pChan->name=tChan->name;
1714 pChan->txHpfEnable=1;
1715 pChan->txLpfEnable=1;
1717 if(pChan->rxCdType==CD_XPMR_NOISE) pChan->rxNoiseSquelchEnable=1;
1719 if(pChan->rxDemod==RX_AUDIO_FLAT) pChan->rxDeEmpEnable=1;
1721 pChan->rxCarrierPoint=(pChan->rxSquelchPoint*32767)/100;
1722 pChan->rxCarrierHyst = 3000; //pChan->rxCarrierPoint/15;
1724 pChan->rxDcsDecodeEnable=0;
1726 if(pChan->b.ctcssRxEnable || pChan->b.dcsRxEnable || pChan->b.lmrRxEnable)
1728 pChan->rxHpfEnable=1;
1729 pChan->rxCenterSlicerEnable=1;
1730 pChan->rxCtcssDecodeEnable=1;
1734 pChan->txPreEmpEnable=1;
1735 pChan->txLimiterEnable=1;
1741 TRACEF(1,("calloc buffers \n"));
1743 pChan->pRxDemod = calloc(numSamples,2);
1744 pChan->pRxNoise = calloc(numSamples,2);
1745 pChan->pRxBase = calloc(numSamples,2);
1746 pChan->pRxHpf = calloc(numSamples,2);
1747 pChan->pRxLsd = calloc(numSamples,2);
1748 pChan->pRxSpeaker = calloc(numSamples,2);
1749 pChan->pRxCtcss = calloc(numSamples,2);
1750 pChan->pRxDcTrack = calloc(numSamples,2);
1751 pChan->pRxLsdLimit = calloc(numSamples,2);
1753 pChan->pTxInput = calloc(numSamples,2);
1754 pChan->pTxBase = calloc(numSamples,2);
1755 pChan->pTxHpf = calloc(numSamples,2);
1756 pChan->pTxPreEmp = calloc(numSamples,2);
1757 pChan->pTxLimiter = calloc(numSamples,2);
1758 pChan->pTxLsd = calloc(numSamples,2);
1759 pChan->pTxLsdLpf = calloc(numSamples,2);
1760 pChan->pTxComposite = calloc(numSamples,2);
1761 pChan->pSigGen0 = calloc(numSamples,2);
1762 pChan->pSigGen1 = calloc(numSamples,2);
1764 pChan->prxMeasure = calloc(numSamples,2);
1766 pChan->pTxOut = calloc(numSamples,2*2*6); // output buffer
1769 pChan->pLsdEnc = calloc(sizeof(t_encLsd),1);
1772 #if XPMR_DEBUG0 == 1
1773 TRACEF(1,("configure tracing\n"));
1775 pChan->pTstTxOut = calloc(numSamples,2);
1776 pChan->pRxLsdCen = calloc(numSamples,2);
1777 pChan->prxDebug0 = calloc(numSamples,2);
1778 pChan->prxDebug1 = calloc(numSamples,2);
1779 pChan->prxDebug2 = calloc(numSamples,2);
1780 pChan->prxDebug3 = calloc(numSamples,2);
1781 pChan->ptxDebug0 = calloc(numSamples,2);
1782 pChan->ptxDebug1 = calloc(numSamples,2);
1783 pChan->ptxDebug2 = calloc(numSamples,2);
1784 pChan->ptxDebug3 = calloc(numSamples,2);
1785 pChan->pNull = calloc(numSamples,2);
1787 for(i=0;i<numSamples;i++)pChan->pNull[i]=((i%(numSamples/2))*8000)-4000;
1789 pChan->rxCtcss->pDebug0=calloc(numSamples,2);
1790 pChan->rxCtcss->pDebug1=calloc(numSamples,2);
1791 pChan->rxCtcss->pDebug2=calloc(numSamples,2);
1792 pChan->rxCtcss->pDebug3=calloc(numSamples,2);
1794 for(i=0;i<CTCSS_NUM_CODES;i++)
1796 pChan->rxCtcss->tdet[i].pDebug0=calloc(numSamples,2);
1797 pChan->rxCtcss->tdet[i].pDebug1=calloc(numSamples,2);
1798 pChan->rxCtcss->tdet[i].pDebug2=calloc(numSamples,2);
1799 pChan->rxCtcss->tdet[i].pDebug3=calloc(numSamples,2);
1802 // buffer, 2 bytes per sample, and 16 channels
1803 pChan->prxDebug=calloc(numSamples*16,2);
1804 pChan->ptxDebug=calloc(numSamples*16,2);
1806 // TSCOPE CONFIGURATION SETSCOPE configure debug traces and sources for each channel of the output
1807 pChan->sdbg = (t_sdbg *)calloc(sizeof(t_sdbg),1);
1809 for(i=0;i<XPMR_DEBUG_CHANS;i++)pChan->sdbg->trace[i]=-1;
1811 TRACEF(1,("pChan->tracetype = %i\n",pChan->tracetype));
1813 if(pChan->tracetype==1) // CTCSS DECODE
1815 pChan->sdbg->source [0]=pChan->pRxDemod;
1816 pChan->sdbg->source [1]=pChan->pRxBase;
1817 pChan->sdbg->source [2]=pChan->pRxNoise;
1818 pChan->sdbg->trace [3]=RX_NOISE_TRIG;
1819 pChan->sdbg->source [4]=pChan->pRxLsd;
1820 pChan->sdbg->source [5]=pChan->pRxLsdCen;
1821 pChan->sdbg->source [6]=pChan->pRxLsdLimit;
1822 pChan->sdbg->source [7]=pChan->rxCtcss->tdet[3].pDebug0;
1823 pChan->sdbg->trace [8]=RX_CTCSS_DECODE;
1824 pChan->sdbg->trace [9]=RX_SMODE;
1826 if(pChan->tracetype==2) // CTCSS DECODE
1828 pChan->sdbg->source [0]=pChan->pRxDemod;
1829 pChan->sdbg->source [1]=pChan->pRxBase;
1830 pChan->sdbg->trace [2]=RX_NOISE_TRIG;
1831 pChan->sdbg->source [3]=pChan->pRxLsd;
1832 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1833 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1834 pChan->sdbg->source [6]=pChan->pRxLsdLimit;
1835 pChan->sdbg->source [7]=pChan->rxCtcss->tdet[3].pDebug0;
1836 pChan->sdbg->source [8]=pChan->rxCtcss->tdet[3].pDebug1;
1837 pChan->sdbg->source [9]=pChan->rxCtcss->tdet[3].pDebug2;
1838 pChan->sdbg->source [10]=pChan->rxCtcss->tdet[3].pDebug3;
1839 pChan->sdbg->trace [11]=RX_CTCSS_DECODE;
1840 pChan->sdbg->trace [12]=RX_SMODE;
1841 pChan->sdbg->trace [13]=TX_PTT_IN;
1842 pChan->sdbg->trace [14]=TX_PTT_OUT;
1843 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1845 else if(pChan->tracetype==3) // DCS DECODE
1847 pChan->sdbg->source [0]=pChan->pRxDemod;
1848 pChan->sdbg->source [1]=pChan->pRxBase;
1849 pChan->sdbg->trace [2]=RX_NOISE_TRIG;
1850 pChan->sdbg->source [3]=pChan->pRxLsd;
1851 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1852 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1853 pChan->sdbg->trace [6]=RX_DCS_CLK;
1854 pChan->sdbg->trace [7]=RX_DCS_DIN;
1855 pChan->sdbg->trace [8]=RX_DCS_DEC;
1856 pChan->sdbg->trace [9]=RX_SMODE;
1857 pChan->sdbg->trace [10]=TX_PTT_IN;
1858 pChan->sdbg->trace [11]=TX_PTT_OUT;
1859 pChan->sdbg->trace [12]=TX_LSD_CLK;
1860 pChan->sdbg->trace [13]=TX_LSD_DAT;
1861 pChan->sdbg->trace [14]=TX_LSD_GEN;
1862 pChan->sdbg->source [14]=pChan->pTxLsd;
1863 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1865 else if(pChan->tracetype==4) // LSD DECODE
1867 pChan->sdbg->source [0]=pChan->pRxDemod;
1868 pChan->sdbg->source [1]=pChan->pRxBase;
1869 pChan->sdbg->trace [2]=RX_NOISE_TRIG;
1870 pChan->sdbg->source [3]=pChan->pRxLsd;
1871 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1872 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1873 pChan->sdbg->trace [6]=RX_LSD_CLK;
1874 pChan->sdbg->trace [7]=RX_LSD_DAT;
1875 pChan->sdbg->trace [8]=RX_LSD_ERR;
1876 pChan->sdbg->trace [9]=RX_LSD_SYNC;
1877 pChan->sdbg->trace [10]=RX_SMODE;
1878 pChan->sdbg->trace [11]=TX_PTT_IN;
1879 pChan->sdbg->trace [12]=TX_PTT_OUT;
1880 pChan->sdbg->trace [13]=TX_LSD_CLK;
1881 pChan->sdbg->trace [14]=TX_LSD_DAT;
1882 //pChan->sdbg->trace [14]=TX_LSD_GEN;
1883 //pChan->sdbg->source [14]=pChan->pTxLsd;
1884 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1886 else if(pChan->tracetype==5) // LSD LOGIC
1888 pChan->sdbg->source [0]=pChan->pRxBase;
1889 pChan->sdbg->trace [1]=RX_NOISE_TRIG;
1890 pChan->sdbg->source [2]=pChan->pRxDcTrack;
1891 pChan->sdbg->trace [3]=RX_LSD_SYNC;
1892 pChan->sdbg->trace [4]=RX_SMODE;
1893 pChan->sdbg->trace [5]=TX_PTT_IN;
1894 pChan->sdbg->trace [6]=TX_PTT_OUT;
1895 pChan->sdbg->source [7]=pChan->pTxLsdLpf;
1897 else if(pChan->tracetype==6)
1899 // tx clock skew and jitter buffer
1900 pChan->sdbg->source [0]=pChan->pRxDemod;
1901 pChan->sdbg->source [5]=pChan->pTxBase;
1902 pChan->sdbg->trace [6]=TX_DEDRIFT_LEAD;
1903 pChan->sdbg->trace [7]=TX_DEDRIFT_ERR;
1904 pChan->sdbg->trace [8]=TX_DEDRIFT_FACTOR;
1905 pChan->sdbg->trace [9]=TX_DEDRIFT_DRIFT;
1907 else if(pChan->tracetype==7)
1910 pChan->sdbg->source [0]=pChan->pRxBase;
1911 pChan->sdbg->trace [1]=RX_NOISE_TRIG;
1912 pChan->sdbg->source [2]=pChan->pRxLsd;
1913 pChan->sdbg->trace [3]=RX_CTCSS_DECODE;
1914 pChan->sdbg->source [4]=pChan->pRxHpf;
1916 pChan->sdbg->trace [5]=TX_PTT_IN;
1917 pChan->sdbg->trace [6]=TX_PTT_OUT;
1919 pChan->sdbg->source [7]=pChan->pTxBase;
1920 pChan->sdbg->source [8]=pChan->pTxHpf;
1921 pChan->sdbg->source [9]=pChan->pTxPreEmp;
1922 pChan->sdbg->source [10]=pChan->pTxLimiter;
1923 pChan->sdbg->source [11]=pChan->pTxComposite;
1924 pChan->sdbg->source [12]=pChan->pTxLsdLpf;
1927 for(i=0;i<XPMR_DEBUG_CHANS;i++){
1928 if(pChan->sdbg->trace[i]>=0)pChan->sdbg->point[pChan->sdbg->trace[i]]=i;
1930 pChan->sdbg->mode=1;
1935 pSps=pChan->spsLsdGen=createPmrSps(pChan);
1937 pSps->sink=pChan->pTxLsd;
1940 pSps->sigProc=LsdGen;
1941 pSps->nSamples=pChan->nSamplesTx;
1942 pSps->outputGain=(.25*M_Q8);
1944 pSps->interpolate=1;
1949 // General Purpose Function Generator
1950 pSps=pChan->spsSigGen1=createPmrSps(pChan);
1951 pSps->sink=pChan->pSigGen1;
1954 pSps->sigProc=SigGen;
1955 pSps->nSamples=pChan->nSamplesTx;
1956 pSps->sampleRate=SAMPLE_RATE_NETWORK;
1957 pSps->freq=10000; // in increments of 0.1 Hz
1958 pSps->outputGain=(.25*M_Q8);
1960 pSps->interpolate=1;
1966 pSps = pChan->spsSigGen0 = createPmrSps(pChan);
1967 pSps->sink=pChan->pTxLsd;
1968 pSps->sigProc=SigGen;
1971 pSps->nSamples=pChan->nSamplesTx;
1972 pSps->sampleRate=SAMPLE_RATE_NETWORK;
1973 pSps->freq=1000; // in 0.1 Hz steps
1974 pSps->outputGain=(0.5*M_Q8);
1976 pSps->interpolate=1;
1980 // Tx LSD Low Pass Filter
1981 pSps=pChan->spsTxLsdLpf=createPmrSps(pChan);
1982 pSps->source=pChan->pTxLsd;
1983 pSps->sink=pChan->pTxLsdLpf;
1984 pSps->sigProc=pmr_gp_fir;
1988 pSps->nSamples=pChan->nSamplesTx;
1989 pSps->decimator=pSps->decimate=1;
1990 pSps->interpolate=1;
1991 pSps->inputGain=(1*M_Q8);
1992 pSps->outputGain=(1*M_Q8);
1994 // configure the longer, lower cutoff filter by default
1995 pSps->ncoef=taps_fir_lpf_215_9_88;
1997 pSps->coef=(void*)coef_fir_lpf_215_9_88;
1998 pSps->nx=taps_fir_lpf_215_9_88;
2000 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2001 pSps->calcAdjust=gain_fir_lpf_215_9_88;
2003 pSps->inputGain=(1*M_Q8);
2004 pSps->outputGain=(1*M_Q8);
2006 TRACEF(1,("spsTxLsdLpf = sps \n"));
2008 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2012 TRACEF(1,("create rx\n"));
2015 // allocate space for first sps and set pointers
2016 pSps=pChan->spsRx=createPmrSps(pChan);
2017 pSps->source=NULL; //set when called
2018 pSps->sink=pChan->pRxBase;
2019 pSps->sigProc=pmr_rx_frontend;
2021 pSps->decimator=pSps->decimate=6;
2022 pSps->interpolate=1;
2023 pSps->nSamples=pChan->nSamplesRx;
2024 pSps->ncoef=taps_fir_bpf_noise_1;
2026 pSps->coef=(void*)coef_fir_lpf_3K_1;
2027 pSps->coef2=(void*)coef_fir_bpf_noise_1;
2028 pSps->nx=taps_fir_bpf_noise_1;
2030 pSps->x=(void*)(calloc(pSps->nx,pSps->size_coef));
2031 pSps->calcAdjust=(gain_fir_lpf_3K_1*256)/0x0100;
2032 pSps->outputGain=(1.0*M_Q8);
2034 pSps->hyst=pChan->rxCarrierHyst;
2035 pSps->setpt=pChan->rxCarrierPoint;
2036 pChan->prxSquelchAdjust=&pSps->setpt;
2037 #if XPMR_DEBUG0 == 1
2038 pSps->debugBuff0=pChan->pRxDemod;
2039 pSps->debugBuff1=pChan->pRxNoise;
2040 pSps->debugBuff2=pChan->prxDebug0;
2044 // allocate space for next sps and set pointers
2045 // Rx SubAudible Decoder Low Pass Filter
2046 pSps=pChan->spsRxLsd=pSps->nextSps=createPmrSps(pChan);
2047 pSps->source=pChan->pRxBase;
2048 pSps->sink=pChan->pRxLsd;
2049 pSps->sigProc=pmr_gp_fir;
2053 pSps->nSamples=pChan->nSamplesRx;
2054 pSps->decimator=pSps->decimate=1;
2055 pSps->interpolate=1;
2057 // configure the the larger, lower cutoff filter by default
2058 pSps->ncoef=taps_fir_lpf_215_9_88;
2060 pSps->coef=(void*)coef_fir_lpf_215_9_88;
2061 pSps->nx=taps_fir_lpf_215_9_88;
2063 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2064 pSps->calcAdjust=gain_fir_lpf_215_9_88;
2066 pSps->inputGain=(1*M_Q8);
2067 pSps->outputGain=(1*M_Q8);
2068 pChan->prxCtcssMeasure=pSps->sink;
2069 pChan->prxCtcssAdjust=&(pSps->outputGain);
2071 // CTCSS CenterSlicer
2072 pSps=pChan->spsRxLsdNrz=pSps->nextSps=createPmrSps(pChan);
2073 pSps->source=pChan->pRxLsd;
2074 pSps->sink=pChan->pRxDcTrack;
2075 pSps->buff=pChan->pRxLsdLimit;
2076 pSps->sigProc=CenterSlicer;
2077 pSps->nSamples=pChan->nSamplesRx;
2078 pSps->discfactor=LSD_DFS; // centering time constant
2079 pSps->inputGain=(1*M_Q8);
2080 pSps->outputGain=(1*M_Q8);
2081 pSps->setpt=4900; // ptp clamp for DC centering
2082 pSps->inputGainB=625; // peak output limiter clip point
2087 pSps=pSps->nextSps=createPmrSps(pChan);
2088 pChan->spsRxHpf=pSps;
2089 pSps->source=pChan->pRxBase;
2090 pSps->sink=pChan->pRxHpf;
2091 pSps->sigProc=pmr_gp_fir;
2095 pSps->nSamples=pChan->nSamplesRx;
2096 pSps->decimator=pSps->decimate=1;
2097 pSps->interpolate=1;
2098 pSps->ncoef=taps_fir_hpf_300_9_66;
2100 pSps->coef=(void*)coef_fir_hpf_300_9_66;
2101 pSps->nx=taps_fir_hpf_300_9_66;
2103 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2104 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2105 pSps->calcAdjust=gain_fir_hpf_300_9_66;
2106 pSps->inputGain=(1*M_Q8);
2107 pSps->outputGain=(1*M_Q8);
2108 pChan->prxVoiceAdjust=&(pSps->outputGain);
2109 pChan->spsRxOut=pSps;
2111 // allocate space for next sps and set pointers
2113 if(pChan->rxDeEmpEnable){
2114 pSps=pSps->nextSps=createPmrSps(pChan);
2115 pChan->spsRxDeEmp=pSps;
2116 pSps->source=pChan->pRxHpf;
2117 pSps->sink=pChan->pRxSpeaker;
2118 pChan->spsRxOut=pSps; // OUTPUT STRUCTURE!
2119 pSps->sigProc=gp_inte_00;
2121 pSps->nSamples=pChan->nSamplesRx;
2123 pSps->ncoef=taps_int_lpf_300_1_2;
2125 pSps->coef=(void*)coef_int_lpf_300_1_2;
2127 pSps->nx=taps_int_lpf_300_1_2;
2129 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2130 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2131 pSps->calcAdjust=gain_int_lpf_300_1_2/2;
2132 pSps->inputGain=(1.0*M_Q8);
2133 pSps->outputGain=(1.0*M_Q8);
2134 pChan->prxVoiceMeasure=pSps->sink;
2135 pChan->prxVoiceAdjust=&(pSps->outputGain);
2138 if(pChan->rxDelayLineEnable)
2140 TRACEF(1,("create delayline\n"));
2141 pSps=pChan->spsDelayLine=pSps->nextSps=createPmrSps(pChan);
2142 pSps->sigProc=DelayLine;
2143 pSps->source=pChan->pRxSpeaker;
2144 pSps->sink=pChan->pRxSpeaker;
2146 pSps->inputGain=1*M_Q8;
2147 pSps->outputGain=1*M_Q8;
2148 pSps->nSamples=pChan->nSamplesRx;
2149 pSps->buffSize=4096;
2150 pSps->buff=calloc(4096,2); // one second maximum
2151 pSps->buffLead = (SAMPLE_RATE_NETWORK*0.100);
2152 pSps->buffOutIndex=0;
2155 if(pChan->rxCdType==CD_XPMR_VOX)
2157 TRACEF(1,("create vox measureblock\n"));
2158 pChan->prxVoxMeas=calloc(pChan->nSamplesRx,2);
2160 pSps=pChan->spsRxVox=pSps->nextSps=createPmrSps(pChan);
2161 pSps->sigProc=MeasureBlock;
2162 pSps->parentChan=pChan;
2163 pSps->source=pChan->pRxBase;
2164 pSps->sink=pChan->prxVoxMeas;
2165 pSps->inputGain=1*M_Q8;
2166 pSps->outputGain=1*M_Q8;
2167 pSps->nSamples=pChan->nSamplesRx;
2169 if(pChan->rxSqVoxAdj==0)
2170 pSps->setpt=(0.011*M_Q15);
2172 pSps->setpt=(pChan->rxSqVoxAdj);
2173 pSps->hyst=(pSps->setpt/10);
2177 // tuning measure block
2178 pSps=pChan->spsMeasure=pSps->nextSps=createPmrSps(pChan);
2179 pSps->source=pChan->spsRx->sink;
2180 pSps->sink=pChan->prxMeasure;
2181 pSps->sigProc=MeasureBlock;
2183 pSps->nSamples=pChan->nSamplesRx;
2184 pSps->discfactor=10;
2186 pSps->nextSps=NULL; // last sps in chain RX
2189 // CREATE TRANSMIT CHAIN
2190 TRACEF(1,("create tx\n"));
2194 // allocate space for first sps and set pointers
2196 // Tx HPF SubAudible
2197 if(pChan->txHpfEnable)
2199 pSps=createPmrSps(pChan);
2201 pSps->source=pChan->pTxBase;
2202 pSps->sink=pChan->pTxHpf;
2203 pSps->sigProc=pmr_gp_fir;
2207 pSps->nSamples=pChan->nSamplesTx;
2208 pSps->decimator=pSps->decimate=1;
2209 pSps->interpolate=1;
2210 pSps->ncoef=taps_fir_hpf_300_9_66;
2212 pSps->coef=(void*)coef_fir_hpf_300_9_66;
2213 pSps->nx=taps_fir_hpf_300_9_66;
2215 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2216 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2217 pSps->calcAdjust=gain_fir_hpf_300_9_66;
2218 pSps->inputGain=(1*M_Q8);
2219 pSps->outputGain=(1*M_Q8);
2220 inputTmp=pChan->pTxHpf;
2224 if(pChan->txPreEmpEnable)
2226 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2227 else pSps=pSps->nextSps=createPmrSps(pChan);
2229 pSps->source=inputTmp;
2230 pSps->sink=pChan->pTxPreEmp;
2232 pSps->sigProc=gp_diff;
2234 pSps->nSamples=pChan->nSamplesTx;
2236 pSps->ncoef=taps_int_hpf_4000_1_2;
2238 pSps->coef=(void*)coef_int_hpf_4000_1_2;
2240 pSps->nx=taps_int_hpf_4000_1_2;
2242 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2243 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2245 pSps->calcAdjust=gain_int_hpf_4000_1_2;
2246 pSps->inputGain=(1*M_Q8);
2247 pSps->outputGain=(1*M_Q8); // to match flat at 1KHz
2248 inputTmp=pSps->sink;
2252 if(pChan->txLimiterEnable)
2254 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2255 else pSps=pSps->nextSps=createPmrSps(pChan);
2256 pSps->source=inputTmp;
2257 pSps->sink=pChan->pTxLimiter;
2258 pSps->sigProc=SoftLimiter;
2260 pSps->nSamples=pChan->nSamplesTx;
2261 pSps->inputGain=(1*M_Q8);
2262 pSps->outputGain=(1*M_Q8);
2264 inputTmp=pSps->sink;
2267 // Composite Mix of Voice and LSD
2268 if((pChan->txMixA==TX_OUT_COMPOSITE)||(pChan->txMixB==TX_OUT_COMPOSITE))
2271 pSps=pChan->spsTx=createPmrSps(pChan);
2273 pSps=pSps->nextSps=createPmrSps(pChan);
2274 pSps->source=inputTmp;
2275 pSps->sourceB=pChan->pTxLsdLpf; //asdf ??? !!! maw pTxLsdLpf
2276 pSps->sink=pChan->pTxComposite;
2277 pSps->sigProc=pmrMixer;
2279 pSps->nSamples=pChan->nSamplesTx;
2280 pSps->inputGain=2*M_Q8;
2281 pSps->inputGainB=1*M_Q8/8;
2282 pSps->outputGain=1*M_Q8;
2284 inputTmp=pSps->sink;
2285 pChan->ptxCtcssAdjust=&pSps->inputGainB;
2288 // Chan A Upsampler and Filter
2289 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2290 else pSps=pSps->nextSps=createPmrSps(pChan);
2292 pChan->spsTxOutA=pSps;
2293 if(!pChan->spsTx)pChan->spsTx=pSps;
2295 if(pChan->txMixA==TX_OUT_COMPOSITE)
2297 pSps->source=pChan->pTxComposite;
2299 else if(pChan->txMixA==TX_OUT_LSD)
2301 pSps->source=pChan->pTxLsdLpf;
2303 else if(pChan->txMixA==TX_OUT_VOICE)
2305 pSps->source=pChan->pTxHpf;
2307 else if (pChan->txMixA==TX_OUT_AUX)
2309 pSps->source=inputTmp;
2313 pSps->source=NULL; // maw sph asdf !!! no blow up
2314 pSps->source=inputTmp;
2317 pSps->sink=pChan->pTxOut;
2318 pSps->sigProc=pmr_gp_fir;
2322 pSps->nSamples=pChan->nSamplesTx;
2323 pSps->interpolate=6;
2324 pSps->ncoef=taps_fir_lpf_3K_1;
2326 pSps->coef=(void*)coef_fir_lpf_3K_1;
2327 pSps->nx=taps_fir_lpf_3K_1;
2329 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2330 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2331 pSps->calcAdjust=gain_fir_lpf_3K_1;
2332 pSps->inputGain=(1*M_Q8);
2333 pSps->outputGain=(1*M_Q8);
2334 if(pChan->txMixA==pChan->txMixB)pSps->monoOut=1;
2335 else pSps->monoOut=0;
2338 // Chan B Upsampler and Filter
2339 if((pChan->txMixA!=pChan->txMixB)&&(pChan->txMixB!=TX_OUT_OFF))
2341 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2342 else pSps=pSps->nextSps=createPmrSps(pChan);
2344 pChan->spsTxOutB=pSps;
2345 if(pChan->txMixB==TX_OUT_COMPOSITE)
2347 pSps->source=pChan->pTxComposite;
2349 else if(pChan->txMixB==TX_OUT_LSD)
2351 pSps->source=pChan->pTxLsdLpf;
2352 // pChan->ptxCtcssAdjust=&pSps->inputGain;
2354 else if(pChan->txMixB==TX_OUT_VOICE)
2356 pSps->source=inputTmp;
2358 else if(pChan->txMixB==TX_OUT_AUX)
2360 pSps->source=pChan->pTxHpf;
2367 pSps->sink=pChan->pTxOut;
2368 pSps->sigProc=pmr_gp_fir;
2373 pSps->nSamples=pChan->nSamplesTx;
2374 pSps->interpolate=6;
2375 pSps->ncoef=taps_fir_lpf_3K_1;
2377 pSps->coef=(void*)coef_fir_lpf_3K_1;
2378 pSps->nx=taps_fir_lpf_3K_1;
2380 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2381 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2382 pSps->calcAdjust=(gain_fir_lpf_3K_1);
2383 pSps->inputGain=(1*M_Q8);
2384 pSps->outputGain=(1*M_Q8);
2389 // Configure Coded Signaling
2390 code_string_parse(pChan);
2392 pChan->smode=SMODE_NULL;
2393 pChan->smodewas=SMODE_NULL;
2394 pChan->smodetime=2500;
2395 pChan->smodetimer=0;
2396 pChan->b.smodeturnoff=0;
2398 pChan->txsettletimer=0;
2400 TRACEF(1,("createPmrChannel() end\n"));
2406 i16 destroyPmrChannel(t_pmr_chan *pChan)
2408 #if XPMR_DEBUG0 == 1
2411 t_pmr_sps *pmr_sps, *tmp_sps;
2413 TRACEF(1,("destroyPmrChannel()\n"));
2415 free(pChan->pRxDemod);
2416 free(pChan->pRxNoise);
2417 free(pChan->pRxBase);
2418 free(pChan->pRxHpf);
2419 free(pChan->pRxLsd);
2420 free(pChan->pRxSpeaker);
2421 free(pChan->pRxDcTrack);
2422 if(pChan->pRxLsdLimit)free(pChan->pRxLsdLimit);
2423 free(pChan->pTxBase);
2424 free(pChan->pTxHpf);
2425 free(pChan->pTxPreEmp);
2426 free(pChan->pTxLimiter);
2427 free(pChan->pTxLsd);
2428 free(pChan->pTxLsdLpf);
2429 if(pChan->pTxComposite)free(pChan->pTxComposite);
2430 free(pChan->pTxOut);
2432 if(pChan->prxMeasure)free(pChan->prxMeasure);
2433 if(pChan->pSigGen0)free(pChan->pSigGen0);
2434 if(pChan->pSigGen1)free(pChan->pSigGen1);
2437 #if XPMR_DEBUG0 == 1
2438 //if(pChan->prxDebug)free(pChan->prxDebug);
2439 if(pChan->ptxDebug)free(pChan->ptxDebug);
2440 free(pChan->prxDebug0);
2441 free(pChan->prxDebug1);
2442 free(pChan->prxDebug2);
2443 free(pChan->prxDebug3);
2445 free(pChan->ptxDebug0);
2446 free(pChan->ptxDebug1);
2447 free(pChan->ptxDebug2);
2448 free(pChan->ptxDebug3);
2450 free(pChan->rxCtcss->pDebug0);
2451 free(pChan->rxCtcss->pDebug1);
2453 for(i=0;i<CTCSS_NUM_CODES;i++)
2455 free(pChan->rxCtcss->tdet[i].pDebug0);
2456 free(pChan->rxCtcss->tdet[i].pDebug1);
2457 free(pChan->rxCtcss->tdet[i].pDebug2);
2458 free(pChan->rxCtcss->tdet[i].pDebug3);
2465 free(pChan->pRxCtcss);
2467 pmr_sps=pChan->spsRx;
2469 if(pChan->sdbg)free(pChan->sdbg);
2474 pmr_sps = tmp_sps->nextSps;
2475 destroyPmrSps(tmp_sps);
2484 t_pmr_sps *createPmrSps(t_pmr_chan *pChan)
2488 TRACEF(1,("createPmrSps()\n"));
2490 pSps = (t_pmr_sps *)calloc(sizeof(t_pmr_sps),1);
2492 if(!pSps)printf("Error: createPmrSps()\n");
2494 pSps->parentChan=pChan;
2495 pSps->index=pChan->spsIndex++;
2497 // pSps->x=calloc(pSps->nx,pSps->size_x);
2503 i16 destroyPmrSps(t_pmr_sps *pSps)
2505 TRACEJ(1,("destroyPmrSps(%i)\n",pSps->index));
2507 if(pSps->x!=NULL)free(pSps->x);
2512 PmrTx - takes data from network and holds it for PmrRx
2514 i16 PmrTx(t_pmr_chan *pChan, i16 *input)
2516 pChan->frameCountTx++;
2518 TRACEF(5,("PmrTx() start %i\n",pChan->frameCountTx));
2522 if(pptp_p2)ioctl(ppdrvdev,PPDRV_IOC_PINSET,LP_PIN02);
2523 else ioctl(ppdrvdev,PPDRV_IOC_PINCLEAR,LP_PIN02);
2527 printf("PmrTx() pChan == NULL\n");
2531 #if XPMR_DEBUG0 == 1
2532 if(pChan->b.rxCapture && pChan->tracetype==5)
2534 memcpy(pChan->pTxInput,input,pChan->nSamplesRx*2);
2538 //if(pChan->b.radioactive)pChan->dd.debug=1;
2539 //else pChan->dd.debug=0;
2541 dedrift_write(pChan,input);
2546 PmrRx handles a block of data from the usb audio device
2548 i16 PmrRx(t_pmr_chan *pChan, i16 *input, i16 *outputrx, i16 *outputtx)
2554 TRACEC(5,("PmrRx(%p %p %p %p)\n",pChan, input, outputrx, outputtx));
2557 if(pChan->b.radioactive)
2559 pptp_write(1,pChan->frameCountRx&0x00000001);
2564 printf("PmrRx() pChan == NULL\n");
2568 pChan->frameCountRx++;
2570 #if XPMR_DEBUG0 == 1
2571 if(pChan->b.rxCapture)
2573 //if(pChan->prxDebug)memset((void *)pChan->prxDebug,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2574 if(pChan->ptxDebug)memset((void *)pChan->ptxDebug,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2575 if(pChan->sdbg->buffer)
2577 memset((void *)pChan->sdbg->buffer,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2578 pChan->prxDebug=pChan->sdbg->buffer;
2583 pmr_sps=pChan->spsRx; // first sps
2584 pmr_sps->source=input;
2586 if(outputrx!=NULL)pChan->spsRxOut->sink=outputrx; //last sps
2589 if(pChan->inputBlanking>0)
2591 pChan->inputBlanking-=pChan->nSamplesRx;
2592 if(pChan->inputBlanking<0)pChan->inputBlanking=0;
2593 for(i=0;i<pChan->nSamplesRx*6;i++)
2598 if( pChan->rxCpuSaver && !pChan->rxCarrierDetect &&
2599 pChan->smode==SMODE_NULL &&
2600 !pChan->txPttIn && !pChan->txPttOut)
2602 if(!pChan->b.rxhalted)
2604 if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=0;
2605 if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=0;
2606 pChan->b.rxhalted=1;
2607 TRACEC(1,("PmrRx() rx sps halted\n"));
2610 else if(pChan->b.rxhalted)
2612 if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=1;
2613 if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=1;
2614 pChan->b.rxhalted=0;
2615 TRACEC(1,("PmrRx() rx sps un-halted\n"));
2619 while(pmr_sps!=NULL && pmr_sps!=0)
2621 TRACEC(5,("PmrRx() sps %i\n",i++));
2622 pmr_sps->sigProc(pmr_sps);
2623 pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps);
2624 //pmr_sps=NULL; // sph maw
2627 #define XPMR_VOX_HANGTIME 2000
2629 if(pChan->rxCdType==CD_XPMR_VOX)
2631 if(pChan->spsRxVox->compOut)
2633 pChan->rxVoxTimer=XPMR_VOX_HANGTIME; //VOX HangTime in ms
2635 if(pChan->rxVoxTimer>0)
2637 pChan->rxVoxTimer-=MS_PER_FRAME;
2638 pChan->rxCarrierDetect=1;
2642 pChan->rxVoxTimer=0;
2643 pChan->rxCarrierDetect=0;
2648 pChan->rxCarrierDetect=!pChan->spsRx->compOut;
2651 // stop and start these engines instead to eliminate falsing
2652 if( pChan->b.ctcssRxEnable &&
2653 ( (!pChan->b.rxhalted ||
2654 pChan->rxCtcss->decode!=CTCSS_NULL || pChan->smode==SMODE_CTCSS) &&
2655 (pChan->smode!=SMODE_DCS&&pChan->smode!=SMODE_LSD) )
2658 ctcss_detect(pChan);
2662 if(pChan->txPttIn!=pChan->b.pttwas)
2664 pChan->b.pttwas=pChan->txPttIn;
2665 TRACEC(1,("PmrRx() txPttIn=%i\n",pChan->b.pttwas));
2670 xpmrx(pChan,XXO_RXDECODE);
2673 if(pChan->smodetimer>0 && !pChan->txPttIn)
2675 pChan->smodetimer-=MS_PER_FRAME;
2677 if(pChan->smodetimer<=0)
2679 pChan->smodetimer=0;
2680 pChan->smodewas=pChan->smode;
2681 pChan->smode=SMODE_NULL;
2682 pChan->b.smodeturnoff=1;
2683 TRACEC(1,("smode timeout. smode was=%i\n",pChan->smodewas));
2687 if(pChan->rxCtcss->decode > CTCSS_NULL &&
2688 (pChan->smode==SMODE_NULL||pChan->smode==SMODE_CTCSS) )
2690 if(pChan->smode!=SMODE_CTCSS)
2692 TRACEC(1,("smode set=%i code=%i\n",pChan->smode,pChan->rxCtcss->decode));
2693 pChan->smode=pChan->smodewas=SMODE_CTCSS;
2695 pChan->smodetimer=pChan->smodetime;
2699 xpmrx(pChan,XXO_LSDCTL);
2702 //TRACEX(("PmrRx() tx portion.\n"));
2704 // handle radio transmitter ptt input
2706 if( !(pChan->smode==SMODE_DCS||pChan->smode==SMODE_LSD) )
2709 if( pChan->txPttIn && pChan->txState==CHAN_TXSTATE_IDLE )
2711 TRACEC(1,("txPttIn==1 from CHAN_TXSTATE_IDLE && !SMODE_LSD. codeindex=%i %i \n",pChan->rxCtcss->decode, pChan->rxCtcssMap[pChan->rxCtcss->decode] ));
2712 pChan->dd.b.doitnow=1;
2714 if(pChan->smode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2716 if(pChan->rxCtcss->decode>CTCSS_NULL)
2718 if(pChan->rxCtcssMap[pChan->rxCtcss->decode]!=CTCSS_RXONLY)
2720 f=freq_ctcss[pChan->rxCtcssMap[pChan->rxCtcss->decode]];
2725 f=pChan->txctcssdefault_value;
2727 TRACEC(1,("txPttIn - Start CTCSSGen %f \n",f));
2732 pChan->spsSigGen0->freq=f*10;
2733 pSps=pChan->spsTxLsdLpf;
2739 pSps->ncoef=taps_fir_lpf_250_9_66;
2741 pSps->coef=(void*)coef_fir_lpf_250_9_66;
2742 pSps->nx=taps_fir_lpf_250_9_66;
2744 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2745 pSps->calcAdjust=gain_fir_lpf_250_9_66;
2749 pSps->ncoef=taps_fir_lpf_215_9_88;
2751 pSps->coef=(void*)coef_fir_lpf_215_9_88;
2752 pSps->nx=taps_fir_lpf_215_9_88;
2754 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2755 pSps->calcAdjust=gain_fir_lpf_215_9_88;
2759 pChan->spsSigGen0->option=1;
2760 pChan->spsSigGen0->enabled=1;
2761 pChan->spsSigGen0->discounterl=0;
2764 else if(pChan->smode==SMODE_NULL && pChan->txcodedefaultsmode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2766 TRACEC(1,("txPtt Encode txcodedefaultsmode==SMODE_CTCSS %f\n",pChan->txctcssdefault_value));
2767 pChan->spsSigGen0->freq=pChan->txctcssdefault_value*10;
2768 pChan->spsSigGen0->option=1;
2769 pChan->spsSigGen0->enabled=1;
2770 pChan->spsSigGen0->discounterl=0;
2771 pChan->smode=SMODE_CTCSS;
2772 pChan->smodetimer=pChan->smodetime;
2774 else if(pChan->txcodedefaultsmode==SMODE_NULL||pChan->b.txCtcssInhibit)
2776 TRACEC(1,("txPtt Encode txcodedefaultsmode==SMODE_NULL\n"));
2780 printf ("ERROR: txPttIn=%i NOT HANDLED PROPERLY.\n",pChan->txPttIn);
2781 TRACEC(1,("ERROR: txPttIn=%i NOT HANDLED PROPERLY.\n",pChan->txPttIn));
2784 pChan->txState = CHAN_TXSTATE_ACTIVE;
2787 pChan->txsettletimer=pChan->txsettletime;
2789 if(pChan->spsTxOutA)pChan->spsTxOutA->enabled=1;
2790 if(pChan->spsTxOutB)pChan->spsTxOutB->enabled=1;
2791 if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->enabled=1;
2792 if(pChan->txfreq)pChan->b.reprog=1;
2793 TRACEC(1,("PmrRx() TxOn\n"));
2795 else if(pChan->txPttIn && pChan->txState==CHAN_TXSTATE_ACTIVE)
2797 // pChan->smode=SMODE_CTCSS;
2798 pChan->smodetimer=pChan->smodetime;
2800 else if(!pChan->txPttIn && pChan->txState==CHAN_TXSTATE_ACTIVE)
2802 TRACEC(1,("txPttIn==0 from CHAN_TXSTATE_ACTIVE\n"));
2803 if(pChan->smode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2805 if( pChan->txTocType==TOC_NONE || !pChan->b.ctcssTxEnable )
2807 TRACEC(1,("Tx Off Immediate.\n"));
2808 pChan->spsSigGen0->option=3;
2809 pChan->txBufferClear=3;
2810 pChan->txState=CHAN_TXSTATE_FINISHING;
2812 else if(pChan->txTocType==TOC_NOTONE)
2814 pChan->txState=CHAN_TXSTATE_TOC;
2815 pChan->txHangTime=TOC_NOTONE_TIME/MS_PER_FRAME;
2816 pChan->spsSigGen0->option=3;
2817 TRACEC(1,("Tx Turn Off No Tone Start.\n"));
2821 pChan->txState=CHAN_TXSTATE_TOC;
2822 pChan->txHangTime=0;
2823 pChan->spsSigGen0->option=2;
2824 TRACEC(1,("Tx Turn Off Phase Shift Start.\n"));
2829 pChan->txBufferClear=3;
2830 pChan->txState=CHAN_TXSTATE_FINISHING;
2831 TRACEC(1,("Tx Off No SMODE to Finish.\n"));
2834 else if(pChan->txState==CHAN_TXSTATE_TOC)
2836 if( pChan->txPttIn && pChan->smode==SMODE_CTCSS )
2838 TRACEC(1,("Tx Key During HangTime\n"));
2839 pChan->txState = CHAN_TXSTATE_ACTIVE;
2840 pChan->spsSigGen0->option=1;
2841 pChan->spsSigGen0->enabled=1;
2842 pChan->spsSigGen0->discounterl=0;
2845 else if(pChan->txHangTime)
2847 if(--pChan->txHangTime==0)pChan->txState=CHAN_TXSTATE_FINISHING;
2849 else if(pChan->txHangTime<=0 && pChan->spsSigGen0->state==0)
2851 pChan->txBufferClear=3;
2852 pChan->txState=CHAN_TXSTATE_FINISHING;
2853 TRACEC(1,("Tx Off TOC.\n"));
2856 else if(pChan->txState==CHAN_TXSTATE_FINISHING)
2858 if(--pChan->txBufferClear<=0)
2859 pChan->txState=CHAN_TXSTATE_COMPLETE;
2861 else if(pChan->txState==CHAN_TXSTATE_COMPLETE)
2865 } // end of if SMODE==LSD
2870 pChan->spsSigGen0->option=3;
2871 pChan->txState=CHAN_TXSTATE_IDLE;
2872 if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->option=3;
2873 if(pChan->spsTxOutA)pChan->spsTxOutA->option=3;
2874 if(pChan->spsTxOutB)pChan->spsTxOutB->option=3;
2875 if(pChan->rxfreq||pChan->txfreq)pChan->b.reprog=1;
2876 TRACEC(1,("Tx Off hit.\n"));
2885 if(pChan->txsettletimer && pChan->txPttHid )
2887 pChan->txsettletimer-=MS_PER_FRAME;
2888 if(pChan->txsettletimer<0)pChan->txsettletimer=0;
2891 // enable this after we know everything else is working
2892 if( pChan->txCpuSaver &&
2893 !pChan->txPttIn && !pChan->txPttOut &&
2894 pChan->txState==CHAN_TXSTATE_IDLE &&
2895 !pChan->dd.b.doitnow
2898 if(!pChan->b.txhalted)
2900 pChan->b.txhalted=1;
2901 TRACEC(1,("PmrRx() tx sps halted\n"));
2904 else if(pChan->b.txhalted)
2906 pChan->dd.b.doitnow=1;
2907 pChan->b.txhalted=0;
2908 TRACEC(1,("PmrRx() tx sps un-halted\n"));
2911 if(pChan->b.txhalted)return(1);
2913 if(pChan->b.startSpecialTone)
2915 pChan->b.startSpecialTone=0;
2916 pChan->spsSigGen1->option=1;
2917 pChan->spsSigGen1->enabled=1;
2918 pChan->b.doingSpecialTone=1;
2920 else if(pChan->b.stopSpecialTone)
2922 pChan->b.stopSpecialTone=0;
2923 pChan->spsSigGen1->option=0;
2924 pChan->b.doingSpecialTone=0;
2925 pChan->spsSigGen1->enabled=0;
2927 else if(pChan->b.doingSpecialTone)
2929 pChan->spsSigGen1->sink=outputtx;
2930 pChan->spsSigGen1->sigProc(pChan->spsSigGen1);
2931 for(i=0;i<(pChan->nSamplesTx*2*6);i+=2)outputtx[i+1]=outputtx[i];
2935 if(pChan->spsSigGen0 && pChan->spsSigGen0->enabled )
2937 pChan->spsSigGen0->sigProc(pChan->spsSigGen0);
2940 if(pChan->spsSigGen1 && pChan->spsSigGen1->enabled)
2942 pChan->spsSigGen1->sigProc(pChan->spsSigGen1);
2946 pChan->spsLsdGen->sigProc(pChan->spsLsdGen); // maw sph ???
2949 // Do Low Speed Data Low Pass Filter
2950 pChan->spsTxLsdLpf->sigProc(pChan->spsTxLsdLpf);
2953 pmr_sps=pChan->spsTx;
2955 // get tx data from de-drift process
2957 pChan->dd.ptr=pChan->pTxBase;
2961 if(!pChan->spsSigGen1->enabled)
2963 pmr_sps->source=pChan->pTxBase;
2965 else input=pmr_sps->source;
2969 if(pChan->spsTxOutA)pChan->spsTxOutA->sink=outputtx;
2970 if(pChan->spsTxOutB)pChan->spsTxOutB->sink=outputtx;
2974 while(pmr_sps!=NULL && pmr_sps!=0)
2976 //TRACEF(1,("PmrTx() sps %i\n",i++));
2977 pmr_sps->sigProc(pmr_sps);
2978 pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps);
2981 //TRACEF(1,("PmrTx() - outputs \n"));
2982 if(pChan->txMixA==TX_OUT_OFF || !pChan->txPttOut){
2983 for(i=0;i<pChan->nSamplesTx*2*6;i+=2)outputtx[i]=0;
2986 if(pChan->txMixB==TX_OUT_OFF || !pChan->txPttOut ){
2987 for(i=0;i<pChan->nSamplesTx*2*6;i+=2)outputtx[i+1]=0;
2991 if( pChan->b.radioactive && pChan->b.pptp_p1!=pChan->txPttOut)
2993 pChan->b.pptp_p1=pChan->txPttOut;
2994 pptp_write(0,pChan->b.pptp_p1);
2998 #if XPMR_DEBUG0 == 1
2999 // TRACEF(1,("PmrRx() - debug outputs \n"));
3000 if(pChan->b.rxCapture){
3001 for(i=0;i<pChan->nSamplesRx;i++)
3003 pChan->pRxDemod[i]=input[i*2*6];
3004 pChan->pTstTxOut[i]=outputtx[i*2*6+0]; // txa
3005 //pChan->pTstTxOut[i]=outputtx[i*2*6+1]; // txb
3006 TSCOPE((RX_NOISE_TRIG, pChan->sdbg, i, (pChan->rxCarrierDetect*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
3007 TSCOPE((RX_CTCSS_DECODE, pChan->sdbg, i, pChan->rxCtcss->decode*(M_Q14/CTCSS_NUM_CODES)));
3008 TSCOPE((RX_SMODE, pChan->sdbg, i, pChan->smode*(XPMR_TRACE_AMP/4)));
3009 TSCOPE((TX_PTT_IN, pChan->sdbg, i, (pChan->txPttIn*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
3010 TSCOPE((TX_PTT_OUT, pChan->sdbg, i, (pChan->txPttOut*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
3011 TSCOPE((TX_DEDRIFT_LEAD, pChan->sdbg, i, pChan->dd.lead*8));
3012 TSCOPE((TX_DEDRIFT_ERR, pChan->sdbg, i, pChan->dd.err*16));
3013 TSCOPE((TX_DEDRIFT_FACTOR, pChan->sdbg, i, pChan->dd.factor*16));
3014 TSCOPE((TX_DEDRIFT_DRIFT, pChan->sdbg, i, pChan->dd.drift*16));
3019 strace2(pChan->sdbg);
3020 TRACEC(5,("PmrRx() return cd=%i smode=%i txPttIn=%i txPttOut=%i \n",pChan->rxCarrierDetect,pChan->smode,pChan->txPttIn,pChan->txPttOut));
3024 parallel binary programming of an RF Transceiver*/
3026 void ppbinout (u8 chan)
3032 ppdrvdev = open("/dev/ppdrv_device", 0);
3036 ast_log(LOG_ERROR, "open /dev/ppdrv_ppdrvdev returned %i\n",ppdrvdev);
3041 if(chan&0x01)i|=BIN_PROG_0;
3042 if(chan&0x02)i|=BIN_PROG_1;
3043 if(chan&0x04)i|=BIN_PROG_2;
3044 if(chan&0x08)i|=BIN_PROG_3;
3046 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3047 //ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3048 //ioctl(ppdrvdev, PPDRV_IOC_PINSET, i );
3049 ioctl(ppdrvdev, PPDRV_IOC_PINSET, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3050 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, i );
3052 // ioctl(ppdrvdev, PPDRV_IOC_PINSET, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0 );
3053 ast_log(LOG_NOTICE, "mask=%i 0x%x\n",i,i);
3057 SPI Programming of an RF Transceiver
3058 need to add permissions check and mutex
3061 need to add permissions check and mutex
3063 void ppspiout (u32 spidata)
3066 static char firstrun=0;
3072 ast_log(LOG_ERROR, "no parallel port permission ppdrvdev %i\n",ppdrvdev);
3076 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3077 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3082 for(ii=0;ii<PP_BIT_TIME*200;ii++);
3086 for(ii=0;ii<PP_BIT_TIME*4;ii++);
3089 bitselect=0x00080000;
3091 for(i=0;i<(PP_REG_LEN-12);i++)
3093 if((bitselect&spidata))
3094 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_DATA );
3096 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_DATA );
3098 for(ii=0;ii<PP_BIT_TIME;ii++);
3100 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_CLK );
3101 for(ii=0;ii<PP_BIT_TIME;ii++);
3102 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK );
3103 for(ii=0;ii<PP_BIT_TIME;ii++);
3105 bitselect=(bitselect>>1);
3107 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA );
3108 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_ENABLE );
3109 for(ii=0;ii<PP_BIT_TIME;ii++);
3110 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_ENABLE );
3115 now assumes calling thread secures permissions
3116 could set up a separate thread to program the radio? yuck!
3119 void progdtx(t_pmr_chan *pChan)
3122 //static u32 progcount=0;
3131 TRACEC(1,("\nprogdtx() %i %i %i\n",pChan->rxfreq,pChan->txfreq,0));
3134 ppdrvdev = open("/dev/ppdrv_device", 0);
3138 ast_log(LOG_ERROR, "open /dev/ppdrv_ppdrvdev returned %i\n",ppdrvdev);
3142 if(pChan->rxfreq>200000000)
3155 shiftreg=(reffreq/stepfreq)<<1;
3156 shiftreg=shiftreg|0x00000001;
3161 synthfreq=pChan->txfreq;
3163 synthfreq=pChan->rxfreq-rxiffreq;
3165 shiftreg=(synthfreq/stepfreq)<<1;
3166 tmp=(shiftreg&0xFFFFFF80)<<1;
3167 shiftreg=tmp+(shiftreg&0x0000007F);
3171 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3172 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA | DTX_ENABLE );
3176 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_TXPWR );
3177 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_TX );
3178 if(pChan->txpower && 0) ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_TXPWR );
3182 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_TX | DTX_TXPWR );
3188 reconciles clock differences between the usb adapter and
3189 asterisk's frame rate clock
3190 take out all accumulated drift error on these events:
3191 before transmitter on
3192 when ptt release from mobile units detected
3194 void dedrift(t_pmr_chan *pChan)
3196 TRACEC(5,("dedrift()\n"));
3198 if(pChan->dd.option==9)
3200 TRACEF(1,("dedrift(9)\n"));
3201 pChan->dd.framesize=DDB_FRAME_SIZE;
3202 pChan->dd.frames=DDB_FRAMES_IN_BUFF;
3203 pChan->dd.buffersize = pChan->dd.frames * pChan->dd.framesize;
3204 pChan->dd.buff=calloc(DDB_FRAME_SIZE*DDB_FRAMES_IN_BUFF,2);
3205 pChan->dd.modulus=DDB_ERR_MODULUS;
3206 pChan->dd.inputindex=0;
3207 pChan->dd.outputindex=0;
3208 pChan->dd.skew = pChan->dd.lead=0;
3211 pChan->dd.debugcnt=0;
3212 pChan->dd.lock=pChan->dd.b.txlock=pChan->dd.b.rxlock=0;
3213 pChan->dd.initcnt=2;
3214 pChan->dd.timer=10000/20;
3216 pChan->dd.factor=pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3217 pChan->dd.txframecnt=pChan->dd.rxframecnt=0;
3218 // clear the buffer too!
3221 else if(pChan->dd.option==8)
3223 free(pChan->dd.buff);
3225 pChan->dd.b.txlock=pChan->dd.b.rxlock=0;
3228 else if(pChan->dd.initcnt==0)
3230 const i32 a0 = 26231;
3231 const i32 a1 = 26231;
3232 const i32 b0 = 32768;
3233 const i32 b1 = -32358;
3240 inputindex = pChan->dd.inputindex;
3241 pChan->dd.skew = pChan->dd.txframecnt-pChan->dd.rxframecnt;
3242 pChan->dd.rxframecnt++;
3244 // pull data from buffer
3245 if( (pChan->dd.outputindex + pChan->dd.framesize) > pChan->dd.buffersize )
3249 dofirst = pChan->dd.buffersize - pChan->dd.outputindex;
3250 donext = pChan->dd.framesize - dofirst;
3251 vptr = (void*)(pChan->dd.ptr);
3252 memcpy(vptr,(void*)(pChan->dd.buff + pChan->dd.outputindex),dofirst*2);
3253 vptr=(void*)(pChan->dd.ptr + dofirst);
3254 memcpy(vptr,(void*)(pChan->dd.buff),donext*2);
3258 memcpy(pChan->dd.ptr,(void*)(pChan->dd.buff + pChan->dd.outputindex),pChan->dd.framesize*2);
3261 // compute clock error and correction factor
3262 if(pChan->dd.outputindex > inputindex)
3264 pChan->dd.lead = (inputindex + pChan->dd.buffersize) - pChan->dd.outputindex;
3268 pChan->dd.lead = inputindex - pChan->dd.outputindex;
3270 pChan->dd.err = pChan->dd.lead - (pChan->dd.buffersize/2);
3272 // WinFilter, IIR Fs=50, Fc=0.1
3273 pChan->dd.x1 = pChan->dd.x0;
3274 pChan->dd.y1 = pChan->dd.y0;
3275 pChan->dd.x0 = pChan->dd.err;
3276 pChan->dd.y0 = a0 * pChan->dd.x0;
3277 pChan->dd.y0 += (a1 * pChan->dd.x1 - (b1 * pChan->dd.y1));
3279 accum = pChan->dd.y0/dg;
3281 pChan->dd.factor=accum;
3285 // event sync'd correction
3286 if(pChan->dd.b.doitnow)
3288 pChan->dd.b.doitnow=0;
3289 indextweak=pChan->dd.factor;
3290 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3291 pChan->dd.timer=20000/MS_PER_FRAME;
3293 // coarse lead adjustment if really far out of range
3294 else if( pChan->dd.lead >= pChan->dd.framesize*(DDB_FRAMES_IN_BUFF-2) )
3296 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3297 indextweak += (pChan->dd.framesize*5/4);
3299 else if(pChan->dd.lead <= pChan->dd.framesize*2 )
3301 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3302 indextweak -= (pChan->dd.framesize*5/4);
3307 if(pChan->dd.timer>0)pChan->dd.timer--;
3308 if(pChan->dd.timer==0 && abs(pChan->dd.factor)>=16)
3310 indextweak=pChan->dd.factor;
3311 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3312 pChan->dd.timer=20000/MS_PER_FRAME;
3316 #if XPMR_DEBUG0 == 1
3317 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));
3320 // set the output index based on lead and clock offset
3321 pChan->dd.outputindex = (pChan->dd.outputindex + pChan->dd.framesize + indextweak)%pChan->dd.buffersize;
3326 void dedrift_write(t_pmr_chan *pChan, i16 *src )
3330 TRACEF(5,("dedrift_write()\n"));
3331 vptr = pChan->dd.buff + pChan->dd.inputindex;
3332 memcpy(vptr, src, pChan->dd.framesize*2);
3333 pChan->dd.inputindex = (pChan->dd.inputindex + pChan->dd.framesize) % pChan->dd.buffersize;
3334 pChan->dd.txframecnt++;
3335 if(pChan->dd.initcnt!=0)pChan->dd.initcnt--;
3336 pChan->dd.accum+=pChan->dd.framesize;