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>
66 #include "xpmr_coef.h"
69 static i16 pmrChanIndex=0; // count of created pmr instances
70 //static i16 pmrSpsIndex=0;
72 #if (DTX_PROG == 1) || XPMR_PPTP == 1
73 static int ppdrvdev=0;
79 void strace(i16 point, t_sdbg *sdbg, i16 index, i16 value)
81 // make dbg_trace buffer in structure
82 if(!sdbg->mode || sdbg->point[point]<0){
85 sdbg->buffer[(index*XPMR_DEBUG_CHANS) + sdbg->point[point]] = value;
91 void strace2(t_sdbg *sdbg)
94 for(i=0;i<XPMR_DEBUG_CHANS;i++)
99 for(ii=0;ii<SAMPLES_PER_BLOCK;ii++)
101 sdbg->buffer[ii*XPMR_DEBUG_CHANS + i] = sdbg->source[i][ii];
108 Hardware Trace Signals via the PC Parallel Port
110 void pptp_init (void)
113 ppdrvdev = open("/dev/ppdrv_device", 0);
117 ast_log(LOG_ERROR, "open /dev/ppdrv_ppdrvdev returned %i\n",ppdrvdev);
120 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX | DTX_TP1 | DTX_TP2);
121 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX | DTX_TP1 | DTX_TP2);
125 void pptp_write(i16 bit, i16 state)
129 if(state)ioctl(ppdrvdev,PPDRV_IOC_PINSET,DTX_TP1);
130 else ioctl(ppdrvdev,PPDRV_IOC_PINCLEAR,DTX_TP1);
134 if(state)ioctl(ppdrvdev,PPDRV_IOC_PINSET,DTX_TP2);
135 else ioctl(ppdrvdev,PPDRV_IOC_PINCLEAR,DTX_TP2);
140 take source string allocate and copy
141 copy is modified, delimiters are replaced with zeros to mark
144 string_parse( char *src, char *dest, char **sub)
146 i16 string_parse(char *src, char **dest, char ***ptrs)
152 TRACEJ(2,("string_parse(%s)\n",src));
155 TRACEJ(2,(" source len = %i\n",slen));
165 for(i=0;i<slen+1;i++)
167 TRACEJ(5,(" pd[%i] = %c\n",i,pd[i]));
169 if( p==0 && pd[i]!=',' && pd[i]!=' ' )
173 else if(pd[i]==',' || pd[i]==0 )
182 for(i=0;i<numsub;i++)
184 TRACEJ(5,(" ptstr[%i] = %p %s\n",i,ptstr[i],ptstr[i]));
187 if(*ptrs)free(*ptrs);
188 *ptrs=calloc(numsub,4);
189 for(i=0;i<numsub;i++)
192 TRACEJ(5,(" %i = %s\n",i,(*ptrs)[i]));
194 TRACEJ(5,("string_parse()=%i\n\n",numsub));
199 the parent program defines
200 pRxCodeSrc and pTxCodeSrc string pointers to the list of codes
201 pTxCodeDefault the default Tx Code.
204 i16 code_string_parse(t_pmr_chan *pChan)
208 float f, maxctcsstxfreq;
213 TRACEF(1,("code_string_parse(%i)\n",0));
214 TRACEF(1,("pChan->pRxCodeSrc %s \n",pChan->pRxCodeSrc));
215 TRACEF(1,("pChan->pTxCodeSrc %s \n",pChan->pTxCodeSrc));
216 TRACEF(1,("pChan->pTxCodeDefault %s \n",pChan->pTxCodeDefault));
218 //printf("code_string_parse() %s / %s / %s / %s \n",pChan->name, pChan->pTxCodeDefault,pChan->pTxCodeSrc,pChan->pRxCodeSrc);
220 maxctcssindex=CTCSS_NULL;
221 maxctcsstxfreq=CTCSS_NULL;
222 pChan->txctcssdefault_index=CTCSS_NULL;
223 pChan->txctcssdefault_value=CTCSS_NULL;
225 pChan->b.ctcssRxEnable=pChan->b.ctcssTxEnable=0;
226 pChan->b.dcsRxEnable=pChan->b.dcsTxEnable=0;
227 pChan->b.lmrRxEnable=pChan->b.lmrTxEnable=0;
228 pChan->b.mdcRxEnable=pChan->b.mdcTxEnable=0;
229 pChan->b.dstRxEnable=pChan->b.dstTxEnable=0;
230 pChan->b.p25RxEnable=pChan->b.p25TxEnable=0;
232 if(pChan->spsLsdGen){
233 pChan->spsLsdGen->enabled=0;
234 pChan->spsLsdGen->state=0;
237 TRACEF(1,("code_string_parse(%i) 05\n",0));
239 pChan->numrxcodes = string_parse( pChan->pRxCodeSrc, &(pChan->pRxCodeStr), &(pChan->pRxCode));
240 pChan->numtxcodes = string_parse( pChan->pTxCodeSrc, &(pChan->pTxCodeStr), &(pChan->pTxCode));
242 if(pChan->numrxcodes!=pChan->numtxcodes)printf("ERROR: numrxcodes != numtxcodes \n");
244 pChan->rxCtcss->enabled=0;
245 pChan->rxCtcss->gain=1*M_Q8;
246 pChan->rxCtcss->limit=8192;
247 pChan->rxCtcss->input=pChan->pRxLsdLimit;
248 pChan->rxCtcss->decode=CTCSS_NULL;
250 pChan->rxCtcss->testIndex=0;
251 if(!pChan->rxCtcss->testIndex)pChan->rxCtcss->testIndex=3;
253 pChan->rxctcssfreq[0]=0; // decode now CTCSS_RXONLY
255 for(i=0;i<CTCSS_NUM_CODES;i++)
259 pChan->rxCtcssMap[i]=CTCSS_NULL;
262 TRACEF(1,("code_string_parse(%i) 10\n",0));
265 xpmrx(pChan,XXO_LSDCODEPARSE);
268 // Do Receive Codes String
269 for(i=0;i<pChan->numrxcodes;i++)
274 p=pChan->pStr=pChan->pRxCode[i];
277 if(!xpmrx(pChan,XXO_LSDCODEPARSE_1))
281 ri=CtcssFreqIndex(f);
282 if(ri>maxctcssindex)maxctcssindex=ri;
284 sscanf(pChan->pTxCode[i],"%f",&f);
285 ti=CtcssFreqIndex(f);
286 if(f>maxctcsstxfreq)maxctcsstxfreq=f;
288 if(ri>CTCSS_NULL && ti>CTCSS_NULL)
290 pChan->b.ctcssRxEnable=pChan->b.ctcssTxEnable=1;
291 pChan->rxCtcssMap[ri]=ti;
292 pChan->numrxctcssfreqs++;
293 TRACEF(1,("pChan->rxctcss[%i]=%s pChan->rxCtcssMap[%i]=%i\n",i,pChan->rxctcss[i],ri,ti));
295 else if(ri>CTCSS_NULL && f==0)
297 pChan->b.ctcssRxEnable=1;
298 pChan->rxCtcssMap[ri]=CTCSS_RXONLY;
299 pChan->numrxctcssfreqs++;
300 TRACEF(1,("pChan->rxctcss[%i]=%s pChan->rxCtcssMap[%i]=%i RXONLY\n",i,pChan->rxctcss[i],ri,ti));
304 pChan->numrxctcssfreqs=0;
305 for(ii=0;ii<CTCSS_NUM_CODES;ii++) pChan->rxCtcssMap[ii]=CTCSS_NULL;
306 TRACEF(1,("WARNING: Invalid Channel code detected and ignored. %i %s %s \n",i,pChan->pRxCode[i],pChan->pTxCode[i]));
311 TRACEF(1,("code_string_parse() CTCSS Init Struct %i %i\n",pChan->b.ctcssRxEnable,pChan->b.ctcssTxEnable));
312 if(pChan->b.ctcssRxEnable)
314 pChan->rxHpfEnable=1;
315 pChan->spsRxLsdNrz->enabled=pChan->rxCenterSlicerEnable=1;
316 pChan->rxCtcssDecodeEnable=1;
317 pChan->rxCtcss->enabled=1;
321 pChan->rxHpfEnable=1;
322 pChan->spsRxLsdNrz->enabled=pChan->rxCenterSlicerEnable=0;
323 pChan->rxCtcssDecodeEnable=0;
324 pChan->rxCtcss->enabled=0;
327 TRACEF(1,("code_string_parse() CTCSS Init Decoders \n"));
328 for(i=0;i<CTCSS_NUM_CODES;i++)
331 ptdet=&(pChan->rxCtcss->tdet[i]);
332 ptdet->counterFactor=coef_ctcss_div[i];
334 ptdet->setpt=(M_Q15*0.041); // 0.069
335 ptdet->hyst =(M_Q15*0.0130);
336 ptdet->binFactor=(M_Q15*0.135); // was 0.140
337 ptdet->fudgeFactor=8;
342 TRACEF(1,("code_string_parse() Default Tx Code %s \n",pChan->pTxCodeDefault));
343 pChan->txcodedefaultsmode=SMODE_NULL;
344 p=pChan->pStr=pChan->pTxCodeDefault;
347 if(!lsd_code_parse(pChan,3))
351 ti=CtcssFreqIndex(f);
352 if(f>maxctcsstxfreq)maxctcsstxfreq=f;
356 pChan->b.ctcssTxEnable=1;
357 pChan->txctcssdefault_index=ti;
358 pChan->txctcssdefault_value=f;
359 pChan->spsSigGen0->freq=f*10;
360 pChan->txcodedefaultsmode=SMODE_CTCSS;
361 TRACEF(1,("code_string_parse() Tx Default CTCSS = %s %i %f\n",p,ti,f));
366 // set x for maximum length and just change pointers
367 TRACEF(1,("code_string_parse() Filter Config \n"));
368 pSps=pChan->spsTxLsdLpf;
369 if(pSps->x)free(pSps->x);
370 if(maxctcsstxfreq>203.5)
372 pSps->ncoef=taps_fir_lpf_250_9_66;
374 pSps->coef=(void*)coef_fir_lpf_250_9_66;
375 pSps->nx=taps_fir_lpf_250_9_66;
377 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
378 pSps->calcAdjust=gain_fir_lpf_250_9_66;
379 TRACEF(1,("code_string_parse() Tx Filter Freq High\n"));
383 pSps->ncoef=taps_fir_lpf_215_9_88;
385 pSps->coef=(void*)coef_fir_lpf_215_9_88;
386 pSps->nx=taps_fir_lpf_215_9_88;
388 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
389 pSps->calcAdjust=gain_fir_lpf_215_9_88;
390 TRACEF(1,("code_string_parse() Tx Filter Freq Low\n"));
393 // CTCSS Rx Decoder Low Pass Filter
395 ii= CtcssFreqIndex(203.5);
396 for(i=ii;i<CTCSS_NUM_CODES;i++)
398 if(pChan->rxCtcssMap[i]>CTCSS_NULL)hit=1;
401 pSps=pChan->spsRxLsd;
402 if(pSps->x)free(pSps->x);
405 pSps->ncoef=taps_fir_lpf_250_9_66;
407 pSps->coef=(void*)coef_fir_lpf_250_9_66;
408 pSps->nx=taps_fir_lpf_250_9_66;
410 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
411 pSps->calcAdjust=gain_fir_lpf_250_9_66;
412 TRACEF(1,("code_string_parse() Rx Filter Freq High\n"));
416 pSps->ncoef=taps_fir_lpf_215_9_88;
418 pSps->coef=(void*)coef_fir_lpf_215_9_88;
419 pSps->nx=taps_fir_lpf_215_9_88;
421 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
422 pSps->calcAdjust=gain_fir_lpf_215_9_88;
423 TRACEF(1,("code_string_parse() Rx Filter Freq Low\n"));
426 if(pChan->b.ctcssRxEnable || pChan->b.dcsRxEnable || pChan->b.lmrRxEnable)
428 pChan->rxCenterSlicerEnable=1;
433 pChan->rxCenterSlicerEnable=0;
438 TRACEF(2,("code_string_parse() ctcssRxEnable = %i \n",pChan->b.ctcssRxEnable));
439 TRACEF(2,(" ctcssTxEnable = %i \n",pChan->b.ctcssTxEnable));
440 TRACEF(2,(" dcsRxEnable = %i \n",pChan->b.dcsRxEnable));
441 TRACEF(2,(" lmrRxEnable = %i \n",pChan->b.lmrRxEnable));
442 TRACEF(2,(" txcodedefaultsmode = %i \n",pChan->txcodedefaultsmode));
443 for(i=0;i<CTCSS_NUM_CODES;i++)
445 TRACEF(2,("rxCtcssMap[%i] = %i \n",i,pChan->rxCtcssMap[i]));
450 lsd_code_parse(pChan,5);
453 TRACEF(1,("code_string_parse(%i) end\n",0));
458 Convert a Frequency in Hz to a zero based CTCSS Table index
460 i16 CtcssFreqIndex(float freq)
462 i16 i,hit=CTCSS_NULL;
464 for(i=0;i<CTCSS_NUM_CODES;i++){
465 if(freq==freq_ctcss[i])hit=i;
471 Takes a block of data and low pass filters it.
472 Determines the amplitude of high frequency noise for carrier detect.
473 Decimates input data to change the rate.
475 i16 pmr_rx_frontend(t_pmr_sps *mySps)
477 #define DCgainBpfNoise 65536
479 i16 samples,iOutput, *input, *output, *noutput;
480 i16 *x, *coef, *coef2;
481 i32 i, naccum, outputGain, calcAdjust;
483 i16 nx, hyst, setpt, compOut;
484 i16 amax, amin, apeak, discounteru, discounterl, discfactor;
485 i16 decimator, decimate, doNoise;
487 TRACEJ(5,("pmr_rx_frontend()\n"));
489 if(!mySps->enabled)return(1);
491 decimator = mySps->decimator;
492 decimate = mySps->decimate;
494 input = mySps->source;
495 output = mySps->sink;
496 noutput = mySps->parentChan->pRxNoise;
500 coef2 = mySps->coef2;
502 calcAdjust = mySps->calcAdjust;
503 outputGain = mySps->outputGain;
508 discounteru=mySps->discounteru;
509 discounterl=mySps->discounterl;
510 discfactor=mySps->discfactor;
513 compOut=mySps->compOut;
515 samples=mySps->nSamples*decimate;
519 if(mySps->parentChan->rxCdType!=CD_XPMR_VOX)doNoise=1;
522 for(i=0;i<samples;i++)
526 //shift the old samples
527 for(n=nx-1; n>0; n--)
542 y=((y/calcAdjust)*outputGain)/M_Q8;
545 else if(y<-32767)y=-32767;
547 output[iOutput]=y; // Rx Baseband decimated
548 noutput[iOutput++] = apeak; // Rx Noise
553 // calculate noise output
556 naccum += coef_fir_bpf_noise_1[n] * x[n];
558 naccum /= DCgainBpfNoise;
563 discounteru=discfactor;
565 else if(--discounteru<=0)
567 discounteru=discfactor;
568 amax=(i32)((amax*32700)/32768);
574 discounterl=discfactor;
576 else if(--discounterl<=0)
578 discounterl=discfactor;
579 amin=(i32)((amin*32700)/32768);
589 ((t_pmr_chan *)(mySps->parentChan))->rxRssi=apeak;
591 if(apeak>setpt || (compOut&&(apeak>(setpt-hyst)))) compOut=1;
593 mySps->compOut=compOut;
597 mySps->discounteru=discounteru;
598 mySps->discounterl=discounterl;
604 pmr general purpose fir
605 works on a block of samples
607 i16 pmr_gp_fir(t_pmr_sps *mySps)
609 i32 nsamples,inputGain,outputGain,calcAdjust;
613 i16 nx, hyst, setpt, compOut;
614 i16 amax, amin, apeak=0, discounteru=0, discounterl=0, discfactor;
615 i16 decimator, decimate, interpolate;
616 i16 numChanOut, selChanOut, mixOut, monoOut;
618 TRACEJ(5,("pmr_gp_fir() %i %i\n",mySps->index, mySps->enabled));
620 if(!mySps->enabled)return(1);
622 inputGain = mySps->inputGain;
623 calcAdjust = mySps->calcAdjust;
624 outputGain = mySps->outputGain;
626 input = mySps->source;
627 output = mySps->sink;
632 decimator = mySps->decimator;
633 decimate = mySps->decimate;
634 interpolate = mySps->interpolate;
636 setpt = mySps->setpt;
637 compOut = mySps->compOut;
639 inputGain = mySps->inputGain;
640 outputGain = mySps->outputGain;
641 numChanOut = mySps->numChanOut;
642 selChanOut = mySps->selChanOut;
643 mixOut = mySps->mixOut;
644 monoOut = mySps->monoOut;
649 discfactor=mySps->discfactor;
652 nsamples=mySps->nSamples;
658 for(i=0;i<nsamples;i++)
661 output[(i*2)]=output[(i*2)+1]=0;
663 output[(i*numChanOut)+selChanOut]=0;
669 for(i=0;i<nsamples;i++)
680 for(ix=0;ix<interpolate;ix++)
685 for(n=nx-1; n>0; n--)
687 x[0] = (input[i]*inputGain)/M_Q8;
703 y=((y/calcAdjust)*outputGain)/M_Q8;
707 output[(ii*2)]=output[(ii*2)+1]+=y;
710 output[(ii*numChanOut)+selChanOut]+=y;
715 output[(ii*2)]=output[(ii*2)+1]=y;
718 output[(ii*numChanOut)+selChanOut]=y;
725 // amplitude detector
733 discounteru=discfactor;
735 else if(--discounteru<=0)
737 discounteru=discfactor;
738 amax=(i32)((amax*32700)/32768);
744 discounterl=discfactor;
746 else if(--discounterl<=0)
748 discounterl=discfactor;
749 amin=(i32)((amin*32700)/32768);
752 apeak = (i32)(amax-amin)/2;
754 if(apeak>setpt)compOut=1;
755 else if(compOut&&(apeak<(setpt-hyst)))compOut=0;
759 mySps->decimator = decimator;
764 mySps->discounteru=discounteru;
765 mySps->discounterl=discounterl;
767 mySps->compOut=compOut;
772 general purpose integrator lpf
774 i16 gp_inte_00(t_pmr_sps *mySps)
779 i32 inputGain, outputGain,calcAdjust;
784 i16 coeff00, coeff01;
786 TRACEJ(5,("gp_inte_00() %i\n",mySps->enabled));
787 if(!mySps->enabled)return(1);
789 input = mySps->source;
790 output = mySps->sink;
792 npoints=mySps->nSamples;
794 inputGain=mySps->inputGain;
795 outputGain=mySps->outputGain;
796 calcAdjust=mySps->calcAdjust;
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 inputGain, outputGain, calcAdjust;
834 input = mySps->source;
835 output = mySps->sink;
837 npoints=mySps->nSamples;
839 inputGain=mySps->inputGain;
840 outputGain=mySps->outputGain;
841 calcAdjust=mySps->calcAdjust;
843 coef=(i16*)(mySps->coef);
851 TRACEJ(5,("gp_diff()\n"));
853 for (i=0;i<npoints;i++)
857 temp1 = input[i] * a0;
858 y0 = (temp0 + temp1)/calcAdjust;
859 y0 =(y0*outputGain)/M_Q8;
861 if(y0>32766)y0=32766;
862 else if(y0<-32766)y0=-32766;
870 /* ----------------------------------------------------------------------
873 i16 CenterSlicer(t_pmr_sps *mySps)
875 i16 npoints,lhit,uhit;
876 i16 *input, *output, *buff;
878 i32 inputGain, outputGain, inputGainB;
882 i32 amax; // buffer amplitude maximum
883 i32 amin; // buffer amplitude minimum
884 i32 apeak; // buffer amplitude peak
886 i32 setpt; // amplitude set point for peak tracking
888 i32 discounteru; // amplitude detector integrator discharge counter upper
889 i32 discounterl; // amplitude detector integrator discharge counter lower
890 i32 discfactor; // amplitude detector integrator discharge factor
892 TRACEJ(5,("CenterSlicer() %i\n",mySps->enabled));
893 if(!mySps->enabled)return(1);
895 input = mySps->source;
896 output = mySps->sink; // limited output
899 npoints=mySps->nSamples;
901 inputGain=mySps->inputGain;
902 outputGain=mySps->outputGain;
903 inputGainB=mySps->inputGainB;
909 discounteru=mySps->discounteru;
910 discounterl=mySps->discounterl;
912 discfactor=mySps->discfactor;
913 npoints=mySps->nSamples;
915 for(i=0;i<npoints;i++)
925 if(amin<(amax-setpt))
935 if(amax>(amin+setpt))
942 if((discounteru-=1)<=0 && amax>amin)
944 if((amax-=10)<amin)amax=amin;
948 if((discounterl-=1)<=0 && amin<amax)
950 if((amin+=10)>amax)amin=amax;
953 if(uhit)discounteru=discfactor;
954 if(lhit)discounterl=discfactor;
958 if((amax-=discfactor)<amin)amax=amin;
959 if((amin+=discfactor)>amax)amin=amax;
963 apeak = (amax-amin)/2;
964 center = (amax+amin)/2;
965 accum = accum - center;
967 output[i]=accum; // sink output unlimited/centered.
969 // do limiter function
970 if(accum>inputGainB)accum=inputGainB;
971 else if(accum<-inputGainB)accum=-inputGainB;
976 mySps->parentChan->pRxLsdCen[i]=center; // trace center ref
979 if((tfx++/8)&1) // trace min/max levels
980 mySps->parentChan->pRxLsdCen[i]=amax;
982 mySps->parentChan->pRxLsdCen[i]=amin;
985 if(mySps->parentChan->frameCountRx&0x01) mySps->parentChan->prxDebug1[i]=amax;
986 else mySps->parentChan->prxDebug1[i]=amin;
994 mySps->discounteru=discounteru;
995 mySps->discounterl=discounterl;
999 /* ----------------------------------------------------------------------
1001 determine peak amplitude
1003 i16 MeasureBlock(t_pmr_sps *mySps)
1006 i16 *input, *output;
1008 i32 inputGain, outputGain;
1012 i16 amax; // buffer amplitude maximum
1013 i16 amin; // buffer amplitude minimum
1014 i16 apeak=0; // buffer amplitude peak (peak to peak)/2
1015 i16 setpt; // amplitude set point for amplitude comparator
1017 i32 discounteru; // amplitude detector integrator discharge counter upper
1018 i32 discounterl; // amplitude detector integrator discharge counter lower
1019 i32 discfactor; // amplitude detector integrator discharge factor
1021 TRACEJ(5,("MeasureBlock() %i\n",mySps->enabled));
1023 if(!mySps->enabled)return 1;
1025 if(mySps->option==3)
1027 mySps->amax = mySps->amin = mySps->apeak = \
1028 mySps->discounteru = mySps->discounterl = \
1033 input = mySps->source;
1034 output = mySps->sink;
1036 npoints=mySps->nSamples;
1038 inputGain=mySps->inputGain;
1039 outputGain=mySps->outputGain;
1044 discounteru=mySps->discounteru;
1045 discounterl=mySps->discounterl;
1047 discfactor=mySps->discfactor;
1048 npoints=mySps->nSamples;
1050 for(i=0;i<npoints;i++)
1057 discounteru=discfactor;
1059 else if(--discounteru<=0)
1061 discounteru=discfactor;
1062 amax=(i32)((amax*32700)/32768);
1068 discounterl=discfactor;
1070 else if(--discounterl<=0)
1072 discounterl=discfactor;
1073 amin=(i32)((amin*32700)/32768);
1076 apeak = (i32)(amax-amin)/2;
1077 if(output)output[i]=apeak;
1083 mySps->discounteru=discounteru;
1084 mySps->discounterl=discounterl;
1085 if(apeak>=setpt) mySps->compOut=1;
1086 else mySps->compOut=0;
1088 //TRACEX((" -MeasureBlock()=%i\n",mySps->apeak));
1094 i16 SoftLimiter(t_pmr_sps *mySps)
1097 //i16 samples, lhit,uhit;
1098 i16 *input, *output;
1100 i32 inputGain, outputGain;
1105 i32 amax; // buffer amplitude maximum
1106 i32 amin; // buffer amplitude minimum
1107 //i32 apeak; // buffer amplitude peak
1108 i32 setpt; // amplitude set point for amplitude comparator
1109 i16 compOut; // amplitude comparator output
1111 input = mySps->source;
1112 output = mySps->sink;
1114 inputGain=mySps->inputGain;
1115 outputGain=mySps->outputGain;
1117 npoints=mySps->nSamples;
1120 amax=(setpt*124)/128;
1123 TRACEJ(5,("SoftLimiter() %i %i %i) \n",amin, amax,setpt));
1125 for(i=0;i<npoints;i++)
1128 //accum=input[i]*mySps->inputGain/256;
1132 tmp=((accum-setpt)*4)/128;
1134 if(accum>amax)accum=amax;
1138 else if(accum<-setpt)
1140 tmp=((accum+setpt)*4)/128;
1142 if(accum<amin)accum=amin;
1147 output[i]=(accum*outputGain)/M_Q8;
1153 SigGen() - sine, square function generator
1154 sps overloaded values
1155 discfactor = phase factor
1156 discfactoru = phase index
1157 if source is not NULL then mix it in!
1159 sign table and output gain are in Q15 format (32767=.999)
1161 i16 SigGen(t_pmr_sps *mySps)
1163 #define PH_FRACT_FACT 128
1166 i16 i,outputgain,waveform,numChanOut,selChanOut;
1170 pChan=mySps->parentChan;
1171 TRACEC(5,("SigGen(%i %i %i)\n",mySps->option,mySps->enabled,mySps->state));
1173 if(!mySps->freq ||!mySps->enabled)return 0;
1175 outputgain=mySps->outputGain;
1177 numChanOut=mySps->numChanOut;
1178 selChanOut=mySps->selChanOut;
1180 if(mySps->option==1)
1185 (SAMPLES_PER_SINE*mySps->freq*PH_FRACT_FACT)/mySps->sampleRate/10;
1187 TRACEF(5,(" SigGen() discfactor = %i\n",mySps->discfactor));
1188 if(mySps->discounterl)mySps->state=2;
1190 else if(mySps->option==2)
1192 i16 shiftfactor=CTCSS_TURN_OFF_SHIFT;
1193 // phase shift request
1196 mySps->discounterl=CTCSS_TURN_OFF_TIME-(2*MS_PER_FRAME); //
1198 mySps->discounteru = \
1199 (mySps->discounteru + (((SAMPLES_PER_SINE*shiftfactor)/360)*PH_FRACT_FACT)) % (SAMPLES_PER_SINE*PH_FRACT_FACT);
1200 //printf("shiftfactor = %i\n",shiftfactor);
1203 else if(mySps->option==3)
1205 // stop it and clear the output buffer
1209 for(i=0;i<mySps->nSamples;i++)
1210 mySps->sink[(i*numChanOut)+selChanOut]=0;
1213 else if(mySps->state==2)
1216 mySps->discounterl-=MS_PER_FRAME;
1217 if(mySps->discounterl<=0)
1223 else if(mySps->state==0)
1228 ph=mySps->discounteru;
1230 for(i=0;i<mySps->nSamples;i++)
1235 //tmp=(sinetablex[ph/PH_FRACT_FACT]*amplitude)/M_Q16;
1236 accum=sinetablex[ph/PH_FRACT_FACT];
1237 accum=(accum*outputgain)/M_Q8;
1242 if(ph>SAMPLES_PER_SINE/2)
1243 accum=outputgain/M_Q8;
1245 accum=-outputgain/M_Q8;
1248 if(mySps->source)accum+=mySps->source[i];
1250 mySps->sink[(i*numChanOut)+selChanOut]=accum;
1252 ph=(ph+mySps->discfactor)%(SAMPLES_PER_SINE*PH_FRACT_FACT);
1255 mySps->discounteru=ph;
1261 takes existing buffer and adds source buffer to destination buffer
1262 sink buffer = (sink buffer * gain) + source buffer
1264 i16 pmrMixer(t_pmr_sps *mySps)
1267 i16 i, *input, *inputB, *output;
1268 i16 inputGain, inputGainB; // apply to input data in Q7.8 format
1269 i16 outputGain; // apply to output data in Q7.8 format
1270 i16 discounteru,discounterl,amax,amin,setpt,discfactor;
1271 i16 npoints,uhit,lhit,apeak,measPeak;
1274 pChan=mySps->parentChan;
1275 TRACEF(5,("pmrMixer()\n"));
1277 input = mySps->source;
1278 inputB = mySps->sourceB;
1279 output = mySps->sink;
1281 inputGain=mySps->inputGain;
1282 inputGainB=mySps->inputGainB;
1283 outputGain=mySps->outputGain;
1288 discounteru=mySps->discounteru;
1289 discounterl=mySps->discounteru;
1291 discfactor=mySps->discfactor;
1292 npoints=mySps->nSamples;
1293 measPeak=mySps->measPeak;
1295 for(i=0;i<npoints;i++)
1297 accum = ((input[i]*inputGain)/M_Q8) +
1298 ((inputB[i]*inputGainB)/M_Q8);
1300 accum=(accum*outputGain)/M_Q8;
1309 if(amin<(amax-setpt)){
1314 else if(accum<amin){
1317 if(amax>(amin+setpt)){
1323 if(--discounteru<=0 && amax>0){
1328 if(--discounterl<=0 && amin<0){
1333 if(uhit)discounteru=discfactor;
1334 if(lhit)discounterl=discfactor;
1339 apeak = (amax-amin)/2;
1343 mySps->discounteru=discounteru;
1344 mySps->discounterl=discounterl;
1352 i16 DelayLine(t_pmr_sps *mySps)
1354 i16 *input, *output, *buff;
1355 i16 i, npoints,buffsize,inindex,outindex;
1358 pChan=mySps->parentChan;
1359 TRACEF(5,(" DelayLine() %i\n",mySps->enabled));
1361 input = mySps->source;
1362 output = mySps->sink;
1363 buff = (i16*)(mySps->buff);
1364 buffsize = mySps->buffSize;
1365 npoints = mySps->nSamples;
1367 outindex = mySps->buffOutIndex;
1368 inindex = outindex + mySps->buffLead;
1370 for(i=0;i<npoints;i++)
1372 inindex %= buffsize;
1373 outindex %= buffsize;
1375 buff[inindex]=input[i];
1376 output[i]=buff[outindex];
1380 mySps->buffOutIndex=outindex;
1385 Continuous Tone Coded Squelch (CTCSS) Detector
1387 i16 ctcss_detect(t_pmr_chan *pChan)
1389 i16 i,points2do,*pInput,hit,thit,relax;
1390 i16 tnum, tmp,indexNow,gain,diffpeak;
1392 i16 tv0,tv1,tv2,tv3,indexDebug;
1396 TRACEF(5,("ctcss_detect(%p) %i %i %i %i\n",pChan,
1397 pChan->rxCtcss->enabled,
1399 pChan->rxCtcss->testIndex,
1400 pChan->rxCtcss->decode));
1402 if(!pChan->rxCtcss->enabled)return(1);
1404 relax = pChan->rxCtcss->relax;
1405 pInput = pChan->rxCtcss->input;
1406 gain = pChan->rxCtcss->gain;
1408 if(relax) difftrig=(-0.1*M_Q15);
1409 else difftrig=(-0.05*M_Q15);
1413 //TRACEX((" ctcss_detect() %i %i %i %i\n", CTCSS_NUM_CODES,0,0,0));
1415 for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++)
1422 TRACEF(6,(" ctcss_detect() tnum=%i %i\n",tnum,pChan->rxCtcssMap[tnum]));
1423 //if(tnum==14)printf("ctcss_detect() %i %i %i\n",tnum,pChan->rxCtcssMap[tnum], pChan->rxCtcss->decode );
1425 if( (pChan->rxCtcssMap[tnum]==CTCSS_NULL) ||
1426 (pChan->rxCtcss->decode>CTCSS_NULL && (tnum!= pChan->rxCtcss->decode))
1430 TRACEF(6,(" ctcss_detect() tnum=%i\n",tnum));
1432 ptdet=&(pChan->rxCtcss->tdet[tnum]);
1434 points=points2do=pChan->nSamplesRx;
1435 fudgeFactor=ptdet->fudgeFactor;
1436 binFactor=ptdet->binFactor;
1438 while(ptdet->counter < (points2do*CTCSS_SCOUNT_MUL))
1440 tmp=(ptdet->counter/CTCSS_SCOUNT_MUL)+1;
1441 ptdet->counter-=(tmp*CTCSS_SCOUNT_MUL);
1443 indexNow=points-points2do;
1445 ptdet->counter += ptdet->counterFactor;
1447 accum = pInput[indexNow-1]; // duuuude's major bug fix!
1449 ptdet->z[ptdet->zIndex]+=
1450 (((accum - ptdet->z[ptdet->zIndex])*binFactor)/M_Q15);
1452 peak = abs(ptdet->z[0]-ptdet->z[2]) + abs(ptdet->z[1]-ptdet->z[3]);
1454 if (ptdet->peak < peak)
1455 ptdet->peak += ( ((peak-ptdet->peak)*binFactor)/M_Q15);
1460 static const i16 a0=13723;
1461 static const i16 a1=-13723;
1468 ptdet->zd = ptdet->peak;
1469 temp1 = ptdet->peak * a0;
1470 diffpeak = (temp0 + temp1)/1024;
1473 if(diffpeak<(-0.03*M_Q15))ptdet->dvd-=4;
1474 else if(ptdet->dvd<0)ptdet->dvd++;
1476 if((ptdet->dvd < -12) && diffpeak > (-0.02*M_Q15))ptdet->dvu+=2;
1477 else if(ptdet->dvu)ptdet->dvu--;
1480 if(pChan->rxCtcss->decode==tnum)
1482 if(relax)tmp=(tmp*55)/100;
1483 else tmp=(tmp*80)/100;
1486 if(ptdet->peak > tmp)
1488 if(ptdet->decode<(fudgeFactor*32))ptdet->decode++;
1490 else if(pChan->rxCtcss->decode==tnum)
1492 if(ptdet->peak > ptdet->hyst)ptdet->decode--;
1493 else if(relax) ptdet->decode--;
1494 else ptdet->decode-=4;
1501 if((pChan->rxCtcss->decode==tnum) && !relax && (ptdet->dvu > (0.00075*M_Q15)))
1504 ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=ptdet->dvu=0;
1505 TRACEF(4,("ctcss_detect() turnoff detected by dvdt for tnum = %i.\n",tnum));
1508 if(ptdet->decode<0 || !pChan->rxCarrierDetect)ptdet->decode=0;
1510 if(ptdet->decode>=fudgeFactor)
1513 if(pChan->rxCtcss->decode!=tnum)
1515 ptdet->zd=ptdet->dvu=ptdet->dvd=0;
1519 #if XPMR_DEBUG0 == 1
1520 if(thit>=0 && thit==tnum)
1521 TRACEF(6,(" ctcss_detect() %i %i %i %i \n",tnum,ptdet->peak,ptdet->setpt,ptdet->hyst));
1532 ptdet->lasttv0=ptdet->pDebug0[points-1];
1533 ptdet->lasttv1=ptdet->pDebug1[points-1];
1534 ptdet->lasttv2=ptdet->pDebug2[points-1];
1535 ptdet->lasttv3=ptdet->pDebug3[points-1];
1538 while(indexDebug<indexNow)
1540 ptdet->pDebug0[indexDebug]=ptdet->lasttv0;
1541 ptdet->pDebug1[indexDebug]=ptdet->lasttv1;
1542 ptdet->pDebug2[indexDebug]=ptdet->lasttv2;
1543 ptdet->pDebug3[indexDebug]=ptdet->lasttv3;
1553 ptdet->zIndex=(++ptdet->zIndex)%4;
1555 ptdet->counter-=(points2do*CTCSS_SCOUNT_MUL);
1557 #if XPMR_DEBUG0 == 1
1558 for(i=indexWas;i<points;i++)
1560 ptdet->pDebug0[i]=ptdet->lasttv0;
1561 ptdet->pDebug1[i]=ptdet->lasttv1;
1562 ptdet->pDebug2[i]=ptdet->lasttv2;
1563 ptdet->pDebug3[i]=ptdet->lasttv3;
1568 //TRACEX((" ctcss_detect() thit %i\n",thit));
1570 if(pChan->rxCtcss->BlankingTimer>0)pChan->rxCtcss->BlankingTimer-=points;
1571 if(pChan->rxCtcss->BlankingTimer<0)pChan->rxCtcss->BlankingTimer=0;
1573 if(thit>CTCSS_NULL && pChan->rxCtcss->decode<=CTCSS_NULL && !pChan->rxCtcss->BlankingTimer)
1575 pChan->rxCtcss->decode=thit;
1576 sprintf(pChan->rxctcssfreq,"%.1f",freq_ctcss[thit]);
1577 TRACEC(1,("ctcss decode %i %.1f\n",thit,freq_ctcss[thit]));
1579 else if(thit<=CTCSS_NULL && pChan->rxCtcss->decode>CTCSS_NULL)
1581 pChan->rxCtcss->BlankingTimer=SAMPLE_RATE_NETWORK/5;
1582 pChan->rxCtcss->decode=CTCSS_NULL;
1583 strcpy(pChan->rxctcssfreq,"0");
1584 TRACEC(1,("ctcss decode NULL\n"));
1585 for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++)
1588 ptdet=&(pChan->rxCtcss->tdet[tnum]);
1590 ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=0;
1593 //TRACEX((" ctcss_detect() thit %i %i\n",thit,pChan->rxCtcss->decode));
1599 static i16 TxTestTone(t_pmr_chan *pChan, i16 function)
1603 pChan->spsSigGen1->enabled=1;
1604 pChan->spsSigGen1->option=1;
1605 pChan->spsSigGen1->outputGain=(.23125*M_Q8); // to match *99 level
1606 pChan->spsTx->source=pChan->spsSigGen1->sink;
1610 pChan->spsSigGen1->option=3;
1616 sampling rate is 48KS/s
1617 samples are all 16 bits
1618 samples are filtered and decimated by 1/6th
1620 t_pmr_chan *createPmrChannel(t_pmr_chan *tChan, i16 numSamples)
1625 t_dec_ctcss *pDecCtcss;
1627 TRACEJ(1,("createPmrChannel(%p,%i)\n",tChan,numSamples));
1629 pChan = (t_pmr_chan *)calloc(sizeof(t_pmr_chan),1);
1632 printf("createPmrChannel() failed\n");
1640 pChan->index=pmrChanIndex++;
1641 pChan->nSamplesTx=pChan->nSamplesRx=numSamples;
1643 pDecCtcss = (t_dec_ctcss *)calloc(sizeof(t_dec_ctcss),1);
1644 pChan->rxCtcss=pDecCtcss;
1645 pChan->rxctcssfreq[0]=0;
1648 if(tChan->rptnum>=LSD_CHAN_MAX)tChan->rptnum=0;
1653 printf("createPmrChannel() WARNING: NULL tChan!\n");
1654 pChan->rxNoiseSquelchEnable=0;
1655 pChan->rxHpfEnable=0;
1656 pChan->rxDeEmpEnable=0;
1657 pChan->rxCenterSlicerEnable=0;
1658 pChan->rxCtcssDecodeEnable=0;
1659 pChan->rxDcsDecodeEnable=0;
1661 pChan->rxCarrierPoint = 17000;
1662 pChan->rxCarrierHyst = 2500;
1664 pChan->txHpfEnable=0;
1665 pChan->txLimiterEnable=0;
1666 pChan->txPreEmpEnable=0;
1667 pChan->txLpfEnable=1;
1668 pChan->txMixA=TX_OUT_VOICE;
1669 pChan->txMixB=TX_OUT_LSD;
1673 pChan->rxDemod=tChan->rxDemod;
1674 pChan->rxCdType=tChan->rxCdType;
1675 pChan->rxSquelchPoint = tChan->rxSquelchPoint;
1676 pChan->rxCarrierHyst = 3000;
1677 pChan->rxSqVoxAdj=tChan->rxSqVoxAdj;
1679 pChan->txMod=tChan->txMod;
1680 pChan->txHpfEnable=1;
1681 pChan->txLpfEnable=1;
1683 pChan->pTxCodeDefault=tChan->pTxCodeDefault;
1684 pChan->pRxCodeSrc=tChan->pRxCodeSrc;
1685 pChan->pTxCodeSrc=tChan->pTxCodeSrc;
1687 pChan->txMixA=tChan->txMixA;
1688 pChan->txMixB=tChan->txMixB;
1689 pChan->radioDuplex=tChan->radioDuplex;
1690 pChan->area=tChan->area;
1691 pChan->rptnum=tChan->rptnum;
1692 pChan->idleinterval=tChan->idleinterval;
1693 pChan->turnoffs=tChan->turnoffs;
1694 pChan->b.rxpolarity=tChan->b.rxpolarity;
1695 pChan->b.txpolarity=tChan->b.txpolarity;
1696 pChan->b.dcsrxpolarity=tChan->b.dcsrxpolarity;
1697 pChan->b.dcstxpolarity=tChan->b.dcstxpolarity;
1698 pChan->b.lsdrxpolarity=tChan->b.lsdrxpolarity;
1699 pChan->b.lsdtxpolarity=tChan->b.lsdtxpolarity;
1701 pChan->txsettletime=tChan->txsettletime;
1702 pChan->tracelevel=tChan->tracelevel;
1703 pChan->tracetype=tChan->tracetype;
1704 pChan->ukey=tChan->ukey;
1705 pChan->name=tChan->name;
1709 pChan->txHpfEnable=1;
1710 pChan->txLpfEnable=1;
1712 if(pChan->rxCdType==CD_XPMR_NOISE) pChan->rxNoiseSquelchEnable=1;
1714 if(pChan->rxDemod==RX_AUDIO_FLAT) pChan->rxDeEmpEnable=1;
1716 pChan->rxCarrierPoint=(pChan->rxSquelchPoint*32767)/100;
1717 pChan->rxCarrierHyst = 3000; //pChan->rxCarrierPoint/15;
1719 pChan->rxDcsDecodeEnable=0;
1721 if(pChan->b.ctcssRxEnable || pChan->b.dcsRxEnable || pChan->b.lmrRxEnable)
1723 pChan->rxHpfEnable=1;
1724 pChan->rxCenterSlicerEnable=1;
1725 pChan->rxCtcssDecodeEnable=1;
1729 pChan->txPreEmpEnable=1;
1730 pChan->txLimiterEnable=1;
1736 TRACEF(1,("calloc buffers \n"));
1738 pChan->pRxDemod = calloc(numSamples,2);
1739 pChan->pRxNoise = calloc(numSamples,2);
1740 pChan->pRxBase = calloc(numSamples,2);
1741 pChan->pRxHpf = calloc(numSamples,2);
1742 pChan->pRxLsd = calloc(numSamples,2);
1743 pChan->pRxSpeaker = calloc(numSamples,2);
1744 pChan->pRxCtcss = calloc(numSamples,2);
1745 pChan->pRxDcTrack = calloc(numSamples,2);
1746 pChan->pRxLsdLimit = calloc(numSamples,2);
1748 pChan->pTxInput = calloc(numSamples,2);
1749 pChan->pTxBase = calloc(numSamples,2);
1750 pChan->pTxHpf = calloc(numSamples,2);
1751 pChan->pTxPreEmp = calloc(numSamples,2);
1752 pChan->pTxLimiter = calloc(numSamples,2);
1753 pChan->pTxLsd = calloc(numSamples,2);
1754 pChan->pTxLsdLpf = calloc(numSamples,2);
1755 pChan->pTxComposite = calloc(numSamples,2);
1756 pChan->pSigGen0 = calloc(numSamples,2);
1757 pChan->pSigGen1 = calloc(numSamples,2);
1759 pChan->prxMeasure = calloc(numSamples,2);
1761 pChan->pTxOut = calloc(numSamples,2*2*6); // output buffer
1764 pChan->pLsdEnc = calloc(sizeof(t_encLsd),1);
1767 #if XPMR_DEBUG0 == 1
1768 TRACEF(1,("configure tracing\n"));
1770 pChan->pTstTxOut = calloc(numSamples,2);
1771 pChan->pRxLsdCen = calloc(numSamples,2);
1772 pChan->prxDebug0 = calloc(numSamples,2);
1773 pChan->prxDebug1 = calloc(numSamples,2);
1774 pChan->prxDebug2 = calloc(numSamples,2);
1775 pChan->prxDebug3 = calloc(numSamples,2);
1776 pChan->ptxDebug0 = calloc(numSamples,2);
1777 pChan->ptxDebug1 = calloc(numSamples,2);
1778 pChan->ptxDebug2 = calloc(numSamples,2);
1779 pChan->ptxDebug3 = calloc(numSamples,2);
1780 pChan->pNull = calloc(numSamples,2);
1782 for(i=0;i<numSamples;i++)pChan->pNull[i]=((i%(numSamples/2))*8000)-4000;
1784 pChan->rxCtcss->pDebug0=calloc(numSamples,2);
1785 pChan->rxCtcss->pDebug1=calloc(numSamples,2);
1786 pChan->rxCtcss->pDebug2=calloc(numSamples,2);
1787 pChan->rxCtcss->pDebug3=calloc(numSamples,2);
1789 for(i=0;i<CTCSS_NUM_CODES;i++)
1791 pChan->rxCtcss->tdet[i].pDebug0=calloc(numSamples,2);
1792 pChan->rxCtcss->tdet[i].pDebug1=calloc(numSamples,2);
1793 pChan->rxCtcss->tdet[i].pDebug2=calloc(numSamples,2);
1794 pChan->rxCtcss->tdet[i].pDebug3=calloc(numSamples,2);
1797 // buffer, 2 bytes per sample, and 16 channels
1798 pChan->prxDebug=calloc(numSamples*16,2);
1799 pChan->ptxDebug=calloc(numSamples*16,2);
1801 // TSCOPE CONFIGURATION SETSCOPE configure debug traces and sources for each channel of the output
1802 pChan->sdbg = (t_sdbg *)calloc(sizeof(t_sdbg),1);
1804 for(i=0;i<XPMR_DEBUG_CHANS;i++)pChan->sdbg->trace[i]=-1;
1806 TRACEF(1,("pChan->tracetype = %i\n",pChan->tracetype));
1808 if(pChan->tracetype==1) // CTCSS DECODE
1810 pChan->sdbg->source [0]=pChan->pRxDemod;
1811 pChan->sdbg->source [1]=pChan->pRxBase;
1812 pChan->sdbg->source [2]=pChan->pRxNoise;
1813 pChan->sdbg->trace [3]=RX_NOISE_TRIG;
1814 pChan->sdbg->source [4]=pChan->pRxLsd;
1815 pChan->sdbg->source [5]=pChan->pRxLsdCen;
1816 pChan->sdbg->source [6]=pChan->pRxLsdLimit;
1817 pChan->sdbg->source [7]=pChan->rxCtcss->tdet[3].pDebug0;
1818 pChan->sdbg->trace [8]=RX_CTCSS_DECODE;
1819 pChan->sdbg->trace [9]=RX_SMODE;
1821 if(pChan->tracetype==2) // CTCSS DECODE
1823 pChan->sdbg->source [0]=pChan->pRxDemod;
1824 pChan->sdbg->source [1]=pChan->pRxBase;
1825 pChan->sdbg->trace [2]=RX_NOISE_TRIG;
1826 pChan->sdbg->source [3]=pChan->pRxLsd;
1827 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1828 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1829 pChan->sdbg->source [6]=pChan->pRxLsdLimit;
1830 pChan->sdbg->source [7]=pChan->rxCtcss->tdet[3].pDebug0;
1831 pChan->sdbg->source [8]=pChan->rxCtcss->tdet[3].pDebug1;
1832 pChan->sdbg->source [9]=pChan->rxCtcss->tdet[3].pDebug2;
1833 pChan->sdbg->source [10]=pChan->rxCtcss->tdet[3].pDebug3;
1834 pChan->sdbg->trace [11]=RX_CTCSS_DECODE;
1835 pChan->sdbg->trace [12]=RX_SMODE;
1836 pChan->sdbg->trace [13]=TX_PTT_IN;
1837 pChan->sdbg->trace [14]=TX_PTT_OUT;
1838 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1840 else if(pChan->tracetype==3) // DCS DECODE
1842 pChan->sdbg->source [0]=pChan->pRxDemod;
1843 pChan->sdbg->source [1]=pChan->pRxBase;
1844 pChan->sdbg->trace [2]=RX_NOISE_TRIG;
1845 pChan->sdbg->source [3]=pChan->pRxLsd;
1846 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1847 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1848 pChan->sdbg->trace [6]=RX_DCS_CLK;
1849 pChan->sdbg->trace [7]=RX_DCS_DIN;
1850 pChan->sdbg->trace [8]=RX_DCS_DEC;
1851 pChan->sdbg->trace [9]=RX_SMODE;
1852 pChan->sdbg->trace [10]=TX_PTT_IN;
1853 pChan->sdbg->trace [11]=TX_PTT_OUT;
1854 pChan->sdbg->trace [12]=TX_LSD_CLK;
1855 pChan->sdbg->trace [13]=TX_LSD_DAT;
1856 pChan->sdbg->trace [14]=TX_LSD_GEN;
1857 pChan->sdbg->source [14]=pChan->pTxLsd;
1858 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1860 else if(pChan->tracetype==4) // LSD DECODE
1862 pChan->sdbg->source [0]=pChan->pRxDemod;
1863 pChan->sdbg->source [1]=pChan->pRxBase;
1864 pChan->sdbg->trace [2]=RX_NOISE_TRIG;
1865 pChan->sdbg->source [3]=pChan->pRxLsd;
1866 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1867 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1868 pChan->sdbg->trace [6]=RX_LSD_CLK;
1869 pChan->sdbg->trace [7]=RX_LSD_DAT;
1870 pChan->sdbg->trace [8]=RX_LSD_ERR;
1871 pChan->sdbg->trace [9]=RX_LSD_SYNC;
1872 pChan->sdbg->trace [10]=RX_SMODE;
1873 pChan->sdbg->trace [11]=TX_PTT_IN;
1874 pChan->sdbg->trace [12]=TX_PTT_OUT;
1875 pChan->sdbg->trace [13]=TX_LSD_CLK;
1876 pChan->sdbg->trace [14]=TX_LSD_DAT;
1877 //pChan->sdbg->trace [14]=TX_LSD_GEN;
1878 //pChan->sdbg->source [14]=pChan->pTxLsd;
1879 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1881 else if(pChan->tracetype==5) // LSD LOGIC
1883 pChan->sdbg->source [0]=pChan->pRxBase;
1884 pChan->sdbg->trace [1]=RX_NOISE_TRIG;
1885 pChan->sdbg->source [2]=pChan->pRxDcTrack;
1886 pChan->sdbg->trace [3]=RX_LSD_SYNC;
1887 pChan->sdbg->trace [4]=RX_SMODE;
1888 pChan->sdbg->trace [5]=TX_PTT_IN;
1889 pChan->sdbg->trace [6]=TX_PTT_OUT;
1890 pChan->sdbg->source [7]=pChan->pTxLsdLpf;
1892 else if(pChan->tracetype==6)
1894 // tx clock skew and jitter buffer
1895 pChan->sdbg->source [0]=pChan->pRxDemod;
1896 pChan->sdbg->source [5]=pChan->pTxBase;
1897 pChan->sdbg->trace [6]=TX_DEDRIFT_LEAD;
1898 pChan->sdbg->trace [7]=TX_DEDRIFT_ERR;
1899 pChan->sdbg->trace [8]=TX_DEDRIFT_FACTOR;
1900 pChan->sdbg->trace [9]=TX_DEDRIFT_DRIFT;
1902 else if(pChan->tracetype==7)
1905 pChan->sdbg->source [0]=pChan->pRxBase;
1906 pChan->sdbg->trace [1]=RX_NOISE_TRIG;
1907 pChan->sdbg->source [2]=pChan->pRxLsd;
1908 pChan->sdbg->trace [3]=RX_CTCSS_DECODE;
1909 pChan->sdbg->source [4]=pChan->pRxHpf;
1911 pChan->sdbg->trace [5]=TX_PTT_IN;
1912 pChan->sdbg->trace [6]=TX_PTT_OUT;
1914 pChan->sdbg->source [7]=pChan->pTxBase;
1915 pChan->sdbg->source [8]=pChan->pTxHpf;
1916 pChan->sdbg->source [9]=pChan->pTxPreEmp;
1917 pChan->sdbg->source [10]=pChan->pTxLimiter;
1918 pChan->sdbg->source [11]=pChan->pTxComposite;
1919 pChan->sdbg->source [12]=pChan->pTxLsdLpf;
1922 for(i=0;i<XPMR_DEBUG_CHANS;i++){
1923 if(pChan->sdbg->trace[i]>=0)pChan->sdbg->point[pChan->sdbg->trace[i]]=i;
1925 pChan->sdbg->mode=1;
1930 pSps=pChan->spsLsdGen=createPmrSps(pChan);
1932 pSps->sink=pChan->pTxLsd;
1935 pSps->sigProc=LsdGen;
1936 pSps->nSamples=pChan->nSamplesTx;
1937 pSps->outputGain=(.25*M_Q8);
1939 pSps->interpolate=1;
1944 // General Purpose Function Generator
1945 pSps=pChan->spsSigGen1=createPmrSps(pChan);
1946 pSps->sink=pChan->pSigGen1;
1949 pSps->sigProc=SigGen;
1950 pSps->nSamples=pChan->nSamplesTx;
1951 pSps->sampleRate=SAMPLE_RATE_NETWORK;
1952 pSps->freq=10000; // in increments of 0.1 Hz
1953 pSps->outputGain=(.25*M_Q8);
1955 pSps->interpolate=1;
1961 pSps = pChan->spsSigGen0 = createPmrSps(pChan);
1962 pSps->sink=pChan->pTxLsd;
1963 pSps->sigProc=SigGen;
1966 pSps->nSamples=pChan->nSamplesTx;
1967 pSps->sampleRate=SAMPLE_RATE_NETWORK;
1968 pSps->freq=1000; // in 0.1 Hz steps
1969 pSps->outputGain=(0.5*M_Q8);
1971 pSps->interpolate=1;
1975 // Tx LSD Low Pass Filter
1976 pSps=pChan->spsTxLsdLpf=createPmrSps(pChan);
1977 pSps->source=pChan->pTxLsd;
1978 pSps->sink=pChan->pTxLsdLpf;
1979 pSps->sigProc=pmr_gp_fir;
1983 pSps->nSamples=pChan->nSamplesTx;
1984 pSps->decimator=pSps->decimate=1;
1985 pSps->interpolate=1;
1986 pSps->inputGain=(1*M_Q8);
1987 pSps->outputGain=(1*M_Q8);
1989 // configure the longer, lower cutoff filter by default
1990 pSps->ncoef=taps_fir_lpf_215_9_88;
1992 pSps->coef=(void*)coef_fir_lpf_215_9_88;
1993 pSps->nx=taps_fir_lpf_215_9_88;
1995 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
1996 pSps->calcAdjust=gain_fir_lpf_215_9_88;
1998 pSps->inputGain=(1*M_Q8);
1999 pSps->outputGain=(1*M_Q8);
2001 TRACEF(1,("spsTxLsdLpf = sps \n"));
2003 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2007 TRACEF(1,("create rx\n"));
2010 // allocate space for first sps and set pointers
2011 pSps=pChan->spsRx=createPmrSps(pChan);
2012 pSps->source=NULL; //set when called
2013 pSps->sink=pChan->pRxBase;
2014 pSps->sigProc=pmr_rx_frontend;
2016 pSps->decimator=pSps->decimate=6;
2017 pSps->interpolate=pSps->interpolate=1;
2018 pSps->nSamples=pChan->nSamplesRx;
2019 pSps->ncoef=taps_fir_bpf_noise_1;
2021 pSps->coef=(void*)coef_fir_lpf_3K_1;
2022 pSps->coef2=(void*)coef_fir_bpf_noise_1;
2023 pSps->nx=taps_fir_bpf_noise_1;
2025 pSps->x=(void*)(calloc(pSps->nx,pSps->size_coef));
2026 pSps->calcAdjust=(gain_fir_lpf_3K_1*256)/0x0100;
2027 pSps->outputGain=(1.0*M_Q8);
2029 pSps->hyst=pChan->rxCarrierHyst;
2030 pSps->setpt=pChan->rxCarrierPoint;
2031 pChan->prxSquelchAdjust=&pSps->setpt;
2032 #if XPMR_DEBUG0 == 1
2033 pSps->debugBuff0=pChan->pRxDemod;
2034 pSps->debugBuff1=pChan->pRxNoise;
2035 pSps->debugBuff2=pChan->prxDebug0;
2039 // allocate space for next sps and set pointers
2040 // Rx SubAudible Decoder Low Pass Filter
2041 pSps=pChan->spsRxLsd=pSps->nextSps=createPmrSps(pChan);
2042 pSps->source=pChan->pRxBase;
2043 pSps->sink=pChan->pRxLsd;
2044 pSps->sigProc=pmr_gp_fir;
2048 pSps->nSamples=pChan->nSamplesRx;
2049 pSps->decimator=pSps->decimate=1;
2050 pSps->interpolate=1;
2052 // configure the the larger, lower cutoff filter by default
2053 pSps->ncoef=taps_fir_lpf_215_9_88;
2055 pSps->coef=(void*)coef_fir_lpf_215_9_88;
2056 pSps->nx=taps_fir_lpf_215_9_88;
2058 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2059 pSps->calcAdjust=gain_fir_lpf_215_9_88;
2061 pSps->inputGain=(1*M_Q8);
2062 pSps->outputGain=(1*M_Q8);
2063 pChan->prxCtcssMeasure=pSps->sink;
2064 pChan->prxCtcssAdjust=&(pSps->outputGain);
2066 // CTCSS CenterSlicer
2067 pSps=pChan->spsRxLsdNrz=pSps->nextSps=createPmrSps(pChan);
2068 pSps->source=pChan->pRxLsd;
2069 pSps->sink=pChan->pRxDcTrack;
2070 pSps->buff=pChan->pRxLsdLimit;
2071 pSps->sigProc=CenterSlicer;
2072 pSps->nSamples=pChan->nSamplesRx;
2073 pSps->discfactor=LSD_DFS; // centering time constant
2074 pSps->inputGain=(1*M_Q8);
2075 pSps->outputGain=(1*M_Q8);
2076 pSps->setpt=4900; // ptp clamp for DC centering
2077 pSps->inputGainB=625; // peak output limiter clip point
2082 pSps=pSps->nextSps=createPmrSps(pChan);
2083 pChan->spsRxHpf=pSps;
2084 pSps->source=pChan->pRxBase;
2085 pSps->sink=pChan->pRxHpf;
2086 pSps->sigProc=pmr_gp_fir;
2090 pSps->nSamples=pChan->nSamplesRx;
2091 pSps->decimator=pSps->decimate=1;
2092 pSps->interpolate=1;
2093 pSps->ncoef=taps_fir_hpf_300_9_66;
2095 pSps->coef=(void*)coef_fir_hpf_300_9_66;
2096 pSps->nx=taps_fir_hpf_300_9_66;
2098 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2099 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2100 pSps->calcAdjust=gain_fir_hpf_300_9_66;
2101 pSps->inputGain=(1*M_Q8);
2102 pSps->outputGain=(1*M_Q8);
2103 pChan->prxVoiceAdjust=&(pSps->outputGain);
2104 pChan->spsRxOut=pSps;
2106 // allocate space for next sps and set pointers
2108 if(pChan->rxDeEmpEnable){
2109 pSps=pSps->nextSps=createPmrSps(pChan);
2110 pChan->spsRxDeEmp=pSps;
2111 pSps->source=pChan->pRxHpf;
2112 pSps->sink=pChan->pRxSpeaker;
2113 pChan->spsRxOut=pSps; // OUTPUT STRUCTURE!
2114 pSps->sigProc=gp_inte_00;
2116 pSps->nSamples=pChan->nSamplesRx;
2118 pSps->ncoef=taps_int_lpf_300_1_2;
2120 pSps->coef=(void*)coef_int_lpf_300_1_2;
2122 pSps->nx=taps_int_lpf_300_1_2;
2124 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2125 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2126 pSps->calcAdjust=gain_int_lpf_300_1_2/2;
2127 pSps->inputGain=(1.0*M_Q8);
2128 pSps->outputGain=(1.0*M_Q8);
2129 pChan->prxVoiceMeasure=pSps->sink;
2130 pChan->prxVoiceAdjust=&(pSps->outputGain);
2133 if(pChan->rxDelayLineEnable)
2135 TRACEF(1,("create delayline\n"));
2136 pSps=pChan->spsDelayLine=pSps->nextSps=createPmrSps(pChan);
2137 pSps->sigProc=DelayLine;
2138 pSps->source=pChan->pRxSpeaker;
2139 pSps->sink=pChan->pRxSpeaker;
2141 pSps->inputGain=1*M_Q8;
2142 pSps->outputGain=1*M_Q8;
2143 pSps->nSamples=pChan->nSamplesRx;
2144 pSps->buffSize=4096;
2145 pSps->buff=calloc(4096,2); // one second maximum
2146 pSps->buffLead = (SAMPLE_RATE_NETWORK*0.100);
2147 pSps->buffOutIndex=0;
2150 if(pChan->rxCdType==CD_XPMR_VOX)
2152 TRACEF(1,("create vox measureblock\n"));
2153 pChan->prxVoxMeas=calloc(pChan->nSamplesRx,2);
2155 pSps=pChan->spsRxVox=pSps->nextSps=createPmrSps(pChan);
2156 pSps->sigProc=MeasureBlock;
2157 pSps->parentChan=pChan;
2158 pSps->source=pChan->pRxBase;
2159 pSps->sink=pChan->prxVoxMeas;
2160 pSps->inputGain=1*M_Q8;
2161 pSps->outputGain=1*M_Q8;
2162 pSps->nSamples=pChan->nSamplesRx;
2164 if(pChan->rxSqVoxAdj==0)
2165 pSps->setpt=(0.011*M_Q15);
2167 pSps->setpt=(pChan->rxSqVoxAdj);
2168 pSps->hyst=(pSps->setpt/10);
2172 // tuning measure block
2173 pSps=pChan->spsMeasure=pSps->nextSps=createPmrSps(pChan);
2174 pSps->source=pChan->spsRx->sink;
2175 pSps->sink=pChan->prxMeasure;
2176 pSps->sigProc=MeasureBlock;
2178 pSps->nSamples=pChan->nSamplesRx;
2179 pSps->discfactor=10;
2181 pSps->nextSps=NULL; // last sps in chain RX
2184 // CREATE TRANSMIT CHAIN
2185 TRACEF(1,("create tx\n"));
2189 // allocate space for first sps and set pointers
2191 // Tx HPF SubAudible
2192 if(pChan->txHpfEnable)
2194 pSps=createPmrSps(pChan);
2196 pSps->source=pChan->pTxBase;
2197 pSps->sink=pChan->pTxHpf;
2198 pSps->sigProc=pmr_gp_fir;
2202 pSps->nSamples=pChan->nSamplesTx;
2203 pSps->decimator=pSps->decimate=1;
2204 pSps->interpolate=1;
2205 pSps->ncoef=taps_fir_hpf_300_9_66;
2207 pSps->coef=(void*)coef_fir_hpf_300_9_66;
2208 pSps->nx=taps_fir_hpf_300_9_66;
2210 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2211 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2212 pSps->calcAdjust=gain_fir_hpf_300_9_66;
2213 pSps->inputGain=(1*M_Q8);
2214 pSps->outputGain=(1*M_Q8);
2215 inputTmp=pChan->pTxHpf;
2219 if(pChan->txPreEmpEnable)
2221 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2222 else pSps=pSps->nextSps=createPmrSps(pChan);
2224 pSps->source=inputTmp;
2225 pSps->sink=pChan->pTxPreEmp;
2227 pSps->sigProc=gp_diff;
2229 pSps->nSamples=pChan->nSamplesTx;
2231 pSps->ncoef=taps_int_hpf_4000_1_2;
2233 pSps->coef=(void*)coef_int_hpf_4000_1_2;
2235 pSps->nx=taps_int_hpf_4000_1_2;
2237 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2238 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2240 pSps->calcAdjust=gain_int_hpf_4000_1_2;
2241 pSps->inputGain=(1*M_Q8);
2242 pSps->outputGain=(1*M_Q8); // to match flat at 1KHz
2243 inputTmp=pSps->sink;
2247 if(pChan->txLimiterEnable)
2249 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2250 else pSps=pSps->nextSps=createPmrSps(pChan);
2251 pSps->source=inputTmp;
2252 pSps->sink=pChan->pTxLimiter;
2253 pSps->sigProc=SoftLimiter;
2255 pSps->nSamples=pChan->nSamplesTx;
2256 pSps->inputGain=(1*M_Q8);
2257 pSps->outputGain=(1*M_Q8);
2259 inputTmp=pSps->sink;
2262 // Composite Mix of Voice and LSD
2263 if((pChan->txMixA==TX_OUT_COMPOSITE)||(pChan->txMixB==TX_OUT_COMPOSITE))
2266 pSps=pChan->spsTx=createPmrSps(pChan);
2268 pSps=pSps->nextSps=createPmrSps(pChan);
2269 pSps->source=inputTmp;
2270 pSps->sourceB=pChan->pTxLsdLpf; //asdf ??? !!! maw pTxLsdLpf
2271 pSps->sink=pChan->pTxComposite;
2272 pSps->sigProc=pmrMixer;
2274 pSps->nSamples=pChan->nSamplesTx;
2275 pSps->inputGain=2*M_Q8;
2276 pSps->inputGainB=1*M_Q8/8;
2277 pSps->outputGain=1*M_Q8;
2279 inputTmp=pSps->sink;
2280 pChan->ptxCtcssAdjust=&pSps->inputGainB;
2283 // Chan A Upsampler and Filter
2284 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2285 else pSps=pSps->nextSps=createPmrSps(pChan);
2287 pChan->spsTxOutA=pSps;
2288 if(!pChan->spsTx)pChan->spsTx=pSps;
2290 if(pChan->txMixA==TX_OUT_COMPOSITE)
2292 pSps->source=pChan->pTxComposite;
2294 else if(pChan->txMixA==TX_OUT_LSD)
2296 pSps->source=pChan->pTxLsdLpf;
2298 else if(pChan->txMixA==TX_OUT_VOICE)
2300 pSps->source=pChan->pTxHpf;
2302 else if (pChan->txMixA==TX_OUT_AUX)
2304 pSps->source=inputTmp;
2308 pSps->source=NULL; // maw sph asdf !!! no blow up
2309 pSps->source=inputTmp;
2312 pSps->sink=pChan->pTxOut;
2313 pSps->sigProc=pmr_gp_fir;
2317 pSps->nSamples=pChan->nSamplesTx;
2318 pSps->interpolate=6;
2319 pSps->ncoef=taps_fir_lpf_3K_1;
2321 pSps->coef=(void*)coef_fir_lpf_3K_1;
2322 pSps->nx=taps_fir_lpf_3K_1;
2324 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2325 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2326 pSps->calcAdjust=gain_fir_lpf_3K_1;
2327 pSps->inputGain=(1*M_Q8);
2328 pSps->outputGain=(1*M_Q8);
2329 if(pChan->txMixA==pChan->txMixB)pSps->monoOut=1;
2330 else pSps->monoOut=0;
2333 // Chan B Upsampler and Filter
2334 if((pChan->txMixA!=pChan->txMixB)&&(pChan->txMixB!=TX_OUT_OFF))
2336 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2337 else pSps=pSps->nextSps=createPmrSps(pChan);
2339 pChan->spsTxOutB=pSps;
2340 if(pChan->txMixB==TX_OUT_COMPOSITE)
2342 pSps->source=pChan->pTxComposite;
2344 else if(pChan->txMixB==TX_OUT_LSD)
2346 pSps->source=pChan->pTxLsdLpf;
2347 // pChan->ptxCtcssAdjust=&pSps->inputGain;
2349 else if(pChan->txMixB==TX_OUT_VOICE)
2351 pSps->source=inputTmp;
2353 else if(pChan->txMixB==TX_OUT_AUX)
2355 pSps->source=pChan->pTxHpf;
2362 pSps->sink=pChan->pTxOut;
2363 pSps->sigProc=pmr_gp_fir;
2368 pSps->nSamples=pChan->nSamplesTx;
2369 pSps->interpolate=6;
2370 pSps->ncoef=taps_fir_lpf_3K_1;
2372 pSps->coef=(void*)coef_fir_lpf_3K_1;
2373 pSps->nx=taps_fir_lpf_3K_1;
2375 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2376 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2377 pSps->calcAdjust=(gain_fir_lpf_3K_1);
2378 pSps->inputGain=(1*M_Q8);
2379 pSps->outputGain=(1*M_Q8);
2384 // Configure Coded Signaling
2385 code_string_parse(pChan);
2387 pChan->smode=SMODE_NULL;
2388 pChan->smodewas=SMODE_NULL;
2389 pChan->smodetime=2500;
2390 pChan->smodetimer=0;
2391 pChan->b.smodeturnoff=0;
2393 pChan->txsettletimer=0;
2395 TRACEF(1,("createPmrChannel() end\n"));
2401 i16 destroyPmrChannel(t_pmr_chan *pChan)
2403 t_pmr_sps *pmr_sps, *tmp_sps;
2405 TRACEF(1,("destroyPmrChannel()\n"));
2407 free(pChan->pRxDemod);
2408 free(pChan->pRxNoise);
2409 free(pChan->pRxBase);
2410 free(pChan->pRxHpf);
2411 free(pChan->pRxLsd);
2412 free(pChan->pRxSpeaker);
2413 free(pChan->pRxDcTrack);
2414 if(pChan->pRxLsdLimit)free(pChan->pRxLsdLimit);
2415 free(pChan->pTxBase);
2416 free(pChan->pTxHpf);
2417 free(pChan->pTxPreEmp);
2418 free(pChan->pTxLimiter);
2419 free(pChan->pTxLsd);
2420 free(pChan->pTxLsdLpf);
2421 if(pChan->pTxComposite)free(pChan->pTxComposite);
2422 free(pChan->pTxOut);
2424 if(pChan->prxMeasure)free(pChan->prxMeasure);
2425 if(pChan->pSigGen0)free(pChan->pSigGen0);
2426 if(pChan->pSigGen1)free(pChan->pSigGen1);
2429 #if XPMR_DEBUG0 == 1
2430 //if(pChan->prxDebug)free(pChan->prxDebug);
2431 if(pChan->ptxDebug)free(pChan->ptxDebug);
2432 free(pChan->prxDebug0);
2433 free(pChan->prxDebug1);
2434 free(pChan->prxDebug2);
2435 free(pChan->prxDebug3);
2437 free(pChan->ptxDebug0);
2438 free(pChan->ptxDebug1);
2439 free(pChan->ptxDebug2);
2440 free(pChan->ptxDebug3);
2442 free(pChan->rxCtcss->pDebug0);
2443 free(pChan->rxCtcss->pDebug1);
2446 for(i=0;i<CTCSS_NUM_CODES;i++)
2448 free(pChan->rxCtcss->tdet[i].pDebug0);
2449 free(pChan->rxCtcss->tdet[i].pDebug1);
2450 free(pChan->rxCtcss->tdet[i].pDebug2);
2451 free(pChan->rxCtcss->tdet[i].pDebug3);
2458 free(pChan->pRxCtcss);
2460 pmr_sps=pChan->spsRx;
2462 if(pChan->sdbg)free(pChan->sdbg);
2467 pmr_sps = tmp_sps->nextSps;
2468 destroyPmrSps(tmp_sps);
2477 t_pmr_sps *createPmrSps(t_pmr_chan *pChan)
2481 TRACEF(1,("createPmrSps()\n"));
2483 pSps = (t_pmr_sps *)calloc(sizeof(t_pmr_sps),1);
2485 if(!pSps)printf("Error: createPmrSps()\n");
2487 pSps->parentChan=pChan;
2488 pSps->index=pChan->spsIndex++;
2490 // pSps->x=calloc(pSps->nx,pSps->size_x);
2496 i16 destroyPmrSps(t_pmr_sps *pSps)
2498 TRACEJ(1,("destroyPmrSps(%i)\n",pSps->index));
2500 if(pSps->x!=NULL)free(pSps->x);
2505 PmrTx - takes data from network and holds it for PmrRx
2507 i16 PmrTx(t_pmr_chan *pChan, i16 *input)
2509 pChan->frameCountTx++;
2511 TRACEF(5,("PmrTx() start %i\n",pChan->frameCountTx));
2515 if(pptp_p2)ioctl(ppdrvdev,PPDRV_IOC_PINSET,LP_PIN02);
2516 else ioctl(ppdrvdev,PPDRV_IOC_PINCLEAR,LP_PIN02);
2520 printf("PmrTx() pChan == NULL\n");
2524 #if XPMR_DEBUG0 == 1
2525 if(pChan->b.rxCapture && pChan->tracetype==5)
2527 memcpy(pChan->pTxInput,input,pChan->nSamplesRx*2);
2531 //if(pChan->b.radioactive)pChan->dd.debug=1;
2532 //else pChan->dd.debug=0;
2534 dedrift_write(pChan,input);
2539 PmrRx handles a block of data from the usb audio device
2541 i16 PmrRx(t_pmr_chan *pChan, i16 *input, i16 *outputrx, i16 *outputtx)
2547 TRACEC(5,("PmrRx(%p %p %p %p)\n",pChan, input, outputrx, outputtx));
2550 if(pChan->b.radioactive)
2552 pptp_write(1,pChan->frameCountRx&0x00000001);
2557 printf("PmrRx() pChan == NULL\n");
2561 pChan->frameCountRx++;
2563 #if XPMR_DEBUG0 == 1
2564 if(pChan->b.rxCapture)
2566 //if(pChan->prxDebug)memset((void *)pChan->prxDebug,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2567 if(pChan->ptxDebug)memset((void *)pChan->ptxDebug,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2568 if(pChan->sdbg->buffer)
2570 memset((void *)pChan->sdbg->buffer,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2571 pChan->prxDebug=pChan->sdbg->buffer;
2576 pmr_sps=pChan->spsRx; // first sps
2577 pmr_sps->source=input;
2579 if(outputrx!=NULL)pChan->spsRxOut->sink=outputrx; //last sps
2582 if(pChan->inputBlanking>0)
2584 pChan->inputBlanking-=pChan->nSamplesRx;
2585 if(pChan->inputBlanking<0)pChan->inputBlanking=0;
2586 for(i=0;i<pChan->nSamplesRx*6;i++)
2591 if( pChan->rxCpuSaver && !pChan->rxCarrierDetect &&
2592 pChan->smode==SMODE_NULL &&
2593 !pChan->txPttIn && !pChan->txPttOut)
2595 if(!pChan->b.rxhalted)
2597 if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=0;
2598 if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=0;
2599 pChan->b.rxhalted=1;
2600 TRACEC(1,("PmrRx() rx sps halted\n"));
2603 else if(pChan->b.rxhalted)
2605 if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=1;
2606 if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=1;
2607 pChan->b.rxhalted=0;
2608 TRACEC(1,("PmrRx() rx sps un-halted\n"));
2612 while(pmr_sps!=NULL && pmr_sps!=0)
2614 TRACEC(5,("PmrRx() sps %i\n",i++));
2615 pmr_sps->sigProc(pmr_sps);
2616 pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps);
2617 //pmr_sps=NULL; // sph maw
2620 #define XPMR_VOX_HANGTIME 2000
2622 if(pChan->rxCdType==CD_XPMR_VOX)
2624 if(pChan->spsRxVox->compOut)
2626 pChan->rxVoxTimer=XPMR_VOX_HANGTIME; //VOX HangTime in ms
2628 if(pChan->rxVoxTimer>0)
2630 pChan->rxVoxTimer-=MS_PER_FRAME;
2631 pChan->rxCarrierDetect=1;
2635 pChan->rxVoxTimer=0;
2636 pChan->rxCarrierDetect=0;
2641 pChan->rxCarrierDetect=!pChan->spsRx->compOut;
2644 // stop and start these engines instead to eliminate falsing
2645 if( pChan->b.ctcssRxEnable &&
2646 ( (!pChan->b.rxhalted ||
2647 pChan->rxCtcss->decode!=CTCSS_NULL || pChan->smode==SMODE_CTCSS) &&
2648 (pChan->smode!=SMODE_DCS&&pChan->smode!=SMODE_LSD) )
2651 ctcss_detect(pChan);
2655 if(pChan->txPttIn!=pChan->b.pttwas)
2657 pChan->b.pttwas=pChan->txPttIn;
2658 TRACEC(1,("PmrRx() txPttIn=%i\n",pChan->b.pttwas));
2663 xpmrx(pChan,XXO_RXDECODE);
2666 if(pChan->smodetimer>0 && !pChan->txPttIn)
2668 pChan->smodetimer-=MS_PER_FRAME;
2670 if(pChan->smodetimer<=0)
2672 pChan->smodetimer=0;
2673 pChan->smodewas=pChan->smode;
2674 pChan->smode=SMODE_NULL;
2675 pChan->b.smodeturnoff=1;
2676 TRACEC(1,("smode timeout. smode was=%i\n",pChan->smodewas));
2680 if(pChan->rxCtcss->decode > CTCSS_NULL &&
2681 (pChan->smode==SMODE_NULL||pChan->smode==SMODE_CTCSS) )
2683 if(pChan->smode!=SMODE_CTCSS)
2685 TRACEC(1,("smode set=%i code=%i\n",pChan->smode,pChan->rxCtcss->decode));
2686 pChan->smode=pChan->smodewas=SMODE_CTCSS;
2688 pChan->smodetimer=pChan->smodetime;
2692 xpmrx(pChan,XXO_LSDCTL);
2695 //TRACEX(("PmrRx() tx portion.\n"));
2697 // handle radio transmitter ptt input
2699 if( !(pChan->smode==SMODE_DCS||pChan->smode==SMODE_LSD) )
2702 if( pChan->txPttIn && pChan->txState==CHAN_TXSTATE_IDLE )
2704 TRACEC(1,("txPttIn==1 from CHAN_TXSTATE_IDLE && !SMODE_LSD. codeindex=%i %i \n",pChan->rxCtcss->decode, pChan->rxCtcssMap[pChan->rxCtcss->decode] ));
2705 pChan->dd.b.doitnow=1;
2707 if(pChan->smode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2709 if(pChan->rxCtcss->decode>CTCSS_NULL)
2711 if(pChan->rxCtcssMap[pChan->rxCtcss->decode]!=CTCSS_RXONLY)
2713 f=freq_ctcss[pChan->rxCtcssMap[pChan->rxCtcss->decode]];
2718 f=pChan->txctcssdefault_value;
2720 TRACEC(1,("txPttIn - Start CTCSSGen %f \n",f));
2725 pChan->spsSigGen0->freq=f*10;
2726 pSps=pChan->spsTxLsdLpf;
2732 pSps->ncoef=taps_fir_lpf_250_9_66;
2734 pSps->coef=(void*)coef_fir_lpf_250_9_66;
2735 pSps->nx=taps_fir_lpf_250_9_66;
2737 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2738 pSps->calcAdjust=gain_fir_lpf_250_9_66;
2742 pSps->ncoef=taps_fir_lpf_215_9_88;
2744 pSps->coef=(void*)coef_fir_lpf_215_9_88;
2745 pSps->nx=taps_fir_lpf_215_9_88;
2747 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2748 pSps->calcAdjust=gain_fir_lpf_215_9_88;
2752 pChan->spsSigGen0->option=1;
2753 pChan->spsSigGen0->enabled=1;
2754 pChan->spsSigGen0->discounterl=0;
2757 else if(pChan->smode==SMODE_NULL && pChan->txcodedefaultsmode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2759 TRACEC(1,("txPtt Encode txcodedefaultsmode==SMODE_CTCSS %f\n",pChan->txctcssdefault_value));
2760 pChan->spsSigGen0->freq=pChan->txctcssdefault_value*10;
2761 pChan->spsSigGen0->option=1;
2762 pChan->spsSigGen0->enabled=1;
2763 pChan->spsSigGen0->discounterl=0;
2764 pChan->smode=SMODE_CTCSS;
2765 pChan->smodetimer=pChan->smodetime;
2767 else if(pChan->txcodedefaultsmode==SMODE_NULL||pChan->b.txCtcssInhibit)
2769 TRACEC(1,("txPtt Encode txcodedefaultsmode==SMODE_NULL\n"));
2773 printf ("ERROR: txPttIn=%i NOT HANDLED PROPERLY.\n",pChan->txPttIn);
2774 TRACEC(1,("ERROR: txPttIn=%i NOT HANDLED PROPERLY.\n",pChan->txPttIn));
2777 pChan->txState = CHAN_TXSTATE_ACTIVE;
2780 pChan->txsettletimer=pChan->txsettletime;
2782 if(pChan->spsTxOutA)pChan->spsTxOutA->enabled=1;
2783 if(pChan->spsTxOutB)pChan->spsTxOutB->enabled=1;
2784 if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->enabled=1;
2785 if(pChan->txfreq)pChan->b.reprog=1;
2786 TRACEC(1,("PmrRx() TxOn\n"));
2788 else if(pChan->txPttIn && pChan->txState==CHAN_TXSTATE_ACTIVE)
2790 // pChan->smode=SMODE_CTCSS;
2791 pChan->smodetimer=pChan->smodetime;
2793 else if(!pChan->txPttIn && pChan->txState==CHAN_TXSTATE_ACTIVE)
2795 TRACEC(1,("txPttIn==0 from CHAN_TXSTATE_ACTIVE\n"));
2796 if(pChan->smode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2798 if( pChan->txTocType==TOC_NONE || !pChan->b.ctcssTxEnable )
2800 TRACEC(1,("Tx Off Immediate.\n"));
2801 pChan->spsSigGen0->option=3;
2802 pChan->txBufferClear=3;
2803 pChan->txState=CHAN_TXSTATE_FINISHING;
2805 else if(pChan->txTocType==TOC_NOTONE)
2807 pChan->txState=CHAN_TXSTATE_TOC;
2808 pChan->txHangTime=TOC_NOTONE_TIME/MS_PER_FRAME;
2809 pChan->spsSigGen0->option=3;
2810 TRACEC(1,("Tx Turn Off No Tone Start.\n"));
2814 pChan->txState=CHAN_TXSTATE_TOC;
2815 pChan->txHangTime=0;
2816 pChan->spsSigGen0->option=2;
2817 TRACEC(1,("Tx Turn Off Phase Shift Start.\n"));
2822 pChan->txBufferClear=3;
2823 pChan->txState=CHAN_TXSTATE_FINISHING;
2824 TRACEC(1,("Tx Off No SMODE to Finish.\n"));
2827 else if(pChan->txState==CHAN_TXSTATE_TOC)
2829 if( pChan->txPttIn && pChan->smode==SMODE_CTCSS )
2831 TRACEC(1,("Tx Key During HangTime\n"));
2832 pChan->txState = CHAN_TXSTATE_ACTIVE;
2833 pChan->spsSigGen0->option=1;
2834 pChan->spsSigGen0->enabled=1;
2835 pChan->spsSigGen0->discounterl=0;
2838 else if(pChan->txHangTime)
2840 if(--pChan->txHangTime==0)pChan->txState=CHAN_TXSTATE_FINISHING;
2842 else if(pChan->txHangTime<=0 && pChan->spsSigGen0->state==0)
2844 pChan->txBufferClear=3;
2845 pChan->txState=CHAN_TXSTATE_FINISHING;
2846 TRACEC(1,("Tx Off TOC.\n"));
2849 else if(pChan->txState==CHAN_TXSTATE_FINISHING)
2851 if(--pChan->txBufferClear<=0)
2852 pChan->txState=CHAN_TXSTATE_COMPLETE;
2854 else if(pChan->txState==CHAN_TXSTATE_COMPLETE)
2858 } // end of if SMODE==LSD
2863 pChan->spsSigGen0->option=3;
2864 pChan->txState=CHAN_TXSTATE_IDLE;
2865 if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->option=3;
2866 if(pChan->spsTxOutA)pChan->spsTxOutA->option=3;
2867 if(pChan->spsTxOutB)pChan->spsTxOutB->option=3;
2868 if(pChan->rxfreq||pChan->txfreq)pChan->b.reprog=1;
2869 TRACEC(1,("Tx Off hit.\n"));
2878 if(pChan->txsettletimer && pChan->txPttHid )
2880 pChan->txsettletimer-=MS_PER_FRAME;
2881 if(pChan->txsettletimer<0)pChan->txsettletimer=0;
2884 // enable this after we know everything else is working
2885 if( pChan->txCpuSaver &&
2886 !pChan->txPttIn && !pChan->txPttOut &&
2887 pChan->txState==CHAN_TXSTATE_IDLE &&
2888 !pChan->dd.b.doitnow
2891 if(!pChan->b.txhalted)
2893 pChan->b.txhalted=1;
2894 TRACEC(1,("PmrRx() tx sps halted\n"));
2897 else if(pChan->b.txhalted)
2899 pChan->dd.b.doitnow=1;
2900 pChan->b.txhalted=0;
2901 TRACEC(1,("PmrRx() tx sps un-halted\n"));
2904 if(pChan->b.txhalted)return(1);
2906 if(pChan->b.startSpecialTone)
2908 pChan->b.startSpecialTone=0;
2909 pChan->spsSigGen1->option=1;
2910 pChan->spsSigGen1->enabled=1;
2911 pChan->b.doingSpecialTone=1;
2913 else if(pChan->b.stopSpecialTone)
2915 pChan->b.stopSpecialTone=0;
2916 pChan->spsSigGen1->option=0;
2917 pChan->b.doingSpecialTone=0;
2918 pChan->spsSigGen1->enabled=0;
2920 else if(pChan->b.doingSpecialTone)
2922 pChan->spsSigGen1->sink=outputtx;
2923 pChan->spsSigGen1->sigProc(pChan->spsSigGen1);
2924 for(i=0;i<(pChan->nSamplesTx*2*6);i+=2)outputtx[i+1]=outputtx[i];
2928 if(pChan->spsSigGen0 && pChan->spsSigGen0->enabled )
2930 pChan->spsSigGen0->sigProc(pChan->spsSigGen0);
2933 if(pChan->spsSigGen1 && pChan->spsSigGen1->enabled)
2935 pChan->spsSigGen1->sigProc(pChan->spsSigGen1);
2939 pChan->spsLsdGen->sigProc(pChan->spsLsdGen); // maw sph ???
2942 // Do Low Speed Data Low Pass Filter
2943 pChan->spsTxLsdLpf->sigProc(pChan->spsTxLsdLpf);
2946 pmr_sps=pChan->spsTx;
2948 // get tx data from de-drift process
2950 pChan->dd.ptr=pChan->pTxBase;
2954 if(!pChan->spsSigGen1->enabled)
2956 pmr_sps->source=pChan->pTxBase;
2958 else input=pmr_sps->source;
2962 if(pChan->spsTxOutA)pChan->spsTxOutA->sink=outputtx;
2963 if(pChan->spsTxOutB)pChan->spsTxOutB->sink=outputtx;
2967 while(pmr_sps!=NULL && pmr_sps!=0)
2969 //TRACEF(1,("PmrTx() sps %i\n",i++));
2970 pmr_sps->sigProc(pmr_sps);
2971 pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps);
2974 //TRACEF(1,("PmrTx() - outputs \n"));
2975 if(pChan->txMixA==TX_OUT_OFF || !pChan->txPttOut){
2976 for(i=0;i<pChan->nSamplesTx*2*6;i+=2)outputtx[i]=0;
2979 if(pChan->txMixB==TX_OUT_OFF || !pChan->txPttOut ){
2980 for(i=0;i<pChan->nSamplesTx*2*6;i+=2)outputtx[i+1]=0;
2984 if( pChan->b.radioactive && pChan->b.pptp_p1!=pChan->txPttOut)
2986 pChan->b.pptp_p1=pChan->txPttOut;
2987 pptp_write(0,pChan->b.pptp_p1);
2991 #if XPMR_DEBUG0 == 1
2992 // TRACEF(1,("PmrRx() - debug outputs \n"));
2993 if(pChan->b.rxCapture){
2994 for(i=0;i<pChan->nSamplesRx;i++)
2996 pChan->pRxDemod[i]=input[i*2*6];
2997 pChan->pTstTxOut[i]=outputtx[i*2*6+0]; // txa
2998 //pChan->pTstTxOut[i]=outputtx[i*2*6+1]; // txb
2999 TSCOPE((RX_NOISE_TRIG, pChan->sdbg, i, (pChan->rxCarrierDetect*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
3000 TSCOPE((RX_CTCSS_DECODE, pChan->sdbg, i, pChan->rxCtcss->decode*(M_Q14/CTCSS_NUM_CODES)));
3001 TSCOPE((RX_SMODE, pChan->sdbg, i, pChan->smode*(XPMR_TRACE_AMP/4)));
3002 TSCOPE((TX_PTT_IN, pChan->sdbg, i, (pChan->txPttIn*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
3003 TSCOPE((TX_PTT_OUT, pChan->sdbg, i, (pChan->txPttOut*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
3004 TSCOPE((TX_DEDRIFT_LEAD, pChan->sdbg, i, pChan->dd.lead*8));
3005 TSCOPE((TX_DEDRIFT_ERR, pChan->sdbg, i, pChan->dd.err*16));
3006 TSCOPE((TX_DEDRIFT_FACTOR, pChan->sdbg, i, pChan->dd.factor*16));
3007 TSCOPE((TX_DEDRIFT_DRIFT, pChan->sdbg, i, pChan->dd.drift*16));
3012 strace2(pChan->sdbg);
3013 TRACEC(5,("PmrRx() return cd=%i smode=%i txPttIn=%i txPttOut=%i \n",pChan->rxCarrierDetect,pChan->smode,pChan->txPttIn,pChan->txPttOut));
3017 parallel binary programming of an RF Transceiver*/
3019 void ppbinout (u8 chan)
3025 ppdrvdev = open("/dev/ppdrv_device", 0);
3029 ast_log(LOG_ERROR, "open /dev/ppdrv_ppdrvdev returned %i\n",ppdrvdev);
3034 if(chan&0x01)i|=BIN_PROG_0;
3035 if(chan&0x02)i|=BIN_PROG_1;
3036 if(chan&0x04)i|=BIN_PROG_2;
3037 if(chan&0x08)i|=BIN_PROG_3;
3039 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3040 //ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3041 //ioctl(ppdrvdev, PPDRV_IOC_PINSET, i );
3042 ioctl(ppdrvdev, PPDRV_IOC_PINSET, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3043 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, i );
3045 // ioctl(ppdrvdev, PPDRV_IOC_PINSET, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0 );
3046 ast_log(LOG_NOTICE, "mask=%i 0x%x\n",i,i);
3050 SPI Programming of an RF Transceiver
3051 need to add permissions check and mutex
3054 need to add permissions check and mutex
3056 void ppspiout (u32 spidata)
3059 static char firstrun=0;
3065 ast_log(LOG_ERROR, "no parallel port permission ppdrvdev %i\n",ppdrvdev);
3069 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3070 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3075 for(ii=0;ii<PP_BIT_TIME*200;ii++);
3079 for(ii=0;ii<PP_BIT_TIME*4;ii++);
3082 bitselect=0x00080000;
3084 for(i=0;i<(PP_REG_LEN-12);i++)
3086 if((bitselect&spidata))
3087 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_DATA );
3089 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_DATA );
3091 for(ii=0;ii<PP_BIT_TIME;ii++);
3093 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_CLK );
3094 for(ii=0;ii<PP_BIT_TIME;ii++);
3095 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK );
3096 for(ii=0;ii<PP_BIT_TIME;ii++);
3098 bitselect=(bitselect>>1);
3100 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA );
3101 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_ENABLE );
3102 for(ii=0;ii<PP_BIT_TIME;ii++);
3103 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_ENABLE );
3108 now assumes calling thread secures permissions
3109 could set up a separate thread to program the radio? yuck!
3112 void progdtx(t_pmr_chan *pChan)
3115 //static u32 progcount=0;
3124 TRACEC(1,("\nprogdtx() %i %i %i\n",pChan->rxfreq,pChan->txfreq,0));
3127 ppdrvdev = open("/dev/ppdrv_device", 0);
3131 ast_log(LOG_ERROR, "open /dev/ppdrv_ppdrvdev returned %i\n",ppdrvdev);
3135 if(pChan->rxfreq>200000000)
3148 shiftreg=(reffreq/stepfreq)<<1;
3149 shiftreg=shiftreg|0x00000001;
3154 synthfreq=pChan->txfreq;
3156 synthfreq=pChan->rxfreq-rxiffreq;
3158 shiftreg=(synthfreq/stepfreq)<<1;
3159 tmp=(shiftreg&0xFFFFFF80)<<1;
3160 shiftreg=tmp+(shiftreg&0x0000007F);
3164 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3165 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA | DTX_ENABLE );
3169 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_TXPWR );
3170 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_TX );
3171 if(pChan->txpower && 0) ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_TXPWR );
3175 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_TX | DTX_TXPWR );
3181 reconciles clock differences between the usb adapter and
3182 asterisk's frame rate clock
3183 take out all accumulated drift error on these events:
3184 before transmitter on
3185 when ptt release from mobile units detected
3187 void dedrift(t_pmr_chan *pChan)
3189 TRACEC(5,("dedrift()\n"));
3191 if(pChan->dd.option==9)
3193 TRACEF(1,("dedrift(9)\n"));
3194 pChan->dd.framesize=DDB_FRAME_SIZE;
3195 pChan->dd.frames=DDB_FRAMES_IN_BUFF;
3196 pChan->dd.buffersize = pChan->dd.frames * pChan->dd.framesize;
3197 pChan->dd.buff=calloc(DDB_FRAME_SIZE*DDB_FRAMES_IN_BUFF,2);
3198 pChan->dd.modulus=DDB_ERR_MODULUS;
3199 pChan->dd.inputindex=0;
3200 pChan->dd.outputindex=0;
3201 pChan->dd.skew = pChan->dd.lead=0;
3204 pChan->dd.debugcnt=0;
3205 pChan->dd.lock=pChan->dd.b.txlock=pChan->dd.b.rxlock=0;
3206 pChan->dd.initcnt=2;
3207 pChan->dd.timer=10000/20;
3209 pChan->dd.factor=pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3210 pChan->dd.txframecnt=pChan->dd.rxframecnt=0;
3211 // clear the buffer too!
3214 else if(pChan->dd.option==8)
3216 free(pChan->dd.buff);
3218 pChan->dd.b.txlock=pChan->dd.b.rxlock=0;
3221 else if(pChan->dd.initcnt==0)
3228 inputindex = pChan->dd.inputindex;
3229 pChan->dd.skew = pChan->dd.txframecnt-pChan->dd.rxframecnt;
3230 pChan->dd.rxframecnt++;
3232 // pull data from buffer
3233 if( (pChan->dd.outputindex + pChan->dd.framesize) > pChan->dd.buffersize )
3237 dofirst = pChan->dd.buffersize - pChan->dd.outputindex;
3238 donext = pChan->dd.framesize - dofirst;
3239 vptr = (void*)(pChan->dd.ptr);
3240 memcpy(vptr,(void*)(pChan->dd.buff + pChan->dd.outputindex),dofirst*2);
3241 vptr=(void*)(pChan->dd.ptr + dofirst);
3242 memcpy(vptr,(void*)(pChan->dd.buff),donext*2);
3246 memcpy(pChan->dd.ptr,(void*)(pChan->dd.buff + pChan->dd.outputindex),pChan->dd.framesize*2);
3249 // compute clock error and correction factor
3250 if(pChan->dd.outputindex > inputindex)
3252 pChan->dd.lead = (inputindex + pChan->dd.buffersize) - pChan->dd.outputindex;
3256 pChan->dd.lead = inputindex - pChan->dd.outputindex;
3258 pChan->dd.err = pChan->dd.lead - (pChan->dd.buffersize/2);
3260 // WinFilter, IIR Fs=50, Fc=0.1
3261 const i32 a0 = 26231;
3262 const i32 a1 = 26231;
3263 const i32 b0 = 32768;
3264 const i32 b1 = -32358;
3266 pChan->dd.x1 = pChan->dd.x0;
3267 pChan->dd.y1 = pChan->dd.y0;
3268 pChan->dd.x0 = pChan->dd.err;
3269 pChan->dd.y0 = a0 * pChan->dd.x0;
3270 pChan->dd.y0 += (a1 * pChan->dd.x1 - (b1 * pChan->dd.y1));
3272 accum = pChan->dd.y0/dg;
3274 pChan->dd.factor=accum;
3278 // event sync'd correction
3279 if(pChan->dd.b.doitnow)
3281 pChan->dd.b.doitnow=0;
3282 indextweak=pChan->dd.factor;
3283 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3284 pChan->dd.timer=20000/MS_PER_FRAME;
3286 // coarse lead adjustment if really far out of range
3287 else if( pChan->dd.lead >= pChan->dd.framesize*(DDB_FRAMES_IN_BUFF-2) )
3289 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3290 indextweak += (pChan->dd.framesize*5/4);
3292 else if(pChan->dd.lead <= pChan->dd.framesize*2 )
3294 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3295 indextweak -= (pChan->dd.framesize*5/4);
3300 if(pChan->dd.timer>0)pChan->dd.timer--;
3301 if(pChan->dd.timer==0 && abs(pChan->dd.factor)>=16)
3303 indextweak=pChan->dd.factor;
3304 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3305 pChan->dd.timer=20000/MS_PER_FRAME;
3309 #if XPMR_DEBUG0 == 1
3310 if(indextweak!=0)TRACEF(4,("%08i indextweak %+4i %+4i %+5i %5i %5i %5i %+4i\n",pChan->dd.rxframecnt, indextweak, pChan->dd.err, accum, inputindex, pChan->dd.outputindex, pChan->dd.lead, pChan->dd.skew));
3313 // set the output index based on lead and clock offset
3314 pChan->dd.outputindex = (pChan->dd.outputindex + pChan->dd.framesize + indextweak)%pChan->dd.buffersize;
3319 void dedrift_write(t_pmr_chan *pChan, i16 *src )
3323 TRACEF(5,("dedrift_write()\n"));
3324 vptr = pChan->dd.buff + pChan->dd.inputindex;
3325 memcpy(vptr, src, pChan->dd.framesize*2);
3326 pChan->dd.inputindex = (pChan->dd.inputindex + pChan->dd.framesize) % pChan->dd.buffersize;
3327 pChan->dd.txframecnt++;
3328 if(pChan->dd.initcnt!=0)pChan->dd.initcnt--;
3329 pChan->dd.accum+=pChan->dd.framesize;