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 idx, i16 value)
81 // make dbg_trace buffer in structure
82 if(!sdbg->mode || sdbg->point[point]<0){
85 sdbg->buffer[(idx*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));
305 pChan->numrxctcssfreqs=0;
306 for(_ii=0;_ii<CTCSS_NUM_CODES;_ii++) pChan->rxCtcssMap[_ii]=CTCSS_NULL;
307 TRACEF(1,("WARNING: Invalid Channel code detected and ignored. %i %s %s \n",i,pChan->pRxCode[i],pChan->pTxCode[i]));
312 TRACEF(1,("code_string_parse() CTCSS Init Struct %i %i\n",pChan->b.ctcssRxEnable,pChan->b.ctcssTxEnable));
313 if(pChan->b.ctcssRxEnable)
315 pChan->rxHpfEnable=1;
316 pChan->spsRxLsdNrz->enabled=pChan->rxCenterSlicerEnable=1;
317 pChan->rxCtcssDecodeEnable=1;
318 pChan->rxCtcss->enabled=1;
322 pChan->rxHpfEnable=1;
323 pChan->spsRxLsdNrz->enabled=pChan->rxCenterSlicerEnable=0;
324 pChan->rxCtcssDecodeEnable=0;
325 pChan->rxCtcss->enabled=0;
328 TRACEF(1,("code_string_parse() CTCSS Init Decoders \n"));
329 for(i=0;i<CTCSS_NUM_CODES;i++)
332 ptdet=&(pChan->rxCtcss->tdet[i]);
333 ptdet->counterFactor=coef_ctcss_div[i];
335 ptdet->setpt=(M_Q15*0.041); // 0.069
336 ptdet->hyst =(M_Q15*0.0130);
337 ptdet->binFactor=(M_Q15*0.135); // was 0.140
338 ptdet->fudgeFactor=8;
343 TRACEF(1,("code_string_parse() Default Tx Code %s \n",pChan->pTxCodeDefault));
344 pChan->txcodedefaultsmode=SMODE_NULL;
345 p=pChan->pStr=pChan->pTxCodeDefault;
348 if(!lsd_code_parse(pChan,3))
352 ti=CtcssFreqIndex(f);
353 if(f>maxctcsstxfreq)maxctcsstxfreq=f;
357 pChan->b.ctcssTxEnable=1;
358 pChan->txctcssdefault_index=ti;
359 pChan->txctcssdefault_value=f;
360 pChan->spsSigGen0->freq=f*10;
361 pChan->txcodedefaultsmode=SMODE_CTCSS;
362 TRACEF(1,("code_string_parse() Tx Default CTCSS = %s %i %f\n",p,ti,f));
367 // set x for maximum length and just change pointers
368 TRACEF(1,("code_string_parse() Filter Config \n"));
369 pSps=pChan->spsTxLsdLpf;
370 if(pSps->x)free(pSps->x);
371 if(maxctcsstxfreq>203.5)
373 pSps->ncoef=taps_fir_lpf_250_9_66;
375 pSps->coef=(void*)coef_fir_lpf_250_9_66;
376 pSps->nx=taps_fir_lpf_250_9_66;
378 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
379 pSps->calcAdjust=gain_fir_lpf_250_9_66;
380 TRACEF(1,("code_string_parse() Tx Filter Freq High\n"));
384 pSps->ncoef=taps_fir_lpf_215_9_88;
386 pSps->coef=(void*)coef_fir_lpf_215_9_88;
387 pSps->nx=taps_fir_lpf_215_9_88;
389 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
390 pSps->calcAdjust=gain_fir_lpf_215_9_88;
391 TRACEF(1,("code_string_parse() Tx Filter Freq Low\n"));
394 // CTCSS Rx Decoder Low Pass Filter
396 ii= CtcssFreqIndex(203.5);
397 for(i=ii;i<CTCSS_NUM_CODES;i++)
399 if(pChan->rxCtcssMap[i]>CTCSS_NULL)hit=1;
402 pSps=pChan->spsRxLsd;
403 if(pSps->x)free(pSps->x);
406 pSps->ncoef=taps_fir_lpf_250_9_66;
408 pSps->coef=(void*)coef_fir_lpf_250_9_66;
409 pSps->nx=taps_fir_lpf_250_9_66;
411 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
412 pSps->calcAdjust=gain_fir_lpf_250_9_66;
413 TRACEF(1,("code_string_parse() Rx Filter Freq High\n"));
417 pSps->ncoef=taps_fir_lpf_215_9_88;
419 pSps->coef=(void*)coef_fir_lpf_215_9_88;
420 pSps->nx=taps_fir_lpf_215_9_88;
422 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
423 pSps->calcAdjust=gain_fir_lpf_215_9_88;
424 TRACEF(1,("code_string_parse() Rx Filter Freq Low\n"));
427 if(pChan->b.ctcssRxEnable || pChan->b.dcsRxEnable || pChan->b.lmrRxEnable)
429 pChan->rxCenterSlicerEnable=1;
434 pChan->rxCenterSlicerEnable=0;
439 TRACEF(2,("code_string_parse() ctcssRxEnable = %i \n",pChan->b.ctcssRxEnable));
440 TRACEF(2,(" ctcssTxEnable = %i \n",pChan->b.ctcssTxEnable));
441 TRACEF(2,(" dcsRxEnable = %i \n",pChan->b.dcsRxEnable));
442 TRACEF(2,(" lmrRxEnable = %i \n",pChan->b.lmrRxEnable));
443 TRACEF(2,(" txcodedefaultsmode = %i \n",pChan->txcodedefaultsmode));
444 for(i=0;i<CTCSS_NUM_CODES;i++)
446 TRACEF(2,("rxCtcssMap[%i] = %i \n",i,pChan->rxCtcssMap[i]));
451 lsd_code_parse(pChan,5);
454 TRACEF(1,("code_string_parse(%i) end\n",0));
459 Convert a Frequency in Hz to a zero based CTCSS Table index
461 i16 CtcssFreqIndex(float freq)
463 i16 i,hit=CTCSS_NULL;
465 for(i=0;i<CTCSS_NUM_CODES;i++){
466 if(freq==freq_ctcss[i])hit=i;
472 Takes a block of data and low pass filters it.
473 Determines the amplitude of high frequency noise for carrier detect.
474 Decimates input data to change the rate.
476 i16 pmr_rx_frontend(t_pmr_sps *mySps)
478 #define DCgainBpfNoise 65536
480 i16 samples,iOutput, *input, *output, *noutput;
481 i16 *x, *coef, *coef2;
482 i32 i, naccum, outputGain, calcAdjust;
484 i16 nx, hyst, setpt, compOut;
485 i16 amax, amin, apeak, discounteru, discounterl, discfactor;
486 i16 decimator, decimate, doNoise;
488 TRACEJ(5,("pmr_rx_frontend()\n"));
490 if(!mySps->enabled)return(1);
492 decimator = mySps->decimator;
493 decimate = mySps->decimate;
495 input = mySps->source;
496 output = mySps->sink;
497 noutput = mySps->parentChan->pRxNoise;
501 coef2 = mySps->coef2;
503 calcAdjust = mySps->calcAdjust;
504 outputGain = mySps->outputGain;
509 discounteru=mySps->discounteru;
510 discounterl=mySps->discounterl;
511 discfactor=mySps->discfactor;
514 compOut=mySps->compOut;
516 samples=mySps->nSamples*decimate;
520 if(mySps->parentChan->rxCdType!=CD_XPMR_VOX)doNoise=1;
523 for(i=0;i<samples;i++)
527 //shift the old samples
528 for(n=nx-1; n>0; n--)
543 y=((y/calcAdjust)*outputGain)/M_Q8;
546 else if(y<-32767)y=-32767;
548 output[iOutput]=y; // Rx Baseband decimated
549 noutput[iOutput++] = apeak; // Rx Noise
554 // calculate noise output
557 naccum += coef_fir_bpf_noise_1[n] * x[n];
559 naccum /= DCgainBpfNoise;
564 discounteru=discfactor;
566 else if(--discounteru<=0)
568 discounteru=discfactor;
569 amax=(i32)((amax*32700)/32768);
575 discounterl=discfactor;
577 else if(--discounterl<=0)
579 discounterl=discfactor;
580 amin=(i32)((amin*32700)/32768);
590 ((t_pmr_chan *)(mySps->parentChan))->rxRssi=apeak;
592 if(apeak>setpt || (compOut&&(apeak>(setpt-hyst)))) compOut=1;
594 mySps->compOut=compOut;
598 mySps->discounteru=discounteru;
599 mySps->discounterl=discounterl;
605 pmr general purpose fir
606 works on a block of samples
608 i16 pmr_gp_fir(t_pmr_sps *mySps)
610 i32 nsamples,inputGain,outputGain,calcAdjust;
614 i16 nx, hyst, setpt, compOut;
615 i16 amax, amin, apeak=0, discounteru=0, discounterl=0, discfactor;
616 i16 decimator, decimate, interpolate;
617 i16 numChanOut, selChanOut, mixOut, monoOut;
619 TRACEJ(5,("pmr_gp_fir() %i %i\n",mySps->index, mySps->enabled));
621 if(!mySps->enabled)return(1);
623 inputGain = mySps->inputGain;
624 calcAdjust = mySps->calcAdjust;
625 outputGain = mySps->outputGain;
627 input = mySps->source;
628 output = mySps->sink;
633 decimator = mySps->decimator;
634 decimate = mySps->decimate;
635 interpolate = mySps->interpolate;
637 setpt = mySps->setpt;
638 compOut = mySps->compOut;
640 inputGain = mySps->inputGain;
641 outputGain = mySps->outputGain;
642 numChanOut = mySps->numChanOut;
643 selChanOut = mySps->selChanOut;
644 mixOut = mySps->mixOut;
645 monoOut = mySps->monoOut;
650 discfactor=mySps->discfactor;
653 nsamples=mySps->nSamples;
659 for(i=0;i<nsamples;i++)
662 output[(i*2)]=output[(i*2)+1]=0;
664 output[(i*numChanOut)+selChanOut]=0;
670 for(i=0;i<nsamples;i++)
681 for(ix=0;ix<interpolate;ix++)
686 for(n=nx-1; n>0; n--)
688 x[0] = (input[i]*inputGain)/M_Q8;
704 y=((y/calcAdjust)*outputGain)/M_Q8;
708 output[(ii*2)]=output[(ii*2)+1]+=y;
711 output[(ii*numChanOut)+selChanOut]+=y;
716 output[(ii*2)]=output[(ii*2)+1]=y;
719 output[(ii*numChanOut)+selChanOut]=y;
726 // amplitude detector
734 discounteru=discfactor;
736 else if(--discounteru<=0)
738 discounteru=discfactor;
739 amax=(i32)((amax*32700)/32768);
745 discounterl=discfactor;
747 else if(--discounterl<=0)
749 discounterl=discfactor;
750 amin=(i32)((amin*32700)/32768);
753 apeak = (i32)(amax-amin)/2;
755 if(apeak>setpt)compOut=1;
756 else if(compOut&&(apeak<(setpt-hyst)))compOut=0;
760 mySps->decimator = decimator;
765 mySps->discounteru=discounteru;
766 mySps->discounterl=discounterl;
768 mySps->compOut=compOut;
773 general purpose integrator lpf
775 i16 gp_inte_00(t_pmr_sps *mySps)
780 i32 inputGain, outputGain,calcAdjust;
785 i16 coeff00, coeff01;
787 TRACEJ(5,("gp_inte_00() %i\n",mySps->enabled));
788 if(!mySps->enabled)return(1);
790 input = mySps->source;
791 output = mySps->sink;
793 npoints=mySps->nSamples;
795 inputGain=mySps->inputGain;
796 outputGain=mySps->outputGain;
797 calcAdjust=mySps->calcAdjust;
799 coeff00=((i16*)mySps->coef)[0];
800 coeff01=((i16*)mySps->coef)[1];
801 state00=((i32*)mySps->x)[0];
803 // note fixed gain of 2 to compensate for attenuation
806 for(i=0;i<npoints;i++)
809 state00 = accum + (state00*coeff01)/M_Q15;
810 accum = (state00*coeff00)/(M_Q15/4);
811 output[i]=(accum*outputGain)/M_Q8;
814 ((i32*)(mySps->x))[0]=state00;
819 general purpose differentiator hpf
821 i16 gp_diff(t_pmr_sps *mySps)
825 i32 inputGain, outputGain, calcAdjust;
835 input = mySps->source;
836 output = mySps->sink;
838 npoints=mySps->nSamples;
840 inputGain=mySps->inputGain;
841 outputGain=mySps->outputGain;
842 calcAdjust=mySps->calcAdjust;
844 coef=(i16*)(mySps->coef);
852 TRACEJ(5,("gp_diff()\n"));
854 for (i=0;i<npoints;i++)
858 temp1 = input[i] * a0;
859 _y0 = (temp0 + temp1)/calcAdjust;
860 _y0 = (_y0*outputGain)/M_Q8;
862 if(_y0>32766)_y0=32766;
863 else if(_y0<-32766)_y0=-32766;
871 /* ----------------------------------------------------------------------
874 i16 CenterSlicer(t_pmr_sps *mySps)
876 i16 npoints,lhit,uhit;
877 i16 *input, *output, *buff;
879 i32 inputGain, outputGain, inputGainB;
883 i32 amax; // buffer amplitude maximum
884 i32 amin; // buffer amplitude minimum
885 i32 apeak; // buffer amplitude peak
887 i32 setpt; // amplitude set point for peak tracking
889 i32 discounteru; // amplitude detector integrator discharge counter upper
890 i32 discounterl; // amplitude detector integrator discharge counter lower
891 i32 discfactor; // amplitude detector integrator discharge factor
893 TRACEJ(5,("CenterSlicer() %i\n",mySps->enabled));
894 if(!mySps->enabled)return(1);
896 input = mySps->source;
897 output = mySps->sink; // limited output
900 npoints=mySps->nSamples;
902 inputGain=mySps->inputGain;
903 outputGain=mySps->outputGain;
904 inputGainB=mySps->inputGainB;
910 discounteru=mySps->discounteru;
911 discounterl=mySps->discounterl;
913 discfactor=mySps->discfactor;
914 npoints=mySps->nSamples;
916 for(i=0;i<npoints;i++)
929 if(amin<(amax-setpt))
939 if(amax>(amin+setpt))
946 if((discounteru-=1)<=0 && amax>amin)
948 if((amax-=10)<amin)amax=amin;
952 if((discounterl-=1)<=0 && amin<amax)
954 if((amin+=10)>amax)amin=amax;
957 if(uhit)discounteru=discfactor;
958 if(lhit)discounterl=discfactor;
962 if((amax-=discfactor)<amin)amax=amin;
963 if((amin+=discfactor)>amax)amin=amax;
967 apeak = (amax-amin)/2;
968 center = (amax+amin)/2;
969 accum = accum - center;
971 output[i]=accum; // sink output unlimited/centered.
973 // do limiter function
974 if(accum>inputGainB)accum=inputGainB;
975 else if(accum<-inputGainB)accum=-inputGainB;
980 mySps->parentChan->pRxLsdCen[i]=center; // trace center ref
982 if((tfx++/8)&1) // trace min/max levels
983 mySps->parentChan->pRxLsdCen[i]=amax;
985 mySps->parentChan->pRxLsdCen[i]=amin;
988 if(mySps->parentChan->frameCountRx&0x01) mySps->parentChan->prxDebug1[i]=amax;
989 else mySps->parentChan->prxDebug1[i]=amin;
997 mySps->discounteru=discounteru;
998 mySps->discounterl=discounterl;
1002 /* ----------------------------------------------------------------------
1004 determine peak amplitude
1006 i16 MeasureBlock(t_pmr_sps *mySps)
1009 i16 *input, *output;
1011 i32 inputGain, outputGain;
1015 i16 amax; // buffer amplitude maximum
1016 i16 amin; // buffer amplitude minimum
1017 i16 apeak=0; // buffer amplitude peak (peak to peak)/2
1018 i16 setpt; // amplitude set point for amplitude comparator
1020 i32 discounteru; // amplitude detector integrator discharge counter upper
1021 i32 discounterl; // amplitude detector integrator discharge counter lower
1022 i32 discfactor; // amplitude detector integrator discharge factor
1024 TRACEJ(5,("MeasureBlock() %i\n",mySps->enabled));
1026 if(!mySps->enabled)return 1;
1028 if(mySps->option==3)
1030 mySps->amax = mySps->amin = mySps->apeak = \
1031 mySps->discounteru = mySps->discounterl = \
1036 input = mySps->source;
1037 output = mySps->sink;
1039 npoints=mySps->nSamples;
1041 inputGain=mySps->inputGain;
1042 outputGain=mySps->outputGain;
1047 discounteru=mySps->discounteru;
1048 discounterl=mySps->discounterl;
1050 discfactor=mySps->discfactor;
1051 npoints=mySps->nSamples;
1053 for(i=0;i<npoints;i++)
1060 discounteru=discfactor;
1062 else if(--discounteru<=0)
1064 discounteru=discfactor;
1065 amax=(i32)((amax*32700)/32768);
1071 discounterl=discfactor;
1073 else if(--discounterl<=0)
1075 discounterl=discfactor;
1076 amin=(i32)((amin*32700)/32768);
1079 apeak = (i32)(amax-amin)/2;
1080 if(output)output[i]=apeak;
1086 mySps->discounteru=discounteru;
1087 mySps->discounterl=discounterl;
1088 if(apeak>=setpt) mySps->compOut=1;
1089 else mySps->compOut=0;
1091 //TRACEX((" -MeasureBlock()=%i\n",mySps->apeak));
1097 i16 SoftLimiter(t_pmr_sps *mySps)
1100 //i16 samples, lhit,uhit;
1101 i16 *input, *output;
1103 i32 inputGain, outputGain;
1108 i32 amax; // buffer amplitude maximum
1109 i32 amin; // buffer amplitude minimum
1110 //i32 apeak; // buffer amplitude peak
1111 i32 setpt; // amplitude set point for amplitude comparator
1112 i16 compOut; // amplitude comparator output
1114 input = mySps->source;
1115 output = mySps->sink;
1117 inputGain=mySps->inputGain;
1118 outputGain=mySps->outputGain;
1120 npoints=mySps->nSamples;
1123 amax=(setpt*124)/128;
1126 TRACEJ(5,("SoftLimiter() %i %i %i) \n",amin, amax,setpt));
1128 for(i=0;i<npoints;i++)
1131 //accum=input[i]*mySps->inputGain/256;
1135 tmp=((accum-setpt)*4)/128;
1137 if(accum>amax)accum=amax;
1141 else if(accum<-setpt)
1143 tmp=((accum+setpt)*4)/128;
1145 if(accum<amin)accum=amin;
1150 output[i]=(accum*outputGain)/M_Q8;
1156 SigGen() - sine, square function generator
1157 sps overloaded values
1158 discfactor = phase factor
1159 discfactoru = phase index
1160 if source is not NULL then mix it in!
1162 sign table and output gain are in Q15 format (32767=.999)
1164 i16 SigGen(t_pmr_sps *mySps)
1166 #define PH_FRACT_FACT 128
1169 i16 i,outputgain,waveform,numChanOut,selChanOut;
1173 pChan=mySps->parentChan;
1174 TRACEC(5,("SigGen(%i %i %i)\n",mySps->option,mySps->enabled,mySps->state));
1176 if(!mySps->freq ||!mySps->enabled)return 0;
1178 outputgain=mySps->outputGain;
1180 numChanOut=mySps->numChanOut;
1181 selChanOut=mySps->selChanOut;
1183 if(mySps->option==1)
1188 (SAMPLES_PER_SINE*mySps->freq*PH_FRACT_FACT)/mySps->sampleRate/10;
1190 TRACEF(5,(" SigGen() discfactor = %i\n",mySps->discfactor));
1191 if(mySps->discounterl)mySps->state=2;
1193 else if(mySps->option==2)
1195 i16 shiftfactor=CTCSS_TURN_OFF_SHIFT;
1196 // phase shift request
1199 mySps->discounterl=CTCSS_TURN_OFF_TIME-(2*MS_PER_FRAME); //
1201 mySps->discounteru = \
1202 (mySps->discounteru + (((SAMPLES_PER_SINE*shiftfactor)/360)*PH_FRACT_FACT)) % (SAMPLES_PER_SINE*PH_FRACT_FACT);
1203 //printf("shiftfactor = %i\n",shiftfactor);
1206 else if(mySps->option==3)
1208 // stop it and clear the output buffer
1212 for(i=0;i<mySps->nSamples;i++)
1213 mySps->sink[(i*numChanOut)+selChanOut]=0;
1216 else if(mySps->state==2)
1219 mySps->discounterl-=MS_PER_FRAME;
1220 if(mySps->discounterl<=0)
1226 else if(mySps->state==0)
1231 ph=mySps->discounteru;
1233 for(i=0;i<mySps->nSamples;i++)
1238 //tmp=(sinetablex[ph/PH_FRACT_FACT]*amplitude)/M_Q16;
1239 accum=sinetablex[ph/PH_FRACT_FACT];
1240 accum=(accum*outputgain)/M_Q8;
1245 if(ph>SAMPLES_PER_SINE/2)
1246 accum=outputgain/M_Q8;
1248 accum=-outputgain/M_Q8;
1251 if(mySps->source)accum+=mySps->source[i];
1253 mySps->sink[(i*numChanOut)+selChanOut]=accum;
1255 ph=(ph+mySps->discfactor)%(SAMPLES_PER_SINE*PH_FRACT_FACT);
1258 mySps->discounteru=ph;
1264 takes existing buffer and adds source buffer to destination buffer
1265 sink buffer = (sink buffer * gain) + source buffer
1267 i16 pmrMixer(t_pmr_sps *mySps)
1270 i16 i, *input, *inputB, *output;
1271 i16 inputGain, inputGainB; // apply to input data in Q7.8 format
1272 i16 outputGain; // apply to output data in Q7.8 format
1273 i16 discounteru,discounterl,amax,amin,setpt,discfactor;
1274 i16 npoints,uhit,lhit,apeak,measPeak;
1277 pChan=mySps->parentChan;
1278 TRACEF(5,("pmrMixer()\n"));
1280 input = mySps->source;
1281 inputB = mySps->sourceB;
1282 output = mySps->sink;
1284 inputGain=mySps->inputGain;
1285 inputGainB=mySps->inputGainB;
1286 outputGain=mySps->outputGain;
1291 discounteru=mySps->discounteru;
1292 discounterl=mySps->discounteru;
1294 discfactor=mySps->discfactor;
1295 npoints=mySps->nSamples;
1296 measPeak=mySps->measPeak;
1298 for(i=0;i<npoints;i++)
1300 accum = ((input[i]*inputGain)/M_Q8) +
1301 ((inputB[i]*inputGainB)/M_Q8);
1303 accum=(accum*outputGain)/M_Q8;
1312 if(amin<(amax-setpt)){
1317 else if(accum<amin){
1320 if(amax>(amin+setpt)){
1326 if(--discounteru<=0 && amax>0){
1331 if(--discounterl<=0 && amin<0){
1336 if(uhit)discounteru=discfactor;
1337 if(lhit)discounterl=discfactor;
1342 apeak = (amax-amin)/2;
1346 mySps->discounteru=discounteru;
1347 mySps->discounterl=discounterl;
1355 i16 DelayLine(t_pmr_sps *mySps)
1357 i16 *input, *output, *buff;
1358 i16 i, npoints,buffsize,inindex,outindex;
1361 pChan=mySps->parentChan;
1362 TRACEF(5,(" DelayLine() %i\n",mySps->enabled));
1364 input = mySps->source;
1365 output = mySps->sink;
1366 buff = (i16*)(mySps->buff);
1367 buffsize = mySps->buffSize;
1368 npoints = mySps->nSamples;
1370 outindex = mySps->buffOutIndex;
1371 inindex = outindex + mySps->buffLead;
1373 for(i=0;i<npoints;i++)
1375 inindex %= buffsize;
1376 outindex %= buffsize;
1378 buff[inindex]=input[i];
1379 output[i]=buff[outindex];
1383 mySps->buffOutIndex=outindex;
1388 Continuous Tone Coded Squelch (CTCSS) Detector
1390 i16 ctcss_detect(t_pmr_chan *pChan)
1392 i16 i,points2do,*pInput,hit,thit,relax;
1393 i16 tnum, tmp,indexNow,gain,diffpeak;
1395 i16 tv0,tv1,tv2,tv3,indexDebug;
1399 TRACEF(5,("ctcss_detect(%p) %i %i %i %i\n",pChan,
1400 pChan->rxCtcss->enabled,
1402 pChan->rxCtcss->testIndex,
1403 pChan->rxCtcss->decode));
1405 if(!pChan->rxCtcss->enabled)return(1);
1407 relax = pChan->rxCtcss->relax;
1408 pInput = pChan->rxCtcss->input;
1409 gain = pChan->rxCtcss->gain;
1411 if(relax) difftrig=(-0.1*M_Q15);
1412 else difftrig=(-0.05*M_Q15);
1416 //TRACEX((" ctcss_detect() %i %i %i %i\n", CTCSS_NUM_CODES,0,0,0));
1418 for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++)
1425 TRACEF(6,(" ctcss_detect() tnum=%i %i\n",tnum,pChan->rxCtcssMap[tnum]));
1426 //if(tnum==14)printf("ctcss_detect() %i %i %i\n",tnum,pChan->rxCtcssMap[tnum], pChan->rxCtcss->decode );
1428 if( (pChan->rxCtcssMap[tnum]==CTCSS_NULL) ||
1429 (pChan->rxCtcss->decode>CTCSS_NULL && (tnum!= pChan->rxCtcss->decode))
1433 TRACEF(6,(" ctcss_detect() tnum=%i\n",tnum));
1435 ptdet=&(pChan->rxCtcss->tdet[tnum]);
1437 points=points2do=pChan->nSamplesRx;
1438 fudgeFactor=ptdet->fudgeFactor;
1439 binFactor=ptdet->binFactor;
1441 while(ptdet->counter < (points2do*CTCSS_SCOUNT_MUL))
1443 tmp=(ptdet->counter/CTCSS_SCOUNT_MUL)+1;
1444 ptdet->counter-=(tmp*CTCSS_SCOUNT_MUL);
1446 indexNow=points-points2do;
1448 ptdet->counter += ptdet->counterFactor;
1450 accum = pInput[indexNow-1]; // duuuude's major bug fix!
1452 ptdet->z[ptdet->zIndex]+=
1453 (((accum - ptdet->z[ptdet->zIndex])*binFactor)/M_Q15);
1455 peak = abs(ptdet->z[0]-ptdet->z[2]) + abs(ptdet->z[1]-ptdet->z[3]);
1457 if (ptdet->peak < peak)
1458 ptdet->peak += ( ((peak-ptdet->peak)*binFactor)/M_Q15);
1463 static const i16 a0=13723;
1464 static const i16 a1=-13723;
1471 ptdet->zd = ptdet->peak;
1472 temp1 = ptdet->peak * a0;
1473 diffpeak = (temp0 + temp1)/1024;
1476 if(diffpeak<(-0.03*M_Q15))ptdet->dvd-=4;
1477 else if(ptdet->dvd<0)ptdet->dvd++;
1479 if((ptdet->dvd < -12) && diffpeak > (-0.02*M_Q15))ptdet->dvu+=2;
1480 else if(ptdet->dvu)ptdet->dvu--;
1483 if(pChan->rxCtcss->decode==tnum)
1485 if(relax)tmp=(tmp*55)/100;
1486 else tmp=(tmp*80)/100;
1489 if(ptdet->peak > tmp)
1491 if(ptdet->decode<(fudgeFactor*32))ptdet->decode++;
1493 else if(pChan->rxCtcss->decode==tnum)
1495 if(ptdet->peak > ptdet->hyst)ptdet->decode--;
1496 else if(relax) ptdet->decode--;
1497 else ptdet->decode-=4;
1504 if((pChan->rxCtcss->decode==tnum) && !relax && (ptdet->dvu > (0.00075*M_Q15)))
1507 ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=ptdet->dvu=0;
1508 TRACEF(4,("ctcss_detect() turnoff detected by dvdt for tnum = %i.\n",tnum));
1511 if(ptdet->decode<0 || !pChan->rxCarrierDetect)ptdet->decode=0;
1513 if(ptdet->decode>=fudgeFactor)
1516 if(pChan->rxCtcss->decode!=tnum)
1518 ptdet->zd=ptdet->dvu=ptdet->dvd=0;
1522 #if XPMR_DEBUG0 == 1
1523 if(thit>=0 && thit==tnum)
1524 TRACEF(6,(" ctcss_detect() %i %i %i %i \n",tnum,ptdet->peak,ptdet->setpt,ptdet->hyst));
1535 ptdet->lasttv0=ptdet->pDebug0[points-1];
1536 ptdet->lasttv1=ptdet->pDebug1[points-1];
1537 ptdet->lasttv2=ptdet->pDebug2[points-1];
1538 ptdet->lasttv3=ptdet->pDebug3[points-1];
1541 while(indexDebug<indexNow)
1543 ptdet->pDebug0[indexDebug]=ptdet->lasttv0;
1544 ptdet->pDebug1[indexDebug]=ptdet->lasttv1;
1545 ptdet->pDebug2[indexDebug]=ptdet->lasttv2;
1546 ptdet->pDebug3[indexDebug]=ptdet->lasttv3;
1556 ptdet->zIndex=(++ptdet->zIndex)%4;
1558 ptdet->counter-=(points2do*CTCSS_SCOUNT_MUL);
1560 #if XPMR_DEBUG0 == 1
1561 for(i=indexWas;i<points;i++)
1563 ptdet->pDebug0[i]=ptdet->lasttv0;
1564 ptdet->pDebug1[i]=ptdet->lasttv1;
1565 ptdet->pDebug2[i]=ptdet->lasttv2;
1566 ptdet->pDebug3[i]=ptdet->lasttv3;
1571 //TRACEX((" ctcss_detect() thit %i\n",thit));
1573 if(pChan->rxCtcss->BlankingTimer>0)pChan->rxCtcss->BlankingTimer-=points;
1574 if(pChan->rxCtcss->BlankingTimer<0)pChan->rxCtcss->BlankingTimer=0;
1576 if(thit>CTCSS_NULL && pChan->rxCtcss->decode<=CTCSS_NULL && !pChan->rxCtcss->BlankingTimer)
1578 pChan->rxCtcss->decode=thit;
1579 sprintf(pChan->rxctcssfreq,"%.1f",freq_ctcss[thit]);
1580 TRACEC(1,("ctcss decode %i %.1f\n",thit,freq_ctcss[thit]));
1582 else if(thit<=CTCSS_NULL && pChan->rxCtcss->decode>CTCSS_NULL)
1584 pChan->rxCtcss->BlankingTimer=SAMPLE_RATE_NETWORK/5;
1585 pChan->rxCtcss->decode=CTCSS_NULL;
1586 strcpy(pChan->rxctcssfreq,"0");
1587 TRACEC(1,("ctcss decode NULL\n"));
1588 for(tnum=0;tnum<CTCSS_NUM_CODES;tnum++)
1591 ptdet=&(pChan->rxCtcss->tdet[tnum]);
1593 ptdet->z[0]=ptdet->z[1]=ptdet->z[2]=ptdet->z[3]=0;
1596 //TRACEX((" ctcss_detect() thit %i %i\n",thit,pChan->rxCtcss->decode));
1602 static i16 TxTestTone(t_pmr_chan *pChan, i16 function)
1606 pChan->spsSigGen1->enabled=1;
1607 pChan->spsSigGen1->option=1;
1608 pChan->spsSigGen1->outputGain=(.23125*M_Q8); // to match *99 level
1609 pChan->spsTx->source=pChan->spsSigGen1->sink;
1613 pChan->spsSigGen1->option=3;
1619 sampling rate is 48KS/s
1620 samples are all 16 bits
1621 samples are filtered and decimated by 1/6th
1623 t_pmr_chan *createPmrChannel(t_pmr_chan *tChan, i16 numSamples)
1628 t_dec_ctcss *pDecCtcss;
1630 TRACEJ(1,("createPmrChannel(%p,%i)\n",tChan,numSamples));
1632 pChan = (t_pmr_chan *)calloc(sizeof(t_pmr_chan),1);
1635 printf("createPmrChannel() failed\n");
1643 pChan->index=pmrChanIndex++;
1644 pChan->nSamplesTx=pChan->nSamplesRx=numSamples;
1646 pDecCtcss = (t_dec_ctcss *)calloc(sizeof(t_dec_ctcss),1);
1647 pChan->rxCtcss=pDecCtcss;
1648 pChan->rxctcssfreq[0]=0;
1651 if(tChan->rptnum>=LSD_CHAN_MAX)tChan->rptnum=0;
1656 printf("createPmrChannel() WARNING: NULL tChan!\n");
1657 pChan->rxNoiseSquelchEnable=0;
1658 pChan->rxHpfEnable=0;
1659 pChan->rxDeEmpEnable=0;
1660 pChan->rxCenterSlicerEnable=0;
1661 pChan->rxCtcssDecodeEnable=0;
1662 pChan->rxDcsDecodeEnable=0;
1664 pChan->rxCarrierPoint = 17000;
1665 pChan->rxCarrierHyst = 2500;
1667 pChan->txHpfEnable=0;
1668 pChan->txLimiterEnable=0;
1669 pChan->txPreEmpEnable=0;
1670 pChan->txLpfEnable=1;
1671 pChan->txMixA=TX_OUT_VOICE;
1672 pChan->txMixB=TX_OUT_LSD;
1676 pChan->rxDemod=tChan->rxDemod;
1677 pChan->rxCdType=tChan->rxCdType;
1678 pChan->rxSquelchPoint = tChan->rxSquelchPoint;
1679 pChan->rxCarrierHyst = 3000;
1680 pChan->rxSqVoxAdj=tChan->rxSqVoxAdj;
1682 pChan->txMod=tChan->txMod;
1683 pChan->txHpfEnable=1;
1684 pChan->txLpfEnable=1;
1686 pChan->pTxCodeDefault=tChan->pTxCodeDefault;
1687 pChan->pRxCodeSrc=tChan->pRxCodeSrc;
1688 pChan->pTxCodeSrc=tChan->pTxCodeSrc;
1690 pChan->txMixA=tChan->txMixA;
1691 pChan->txMixB=tChan->txMixB;
1692 pChan->radioDuplex=tChan->radioDuplex;
1693 pChan->area=tChan->area;
1694 pChan->rptnum=tChan->rptnum;
1695 pChan->idleinterval=tChan->idleinterval;
1696 pChan->turnoffs=tChan->turnoffs;
1697 pChan->b.rxpolarity=tChan->b.rxpolarity;
1698 pChan->b.txpolarity=tChan->b.txpolarity;
1699 pChan->b.dcsrxpolarity=tChan->b.dcsrxpolarity;
1700 pChan->b.dcstxpolarity=tChan->b.dcstxpolarity;
1701 pChan->b.lsdrxpolarity=tChan->b.lsdrxpolarity;
1702 pChan->b.lsdtxpolarity=tChan->b.lsdtxpolarity;
1704 pChan->txsettletime=tChan->txsettletime;
1705 pChan->tracelevel=tChan->tracelevel;
1706 pChan->tracetype=tChan->tracetype;
1707 pChan->ukey=tChan->ukey;
1708 pChan->name=tChan->name;
1712 pChan->txHpfEnable=1;
1713 pChan->txLpfEnable=1;
1715 if(pChan->rxCdType==CD_XPMR_NOISE) pChan->rxNoiseSquelchEnable=1;
1717 if(pChan->rxDemod==RX_AUDIO_FLAT) pChan->rxDeEmpEnable=1;
1719 pChan->rxCarrierPoint=(pChan->rxSquelchPoint*32767)/100;
1720 pChan->rxCarrierHyst = 3000; //pChan->rxCarrierPoint/15;
1722 pChan->rxDcsDecodeEnable=0;
1724 if(pChan->b.ctcssRxEnable || pChan->b.dcsRxEnable || pChan->b.lmrRxEnable)
1726 pChan->rxHpfEnable=1;
1727 pChan->rxCenterSlicerEnable=1;
1728 pChan->rxCtcssDecodeEnable=1;
1732 pChan->txPreEmpEnable=1;
1733 pChan->txLimiterEnable=1;
1739 TRACEF(1,("calloc buffers \n"));
1741 pChan->pRxDemod = calloc(numSamples,2);
1742 pChan->pRxNoise = calloc(numSamples,2);
1743 pChan->pRxBase = calloc(numSamples,2);
1744 pChan->pRxHpf = calloc(numSamples,2);
1745 pChan->pRxLsd = calloc(numSamples,2);
1746 pChan->pRxSpeaker = calloc(numSamples,2);
1747 pChan->pRxCtcss = calloc(numSamples,2);
1748 pChan->pRxDcTrack = calloc(numSamples,2);
1749 pChan->pRxLsdLimit = calloc(numSamples,2);
1751 pChan->pTxInput = calloc(numSamples,2);
1752 pChan->pTxBase = calloc(numSamples,2);
1753 pChan->pTxHpf = calloc(numSamples,2);
1754 pChan->pTxPreEmp = calloc(numSamples,2);
1755 pChan->pTxLimiter = calloc(numSamples,2);
1756 pChan->pTxLsd = calloc(numSamples,2);
1757 pChan->pTxLsdLpf = calloc(numSamples,2);
1758 pChan->pTxComposite = calloc(numSamples,2);
1759 pChan->pSigGen0 = calloc(numSamples,2);
1760 pChan->pSigGen1 = calloc(numSamples,2);
1762 pChan->prxMeasure = calloc(numSamples,2);
1764 pChan->pTxOut = calloc(numSamples,2*2*6); // output buffer
1767 pChan->pLsdEnc = calloc(sizeof(t_encLsd),1);
1770 #if XPMR_DEBUG0 == 1
1771 TRACEF(1,("configure tracing\n"));
1773 pChan->pTstTxOut = calloc(numSamples,2);
1774 pChan->pRxLsdCen = calloc(numSamples,2);
1775 pChan->prxDebug0 = calloc(numSamples,2);
1776 pChan->prxDebug1 = calloc(numSamples,2);
1777 pChan->prxDebug2 = calloc(numSamples,2);
1778 pChan->prxDebug3 = calloc(numSamples,2);
1779 pChan->ptxDebug0 = calloc(numSamples,2);
1780 pChan->ptxDebug1 = calloc(numSamples,2);
1781 pChan->ptxDebug2 = calloc(numSamples,2);
1782 pChan->ptxDebug3 = calloc(numSamples,2);
1783 pChan->pNull = calloc(numSamples,2);
1785 for(i=0;i<numSamples;i++)pChan->pNull[i]=((i%(numSamples/2))*8000)-4000;
1787 pChan->rxCtcss->pDebug0=calloc(numSamples,2);
1788 pChan->rxCtcss->pDebug1=calloc(numSamples,2);
1789 pChan->rxCtcss->pDebug2=calloc(numSamples,2);
1790 pChan->rxCtcss->pDebug3=calloc(numSamples,2);
1792 for(i=0;i<CTCSS_NUM_CODES;i++)
1794 pChan->rxCtcss->tdet[i].pDebug0=calloc(numSamples,2);
1795 pChan->rxCtcss->tdet[i].pDebug1=calloc(numSamples,2);
1796 pChan->rxCtcss->tdet[i].pDebug2=calloc(numSamples,2);
1797 pChan->rxCtcss->tdet[i].pDebug3=calloc(numSamples,2);
1800 // buffer, 2 bytes per sample, and 16 channels
1801 pChan->prxDebug=calloc(numSamples*16,2);
1802 pChan->ptxDebug=calloc(numSamples*16,2);
1804 // TSCOPE CONFIGURATION SETSCOPE configure debug traces and sources for each channel of the output
1805 pChan->sdbg = (t_sdbg *)calloc(sizeof(t_sdbg),1);
1807 for(i=0;i<XPMR_DEBUG_CHANS;i++)pChan->sdbg->trace[i]=-1;
1809 TRACEF(1,("pChan->tracetype = %i\n",pChan->tracetype));
1811 if(pChan->tracetype==1) // CTCSS DECODE
1813 pChan->sdbg->source [0]=pChan->pRxDemod;
1814 pChan->sdbg->source [1]=pChan->pRxBase;
1815 pChan->sdbg->source [2]=pChan->pRxNoise;
1816 pChan->sdbg->trace [3]=RX_NOISE_TRIG;
1817 pChan->sdbg->source [4]=pChan->pRxLsd;
1818 pChan->sdbg->source [5]=pChan->pRxLsdCen;
1819 pChan->sdbg->source [6]=pChan->pRxLsdLimit;
1820 pChan->sdbg->source [7]=pChan->rxCtcss->tdet[3].pDebug0;
1821 pChan->sdbg->trace [8]=RX_CTCSS_DECODE;
1822 pChan->sdbg->trace [9]=RX_SMODE;
1824 if(pChan->tracetype==2) // CTCSS DECODE
1826 pChan->sdbg->source [0]=pChan->pRxDemod;
1827 pChan->sdbg->source [1]=pChan->pRxBase;
1828 pChan->sdbg->trace [2]=RX_NOISE_TRIG;
1829 pChan->sdbg->source [3]=pChan->pRxLsd;
1830 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1831 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1832 pChan->sdbg->source [6]=pChan->pRxLsdLimit;
1833 pChan->sdbg->source [7]=pChan->rxCtcss->tdet[3].pDebug0;
1834 pChan->sdbg->source [8]=pChan->rxCtcss->tdet[3].pDebug1;
1835 pChan->sdbg->source [9]=pChan->rxCtcss->tdet[3].pDebug2;
1836 pChan->sdbg->source [10]=pChan->rxCtcss->tdet[3].pDebug3;
1837 pChan->sdbg->trace [11]=RX_CTCSS_DECODE;
1838 pChan->sdbg->trace [12]=RX_SMODE;
1839 pChan->sdbg->trace [13]=TX_PTT_IN;
1840 pChan->sdbg->trace [14]=TX_PTT_OUT;
1841 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1843 else if(pChan->tracetype==3) // DCS DECODE
1845 pChan->sdbg->source [0]=pChan->pRxDemod;
1846 pChan->sdbg->source [1]=pChan->pRxBase;
1847 pChan->sdbg->trace [2]=RX_NOISE_TRIG;
1848 pChan->sdbg->source [3]=pChan->pRxLsd;
1849 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1850 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1851 pChan->sdbg->trace [6]=RX_DCS_CLK;
1852 pChan->sdbg->trace [7]=RX_DCS_DIN;
1853 pChan->sdbg->trace [8]=RX_DCS_DEC;
1854 pChan->sdbg->trace [9]=RX_SMODE;
1855 pChan->sdbg->trace [10]=TX_PTT_IN;
1856 pChan->sdbg->trace [11]=TX_PTT_OUT;
1857 pChan->sdbg->trace [12]=TX_LSD_CLK;
1858 pChan->sdbg->trace [13]=TX_LSD_DAT;
1859 pChan->sdbg->trace [14]=TX_LSD_GEN;
1860 pChan->sdbg->source [14]=pChan->pTxLsd;
1861 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1863 else if(pChan->tracetype==4) // LSD DECODE
1865 pChan->sdbg->source [0]=pChan->pRxDemod;
1866 pChan->sdbg->source [1]=pChan->pRxBase;
1867 pChan->sdbg->trace [2]=RX_NOISE_TRIG;
1868 pChan->sdbg->source [3]=pChan->pRxLsd;
1869 pChan->sdbg->source [4]=pChan->pRxLsdCen;
1870 pChan->sdbg->source [5]=pChan->pRxDcTrack;
1871 pChan->sdbg->trace [6]=RX_LSD_CLK;
1872 pChan->sdbg->trace [7]=RX_LSD_DAT;
1873 pChan->sdbg->trace [8]=RX_LSD_ERR;
1874 pChan->sdbg->trace [9]=RX_LSD_SYNC;
1875 pChan->sdbg->trace [10]=RX_SMODE;
1876 pChan->sdbg->trace [11]=TX_PTT_IN;
1877 pChan->sdbg->trace [12]=TX_PTT_OUT;
1878 pChan->sdbg->trace [13]=TX_LSD_CLK;
1879 pChan->sdbg->trace [14]=TX_LSD_DAT;
1880 //pChan->sdbg->trace [14]=TX_LSD_GEN;
1881 //pChan->sdbg->source [14]=pChan->pTxLsd;
1882 pChan->sdbg->source [15]=pChan->pTxLsdLpf;
1884 else if(pChan->tracetype==5) // LSD LOGIC
1886 pChan->sdbg->source [0]=pChan->pRxBase;
1887 pChan->sdbg->trace [1]=RX_NOISE_TRIG;
1888 pChan->sdbg->source [2]=pChan->pRxDcTrack;
1889 pChan->sdbg->trace [3]=RX_LSD_SYNC;
1890 pChan->sdbg->trace [4]=RX_SMODE;
1891 pChan->sdbg->trace [5]=TX_PTT_IN;
1892 pChan->sdbg->trace [6]=TX_PTT_OUT;
1893 pChan->sdbg->source [7]=pChan->pTxLsdLpf;
1895 else if(pChan->tracetype==6)
1897 // tx clock skew and jitter buffer
1898 pChan->sdbg->source [0]=pChan->pRxDemod;
1899 pChan->sdbg->source [5]=pChan->pTxBase;
1900 pChan->sdbg->trace [6]=TX_DEDRIFT_LEAD;
1901 pChan->sdbg->trace [7]=TX_DEDRIFT_ERR;
1902 pChan->sdbg->trace [8]=TX_DEDRIFT_FACTOR;
1903 pChan->sdbg->trace [9]=TX_DEDRIFT_DRIFT;
1905 else if(pChan->tracetype==7)
1908 pChan->sdbg->source [0]=pChan->pRxBase;
1909 pChan->sdbg->trace [1]=RX_NOISE_TRIG;
1910 pChan->sdbg->source [2]=pChan->pRxLsd;
1911 pChan->sdbg->trace [3]=RX_CTCSS_DECODE;
1912 pChan->sdbg->source [4]=pChan->pRxHpf;
1914 pChan->sdbg->trace [5]=TX_PTT_IN;
1915 pChan->sdbg->trace [6]=TX_PTT_OUT;
1917 pChan->sdbg->source [7]=pChan->pTxBase;
1918 pChan->sdbg->source [8]=pChan->pTxHpf;
1919 pChan->sdbg->source [9]=pChan->pTxPreEmp;
1920 pChan->sdbg->source [10]=pChan->pTxLimiter;
1921 pChan->sdbg->source [11]=pChan->pTxComposite;
1922 pChan->sdbg->source [12]=pChan->pTxLsdLpf;
1925 for(i=0;i<XPMR_DEBUG_CHANS;i++){
1926 if(pChan->sdbg->trace[i]>=0)pChan->sdbg->point[pChan->sdbg->trace[i]]=i;
1928 pChan->sdbg->mode=1;
1933 pSps=pChan->spsLsdGen=createPmrSps(pChan);
1935 pSps->sink=pChan->pTxLsd;
1938 pSps->sigProc=LsdGen;
1939 pSps->nSamples=pChan->nSamplesTx;
1940 pSps->outputGain=(.25*M_Q8);
1942 pSps->interpolate=1;
1947 // General Purpose Function Generator
1948 pSps=pChan->spsSigGen1=createPmrSps(pChan);
1949 pSps->sink=pChan->pSigGen1;
1952 pSps->sigProc=SigGen;
1953 pSps->nSamples=pChan->nSamplesTx;
1954 pSps->sampleRate=SAMPLE_RATE_NETWORK;
1955 pSps->freq=10000; // in increments of 0.1 Hz
1956 pSps->outputGain=(.25*M_Q8);
1958 pSps->interpolate=1;
1964 pSps = pChan->spsSigGen0 = createPmrSps(pChan);
1965 pSps->sink=pChan->pTxLsd;
1966 pSps->sigProc=SigGen;
1969 pSps->nSamples=pChan->nSamplesTx;
1970 pSps->sampleRate=SAMPLE_RATE_NETWORK;
1971 pSps->freq=1000; // in 0.1 Hz steps
1972 pSps->outputGain=(0.5*M_Q8);
1974 pSps->interpolate=1;
1978 // Tx LSD Low Pass Filter
1979 pSps=pChan->spsTxLsdLpf=createPmrSps(pChan);
1980 pSps->source=pChan->pTxLsd;
1981 pSps->sink=pChan->pTxLsdLpf;
1982 pSps->sigProc=pmr_gp_fir;
1986 pSps->nSamples=pChan->nSamplesTx;
1987 pSps->decimator=pSps->decimate=1;
1988 pSps->interpolate=1;
1989 pSps->inputGain=(1*M_Q8);
1990 pSps->outputGain=(1*M_Q8);
1992 // configure the longer, lower cutoff filter by default
1993 pSps->ncoef=taps_fir_lpf_215_9_88;
1995 pSps->coef=(void*)coef_fir_lpf_215_9_88;
1996 pSps->nx=taps_fir_lpf_215_9_88;
1998 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
1999 pSps->calcAdjust=gain_fir_lpf_215_9_88;
2001 pSps->inputGain=(1*M_Q8);
2002 pSps->outputGain=(1*M_Q8);
2004 TRACEF(1,("spsTxLsdLpf = sps \n"));
2006 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2010 TRACEF(1,("create rx\n"));
2013 // allocate space for first sps and set pointers
2014 pSps=pChan->spsRx=createPmrSps(pChan);
2015 pSps->source=NULL; //set when called
2016 pSps->sink=pChan->pRxBase;
2017 pSps->sigProc=pmr_rx_frontend;
2019 pSps->decimator=pSps->decimate=6;
2020 pSps->interpolate=pSps->interpolate=1;
2021 pSps->nSamples=pChan->nSamplesRx;
2022 pSps->ncoef=taps_fir_bpf_noise_1;
2024 pSps->coef=(void*)coef_fir_lpf_3K_1;
2025 pSps->coef2=(void*)coef_fir_bpf_noise_1;
2026 pSps->nx=taps_fir_bpf_noise_1;
2028 pSps->x=(void*)(calloc(pSps->nx,pSps->size_coef));
2029 pSps->calcAdjust=(gain_fir_lpf_3K_1*256)/0x0100;
2030 pSps->outputGain=(1.0*M_Q8);
2032 pSps->hyst=pChan->rxCarrierHyst;
2033 pSps->setpt=pChan->rxCarrierPoint;
2034 pChan->prxSquelchAdjust=&pSps->setpt;
2035 #if XPMR_DEBUG0 == 1
2036 pSps->debugBuff0=pChan->pRxDemod;
2037 pSps->debugBuff1=pChan->pRxNoise;
2038 pSps->debugBuff2=pChan->prxDebug0;
2042 // allocate space for next sps and set pointers
2043 // Rx SubAudible Decoder Low Pass Filter
2044 pSps=pChan->spsRxLsd=pSps->nextSps=createPmrSps(pChan);
2045 pSps->source=pChan->pRxBase;
2046 pSps->sink=pChan->pRxLsd;
2047 pSps->sigProc=pmr_gp_fir;
2051 pSps->nSamples=pChan->nSamplesRx;
2052 pSps->decimator=pSps->decimate=1;
2053 pSps->interpolate=1;
2055 // configure the the larger, lower cutoff filter by default
2056 pSps->ncoef=taps_fir_lpf_215_9_88;
2058 pSps->coef=(void*)coef_fir_lpf_215_9_88;
2059 pSps->nx=taps_fir_lpf_215_9_88;
2061 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2062 pSps->calcAdjust=gain_fir_lpf_215_9_88;
2064 pSps->inputGain=(1*M_Q8);
2065 pSps->outputGain=(1*M_Q8);
2066 pChan->prxCtcssMeasure=pSps->sink;
2067 pChan->prxCtcssAdjust=&(pSps->outputGain);
2069 // CTCSS CenterSlicer
2070 pSps=pChan->spsRxLsdNrz=pSps->nextSps=createPmrSps(pChan);
2071 pSps->source=pChan->pRxLsd;
2072 pSps->sink=pChan->pRxDcTrack;
2073 pSps->buff=pChan->pRxLsdLimit;
2074 pSps->sigProc=CenterSlicer;
2075 pSps->nSamples=pChan->nSamplesRx;
2076 pSps->discfactor=LSD_DFS; // centering time constant
2077 pSps->inputGain=(1*M_Q8);
2078 pSps->outputGain=(1*M_Q8);
2079 pSps->setpt=4900; // ptp clamp for DC centering
2080 pSps->inputGainB=625; // peak output limiter clip point
2085 pSps=pSps->nextSps=createPmrSps(pChan);
2086 pChan->spsRxHpf=pSps;
2087 pSps->source=pChan->pRxBase;
2088 pSps->sink=pChan->pRxHpf;
2089 pSps->sigProc=pmr_gp_fir;
2093 pSps->nSamples=pChan->nSamplesRx;
2094 pSps->decimator=pSps->decimate=1;
2095 pSps->interpolate=1;
2096 pSps->ncoef=taps_fir_hpf_300_9_66;
2098 pSps->coef=(void*)coef_fir_hpf_300_9_66;
2099 pSps->nx=taps_fir_hpf_300_9_66;
2101 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2102 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2103 pSps->calcAdjust=gain_fir_hpf_300_9_66;
2104 pSps->inputGain=(1*M_Q8);
2105 pSps->outputGain=(1*M_Q8);
2106 pChan->prxVoiceAdjust=&(pSps->outputGain);
2107 pChan->spsRxOut=pSps;
2109 // allocate space for next sps and set pointers
2111 if(pChan->rxDeEmpEnable){
2112 pSps=pSps->nextSps=createPmrSps(pChan);
2113 pChan->spsRxDeEmp=pSps;
2114 pSps->source=pChan->pRxHpf;
2115 pSps->sink=pChan->pRxSpeaker;
2116 pChan->spsRxOut=pSps; // OUTPUT STRUCTURE!
2117 pSps->sigProc=gp_inte_00;
2119 pSps->nSamples=pChan->nSamplesRx;
2121 pSps->ncoef=taps_int_lpf_300_1_2;
2123 pSps->coef=(void*)coef_int_lpf_300_1_2;
2125 pSps->nx=taps_int_lpf_300_1_2;
2127 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2128 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2129 pSps->calcAdjust=gain_int_lpf_300_1_2/2;
2130 pSps->inputGain=(1.0*M_Q8);
2131 pSps->outputGain=(1.0*M_Q8);
2132 pChan->prxVoiceMeasure=pSps->sink;
2133 pChan->prxVoiceAdjust=&(pSps->outputGain);
2136 if(pChan->rxDelayLineEnable)
2138 TRACEF(1,("create delayline\n"));
2139 pSps=pChan->spsDelayLine=pSps->nextSps=createPmrSps(pChan);
2140 pSps->sigProc=DelayLine;
2141 pSps->source=pChan->pRxSpeaker;
2142 pSps->sink=pChan->pRxSpeaker;
2144 pSps->inputGain=1*M_Q8;
2145 pSps->outputGain=1*M_Q8;
2146 pSps->nSamples=pChan->nSamplesRx;
2147 pSps->buffSize=4096;
2148 pSps->buff=calloc(4096,2); // one second maximum
2149 pSps->buffLead = (SAMPLE_RATE_NETWORK*0.100);
2150 pSps->buffOutIndex=0;
2153 if(pChan->rxCdType==CD_XPMR_VOX)
2155 TRACEF(1,("create vox measureblock\n"));
2156 pChan->prxVoxMeas=calloc(pChan->nSamplesRx,2);
2158 pSps=pChan->spsRxVox=pSps->nextSps=createPmrSps(pChan);
2159 pSps->sigProc=MeasureBlock;
2160 pSps->parentChan=pChan;
2161 pSps->source=pChan->pRxBase;
2162 pSps->sink=pChan->prxVoxMeas;
2163 pSps->inputGain=1*M_Q8;
2164 pSps->outputGain=1*M_Q8;
2165 pSps->nSamples=pChan->nSamplesRx;
2167 if(pChan->rxSqVoxAdj==0)
2168 pSps->setpt=(0.011*M_Q15);
2170 pSps->setpt=(pChan->rxSqVoxAdj);
2171 pSps->hyst=(pSps->setpt/10);
2175 // tuning measure block
2176 pSps=pChan->spsMeasure=pSps->nextSps=createPmrSps(pChan);
2177 pSps->source=pChan->spsRx->sink;
2178 pSps->sink=pChan->prxMeasure;
2179 pSps->sigProc=MeasureBlock;
2181 pSps->nSamples=pChan->nSamplesRx;
2182 pSps->discfactor=10;
2184 pSps->nextSps=NULL; // last sps in chain RX
2187 // CREATE TRANSMIT CHAIN
2188 TRACEF(1,("create tx\n"));
2192 // allocate space for first sps and set pointers
2194 // Tx HPF SubAudible
2195 if(pChan->txHpfEnable)
2197 pSps=createPmrSps(pChan);
2199 pSps->source=pChan->pTxBase;
2200 pSps->sink=pChan->pTxHpf;
2201 pSps->sigProc=pmr_gp_fir;
2205 pSps->nSamples=pChan->nSamplesTx;
2206 pSps->decimator=pSps->decimate=1;
2207 pSps->interpolate=1;
2208 pSps->ncoef=taps_fir_hpf_300_9_66;
2210 pSps->coef=(void*)coef_fir_hpf_300_9_66;
2211 pSps->nx=taps_fir_hpf_300_9_66;
2213 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2214 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2215 pSps->calcAdjust=gain_fir_hpf_300_9_66;
2216 pSps->inputGain=(1*M_Q8);
2217 pSps->outputGain=(1*M_Q8);
2218 inputTmp=pChan->pTxHpf;
2222 if(pChan->txPreEmpEnable)
2224 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2225 else pSps=pSps->nextSps=createPmrSps(pChan);
2227 pSps->source=inputTmp;
2228 pSps->sink=pChan->pTxPreEmp;
2230 pSps->sigProc=gp_diff;
2232 pSps->nSamples=pChan->nSamplesTx;
2234 pSps->ncoef=taps_int_hpf_4000_1_2;
2236 pSps->coef=(void*)coef_int_hpf_4000_1_2;
2238 pSps->nx=taps_int_hpf_4000_1_2;
2240 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2241 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2243 pSps->calcAdjust=gain_int_hpf_4000_1_2;
2244 pSps->inputGain=(1*M_Q8);
2245 pSps->outputGain=(1*M_Q8); // to match flat at 1KHz
2246 inputTmp=pSps->sink;
2250 if(pChan->txLimiterEnable)
2252 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2253 else pSps=pSps->nextSps=createPmrSps(pChan);
2254 pSps->source=inputTmp;
2255 pSps->sink=pChan->pTxLimiter;
2256 pSps->sigProc=SoftLimiter;
2258 pSps->nSamples=pChan->nSamplesTx;
2259 pSps->inputGain=(1*M_Q8);
2260 pSps->outputGain=(1*M_Q8);
2262 inputTmp=pSps->sink;
2265 // Composite Mix of Voice and LSD
2266 if((pChan->txMixA==TX_OUT_COMPOSITE)||(pChan->txMixB==TX_OUT_COMPOSITE))
2269 pSps=pChan->spsTx=createPmrSps(pChan);
2271 pSps=pSps->nextSps=createPmrSps(pChan);
2272 pSps->source=inputTmp;
2273 pSps->sourceB=pChan->pTxLsdLpf; //asdf ??? !!! maw pTxLsdLpf
2274 pSps->sink=pChan->pTxComposite;
2275 pSps->sigProc=pmrMixer;
2277 pSps->nSamples=pChan->nSamplesTx;
2278 pSps->inputGain=2*M_Q8;
2279 pSps->inputGainB=1*M_Q8/8;
2280 pSps->outputGain=1*M_Q8;
2282 inputTmp=pSps->sink;
2283 pChan->ptxCtcssAdjust=&pSps->inputGainB;
2286 // Chan A Upsampler and Filter
2287 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2288 else pSps=pSps->nextSps=createPmrSps(pChan);
2290 pChan->spsTxOutA=pSps;
2291 if(!pChan->spsTx)pChan->spsTx=pSps;
2293 if(pChan->txMixA==TX_OUT_COMPOSITE)
2295 pSps->source=pChan->pTxComposite;
2297 else if(pChan->txMixA==TX_OUT_LSD)
2299 pSps->source=pChan->pTxLsdLpf;
2301 else if(pChan->txMixA==TX_OUT_VOICE)
2303 pSps->source=pChan->pTxHpf;
2305 else if (pChan->txMixA==TX_OUT_AUX)
2307 pSps->source=inputTmp;
2311 pSps->source=NULL; // maw sph asdf !!! no blow up
2312 pSps->source=inputTmp;
2315 pSps->sink=pChan->pTxOut;
2316 pSps->sigProc=pmr_gp_fir;
2320 pSps->nSamples=pChan->nSamplesTx;
2321 pSps->interpolate=6;
2322 pSps->ncoef=taps_fir_lpf_3K_1;
2324 pSps->coef=(void*)coef_fir_lpf_3K_1;
2325 pSps->nx=taps_fir_lpf_3K_1;
2327 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2328 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2329 pSps->calcAdjust=gain_fir_lpf_3K_1;
2330 pSps->inputGain=(1*M_Q8);
2331 pSps->outputGain=(1*M_Q8);
2332 if(pChan->txMixA==pChan->txMixB)pSps->monoOut=1;
2333 else pSps->monoOut=0;
2336 // Chan B Upsampler and Filter
2337 if((pChan->txMixA!=pChan->txMixB)&&(pChan->txMixB!=TX_OUT_OFF))
2339 if(pSps==NULL) pSps=pChan->spsTx=createPmrSps(pChan);
2340 else pSps=pSps->nextSps=createPmrSps(pChan);
2342 pChan->spsTxOutB=pSps;
2343 if(pChan->txMixB==TX_OUT_COMPOSITE)
2345 pSps->source=pChan->pTxComposite;
2347 else if(pChan->txMixB==TX_OUT_LSD)
2349 pSps->source=pChan->pTxLsdLpf;
2350 // pChan->ptxCtcssAdjust=&pSps->inputGain;
2352 else if(pChan->txMixB==TX_OUT_VOICE)
2354 pSps->source=inputTmp;
2356 else if(pChan->txMixB==TX_OUT_AUX)
2358 pSps->source=pChan->pTxHpf;
2365 pSps->sink=pChan->pTxOut;
2366 pSps->sigProc=pmr_gp_fir;
2371 pSps->nSamples=pChan->nSamplesTx;
2372 pSps->interpolate=6;
2373 pSps->ncoef=taps_fir_lpf_3K_1;
2375 pSps->coef=(void*)coef_fir_lpf_3K_1;
2376 pSps->nx=taps_fir_lpf_3K_1;
2378 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2379 if(pSps==NULL)printf("Error: calloc(), createPmrChannel()\n");
2380 pSps->calcAdjust=(gain_fir_lpf_3K_1);
2381 pSps->inputGain=(1*M_Q8);
2382 pSps->outputGain=(1*M_Q8);
2387 // Configure Coded Signaling
2388 code_string_parse(pChan);
2390 pChan->smode=SMODE_NULL;
2391 pChan->smodewas=SMODE_NULL;
2392 pChan->smodetime=2500;
2393 pChan->smodetimer=0;
2394 pChan->b.smodeturnoff=0;
2396 pChan->txsettletimer=0;
2398 TRACEF(1,("createPmrChannel() end\n"));
2404 i16 destroyPmrChannel(t_pmr_chan *pChan)
2406 #if XPMR_DEBUG0 == 1
2409 t_pmr_sps *pmr_sps, *tmp_sps;
2411 TRACEF(1,("destroyPmrChannel()\n"));
2413 free(pChan->pRxDemod);
2414 free(pChan->pRxNoise);
2415 free(pChan->pRxBase);
2416 free(pChan->pRxHpf);
2417 free(pChan->pRxLsd);
2418 free(pChan->pRxSpeaker);
2419 free(pChan->pRxDcTrack);
2420 if(pChan->pRxLsdLimit)free(pChan->pRxLsdLimit);
2421 free(pChan->pTxBase);
2422 free(pChan->pTxHpf);
2423 free(pChan->pTxPreEmp);
2424 free(pChan->pTxLimiter);
2425 free(pChan->pTxLsd);
2426 free(pChan->pTxLsdLpf);
2427 if(pChan->pTxComposite)free(pChan->pTxComposite);
2428 free(pChan->pTxOut);
2430 if(pChan->prxMeasure)free(pChan->prxMeasure);
2431 if(pChan->pSigGen0)free(pChan->pSigGen0);
2432 if(pChan->pSigGen1)free(pChan->pSigGen1);
2435 #if XPMR_DEBUG0 == 1
2436 //if(pChan->prxDebug)free(pChan->prxDebug);
2437 if(pChan->ptxDebug)free(pChan->ptxDebug);
2438 free(pChan->prxDebug0);
2439 free(pChan->prxDebug1);
2440 free(pChan->prxDebug2);
2441 free(pChan->prxDebug3);
2443 free(pChan->ptxDebug0);
2444 free(pChan->ptxDebug1);
2445 free(pChan->ptxDebug2);
2446 free(pChan->ptxDebug3);
2448 free(pChan->rxCtcss->pDebug0);
2449 free(pChan->rxCtcss->pDebug1);
2451 for(i=0;i<CTCSS_NUM_CODES;i++)
2453 free(pChan->rxCtcss->tdet[i].pDebug0);
2454 free(pChan->rxCtcss->tdet[i].pDebug1);
2455 free(pChan->rxCtcss->tdet[i].pDebug2);
2456 free(pChan->rxCtcss->tdet[i].pDebug3);
2463 free(pChan->pRxCtcss);
2465 pmr_sps=pChan->spsRx;
2467 if(pChan->sdbg)free(pChan->sdbg);
2472 pmr_sps = tmp_sps->nextSps;
2473 destroyPmrSps(tmp_sps);
2482 t_pmr_sps *createPmrSps(t_pmr_chan *pChan)
2486 TRACEF(1,("createPmrSps()\n"));
2488 pSps = (t_pmr_sps *)calloc(sizeof(t_pmr_sps),1);
2490 if(!pSps)printf("Error: createPmrSps()\n");
2492 pSps->parentChan=pChan;
2493 pSps->index=pChan->spsIndex++;
2495 // pSps->x=calloc(pSps->nx,pSps->size_x);
2501 i16 destroyPmrSps(t_pmr_sps *pSps)
2503 TRACEJ(1,("destroyPmrSps(%i)\n",pSps->index));
2505 if(pSps->x!=NULL)free(pSps->x);
2510 PmrTx - takes data from network and holds it for PmrRx
2512 i16 PmrTx(t_pmr_chan *pChan, i16 *input)
2514 pChan->frameCountTx++;
2516 TRACEF(5,("PmrTx() start %i\n",pChan->frameCountTx));
2520 if(pptp_p2)ioctl(ppdrvdev,PPDRV_IOC_PINSET,LP_PIN02);
2521 else ioctl(ppdrvdev,PPDRV_IOC_PINCLEAR,LP_PIN02);
2525 printf("PmrTx() pChan == NULL\n");
2529 #if XPMR_DEBUG0 == 1
2530 if(pChan->b.rxCapture && pChan->tracetype==5)
2532 memcpy(pChan->pTxInput,input,pChan->nSamplesRx*2);
2536 //if(pChan->b.radioactive)pChan->dd.debug=1;
2537 //else pChan->dd.debug=0;
2539 dedrift_write(pChan,input);
2544 PmrRx handles a block of data from the usb audio device
2546 i16 PmrRx(t_pmr_chan *pChan, i16 *input, i16 *outputrx, i16 *outputtx)
2552 TRACEC(5,("PmrRx(%p %p %p %p)\n",pChan, input, outputrx, outputtx));
2555 if(pChan->b.radioactive)
2557 pptp_write(1,pChan->frameCountRx&0x00000001);
2562 printf("PmrRx() pChan == NULL\n");
2566 pChan->frameCountRx++;
2568 #if XPMR_DEBUG0 == 1
2569 if(pChan->b.rxCapture)
2571 //if(pChan->prxDebug)memset((void *)pChan->prxDebug,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2572 if(pChan->ptxDebug)memset((void *)pChan->ptxDebug,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2573 if(pChan->sdbg->buffer)
2575 memset((void *)pChan->sdbg->buffer,0,pChan->nSamplesRx*XPMR_DEBUG_CHANS*2);
2576 pChan->prxDebug=pChan->sdbg->buffer;
2581 pmr_sps=pChan->spsRx; // first sps
2582 pmr_sps->source=input;
2584 if(outputrx!=NULL)pChan->spsRxOut->sink=outputrx; //last sps
2587 if(pChan->inputBlanking>0)
2589 pChan->inputBlanking-=pChan->nSamplesRx;
2590 if(pChan->inputBlanking<0)pChan->inputBlanking=0;
2591 for(i=0;i<pChan->nSamplesRx*6;i++)
2596 if( pChan->rxCpuSaver && !pChan->rxCarrierDetect &&
2597 pChan->smode==SMODE_NULL &&
2598 !pChan->txPttIn && !pChan->txPttOut)
2600 if(!pChan->b.rxhalted)
2602 if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=0;
2603 if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=0;
2604 pChan->b.rxhalted=1;
2605 TRACEC(1,("PmrRx() rx sps halted\n"));
2608 else if(pChan->b.rxhalted)
2610 if(pChan->spsRxHpf)pChan->spsRxHpf->enabled=1;
2611 if(pChan->spsRxDeEmp)pChan->spsRxDeEmp->enabled=1;
2612 pChan->b.rxhalted=0;
2613 TRACEC(1,("PmrRx() rx sps un-halted\n"));
2617 while(pmr_sps!=NULL && pmr_sps!=0)
2619 TRACEC(5,("PmrRx() sps %i\n",i++));
2620 pmr_sps->sigProc(pmr_sps);
2621 pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps);
2622 //pmr_sps=NULL; // sph maw
2625 #define XPMR_VOX_HANGTIME 2000
2627 if(pChan->rxCdType==CD_XPMR_VOX)
2629 if(pChan->spsRxVox->compOut)
2631 pChan->rxVoxTimer=XPMR_VOX_HANGTIME; //VOX HangTime in ms
2633 if(pChan->rxVoxTimer>0)
2635 pChan->rxVoxTimer-=MS_PER_FRAME;
2636 pChan->rxCarrierDetect=1;
2640 pChan->rxVoxTimer=0;
2641 pChan->rxCarrierDetect=0;
2646 pChan->rxCarrierDetect=!pChan->spsRx->compOut;
2649 // stop and start these engines instead to eliminate falsing
2650 if( pChan->b.ctcssRxEnable &&
2651 ( (!pChan->b.rxhalted ||
2652 pChan->rxCtcss->decode!=CTCSS_NULL || pChan->smode==SMODE_CTCSS) &&
2653 (pChan->smode!=SMODE_DCS&&pChan->smode!=SMODE_LSD) )
2656 ctcss_detect(pChan);
2660 if(pChan->txPttIn!=pChan->b.pttwas)
2662 pChan->b.pttwas=pChan->txPttIn;
2663 TRACEC(1,("PmrRx() txPttIn=%i\n",pChan->b.pttwas));
2668 xpmrx(pChan,XXO_RXDECODE);
2671 if(pChan->smodetimer>0 && !pChan->txPttIn)
2673 pChan->smodetimer-=MS_PER_FRAME;
2675 if(pChan->smodetimer<=0)
2677 pChan->smodetimer=0;
2678 pChan->smodewas=pChan->smode;
2679 pChan->smode=SMODE_NULL;
2680 pChan->b.smodeturnoff=1;
2681 TRACEC(1,("smode timeout. smode was=%i\n",pChan->smodewas));
2685 if(pChan->rxCtcss->decode > CTCSS_NULL &&
2686 (pChan->smode==SMODE_NULL||pChan->smode==SMODE_CTCSS) )
2688 if(pChan->smode!=SMODE_CTCSS)
2690 TRACEC(1,("smode set=%i code=%i\n",pChan->smode,pChan->rxCtcss->decode));
2691 pChan->smode=pChan->smodewas=SMODE_CTCSS;
2693 pChan->smodetimer=pChan->smodetime;
2697 xpmrx(pChan,XXO_LSDCTL);
2700 //TRACEX(("PmrRx() tx portion.\n"));
2702 // handle radio transmitter ptt input
2704 if( !(pChan->smode==SMODE_DCS||pChan->smode==SMODE_LSD) )
2707 if( pChan->txPttIn && pChan->txState==CHAN_TXSTATE_IDLE )
2709 TRACEC(1,("txPttIn==1 from CHAN_TXSTATE_IDLE && !SMODE_LSD. codeindex=%i %i \n",pChan->rxCtcss->decode, pChan->rxCtcssMap[pChan->rxCtcss->decode] ));
2710 pChan->dd.b.doitnow=1;
2712 if(pChan->smode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2714 if(pChan->rxCtcss->decode>CTCSS_NULL)
2716 if(pChan->rxCtcssMap[pChan->rxCtcss->decode]!=CTCSS_RXONLY)
2718 f=freq_ctcss[pChan->rxCtcssMap[pChan->rxCtcss->decode]];
2723 f=pChan->txctcssdefault_value;
2725 TRACEC(1,("txPttIn - Start CTCSSGen %f \n",f));
2730 pChan->spsSigGen0->freq=f*10;
2731 pSps=pChan->spsTxLsdLpf;
2737 pSps->ncoef=taps_fir_lpf_250_9_66;
2739 pSps->coef=(void*)coef_fir_lpf_250_9_66;
2740 pSps->nx=taps_fir_lpf_250_9_66;
2742 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2743 pSps->calcAdjust=gain_fir_lpf_250_9_66;
2747 pSps->ncoef=taps_fir_lpf_215_9_88;
2749 pSps->coef=(void*)coef_fir_lpf_215_9_88;
2750 pSps->nx=taps_fir_lpf_215_9_88;
2752 pSps->x=(void*)(calloc(pSps->nx,pSps->size_x));
2753 pSps->calcAdjust=gain_fir_lpf_215_9_88;
2757 pChan->spsSigGen0->option=1;
2758 pChan->spsSigGen0->enabled=1;
2759 pChan->spsSigGen0->discounterl=0;
2762 else if(pChan->smode==SMODE_NULL && pChan->txcodedefaultsmode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2764 TRACEC(1,("txPtt Encode txcodedefaultsmode==SMODE_CTCSS %f\n",pChan->txctcssdefault_value));
2765 pChan->spsSigGen0->freq=pChan->txctcssdefault_value*10;
2766 pChan->spsSigGen0->option=1;
2767 pChan->spsSigGen0->enabled=1;
2768 pChan->spsSigGen0->discounterl=0;
2769 pChan->smode=SMODE_CTCSS;
2770 pChan->smodetimer=pChan->smodetime;
2772 else if(pChan->txcodedefaultsmode==SMODE_NULL||pChan->b.txCtcssInhibit)
2774 TRACEC(1,("txPtt Encode txcodedefaultsmode==SMODE_NULL\n"));
2778 printf ("ERROR: txPttIn=%i NOT HANDLED PROPERLY.\n",pChan->txPttIn);
2779 TRACEC(1,("ERROR: txPttIn=%i NOT HANDLED PROPERLY.\n",pChan->txPttIn));
2782 pChan->txState = CHAN_TXSTATE_ACTIVE;
2785 pChan->txsettletimer=pChan->txsettletime;
2787 if(pChan->spsTxOutA)pChan->spsTxOutA->enabled=1;
2788 if(pChan->spsTxOutB)pChan->spsTxOutB->enabled=1;
2789 if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->enabled=1;
2790 if(pChan->txfreq)pChan->b.reprog=1;
2791 TRACEC(1,("PmrRx() TxOn\n"));
2793 else if(pChan->txPttIn && pChan->txState==CHAN_TXSTATE_ACTIVE)
2795 // pChan->smode=SMODE_CTCSS;
2796 pChan->smodetimer=pChan->smodetime;
2798 else if(!pChan->txPttIn && pChan->txState==CHAN_TXSTATE_ACTIVE)
2800 TRACEC(1,("txPttIn==0 from CHAN_TXSTATE_ACTIVE\n"));
2801 if(pChan->smode==SMODE_CTCSS && !pChan->b.txCtcssInhibit)
2803 if( pChan->txTocType==TOC_NONE || !pChan->b.ctcssTxEnable )
2805 TRACEC(1,("Tx Off Immediate.\n"));
2806 pChan->spsSigGen0->option=3;
2807 pChan->txBufferClear=3;
2808 pChan->txState=CHAN_TXSTATE_FINISHING;
2810 else if(pChan->txTocType==TOC_NOTONE)
2812 pChan->txState=CHAN_TXSTATE_TOC;
2813 pChan->txHangTime=TOC_NOTONE_TIME/MS_PER_FRAME;
2814 pChan->spsSigGen0->option=3;
2815 TRACEC(1,("Tx Turn Off No Tone Start.\n"));
2819 pChan->txState=CHAN_TXSTATE_TOC;
2820 pChan->txHangTime=0;
2821 pChan->spsSigGen0->option=2;
2822 TRACEC(1,("Tx Turn Off Phase Shift Start.\n"));
2827 pChan->txBufferClear=3;
2828 pChan->txState=CHAN_TXSTATE_FINISHING;
2829 TRACEC(1,("Tx Off No SMODE to Finish.\n"));
2832 else if(pChan->txState==CHAN_TXSTATE_TOC)
2834 if( pChan->txPttIn && pChan->smode==SMODE_CTCSS )
2836 TRACEC(1,("Tx Key During HangTime\n"));
2837 pChan->txState = CHAN_TXSTATE_ACTIVE;
2838 pChan->spsSigGen0->option=1;
2839 pChan->spsSigGen0->enabled=1;
2840 pChan->spsSigGen0->discounterl=0;
2843 else if(pChan->txHangTime)
2845 if(--pChan->txHangTime==0)pChan->txState=CHAN_TXSTATE_FINISHING;
2847 else if(pChan->txHangTime<=0 && pChan->spsSigGen0->state==0)
2849 pChan->txBufferClear=3;
2850 pChan->txState=CHAN_TXSTATE_FINISHING;
2851 TRACEC(1,("Tx Off TOC.\n"));
2854 else if(pChan->txState==CHAN_TXSTATE_FINISHING)
2856 if(--pChan->txBufferClear<=0)
2857 pChan->txState=CHAN_TXSTATE_COMPLETE;
2859 else if(pChan->txState==CHAN_TXSTATE_COMPLETE)
2863 } // end of if SMODE==LSD
2868 pChan->spsSigGen0->option=3;
2869 pChan->txState=CHAN_TXSTATE_IDLE;
2870 if(pChan->spsTxLsdLpf)pChan->spsTxLsdLpf->option=3;
2871 if(pChan->spsTxOutA)pChan->spsTxOutA->option=3;
2872 if(pChan->spsTxOutB)pChan->spsTxOutB->option=3;
2873 if(pChan->rxfreq||pChan->txfreq)pChan->b.reprog=1;
2874 TRACEC(1,("Tx Off hit.\n"));
2883 if(pChan->txsettletimer && pChan->txPttHid )
2885 pChan->txsettletimer-=MS_PER_FRAME;
2886 if(pChan->txsettletimer<0)pChan->txsettletimer=0;
2889 // enable this after we know everything else is working
2890 if( pChan->txCpuSaver &&
2891 !pChan->txPttIn && !pChan->txPttOut &&
2892 pChan->txState==CHAN_TXSTATE_IDLE &&
2893 !pChan->dd.b.doitnow
2896 if(!pChan->b.txhalted)
2898 pChan->b.txhalted=1;
2899 TRACEC(1,("PmrRx() tx sps halted\n"));
2902 else if(pChan->b.txhalted)
2904 pChan->dd.b.doitnow=1;
2905 pChan->b.txhalted=0;
2906 TRACEC(1,("PmrRx() tx sps un-halted\n"));
2909 if(pChan->b.txhalted)return(1);
2911 if(pChan->b.startSpecialTone)
2913 pChan->b.startSpecialTone=0;
2914 pChan->spsSigGen1->option=1;
2915 pChan->spsSigGen1->enabled=1;
2916 pChan->b.doingSpecialTone=1;
2918 else if(pChan->b.stopSpecialTone)
2920 pChan->b.stopSpecialTone=0;
2921 pChan->spsSigGen1->option=0;
2922 pChan->b.doingSpecialTone=0;
2923 pChan->spsSigGen1->enabled=0;
2925 else if(pChan->b.doingSpecialTone)
2927 pChan->spsSigGen1->sink=outputtx;
2928 pChan->spsSigGen1->sigProc(pChan->spsSigGen1);
2929 for(i=0;i<(pChan->nSamplesTx*2*6);i+=2)outputtx[i+1]=outputtx[i];
2933 if(pChan->spsSigGen0 && pChan->spsSigGen0->enabled )
2935 pChan->spsSigGen0->sigProc(pChan->spsSigGen0);
2938 if(pChan->spsSigGen1 && pChan->spsSigGen1->enabled)
2940 pChan->spsSigGen1->sigProc(pChan->spsSigGen1);
2944 pChan->spsLsdGen->sigProc(pChan->spsLsdGen); // maw sph ???
2947 // Do Low Speed Data Low Pass Filter
2948 pChan->spsTxLsdLpf->sigProc(pChan->spsTxLsdLpf);
2951 pmr_sps=pChan->spsTx;
2953 // get tx data from de-drift process
2955 pChan->dd.ptr=pChan->pTxBase;
2959 if(!pChan->spsSigGen1->enabled)
2961 pmr_sps->source=pChan->pTxBase;
2963 else input=pmr_sps->source;
2967 if(pChan->spsTxOutA)pChan->spsTxOutA->sink=outputtx;
2968 if(pChan->spsTxOutB)pChan->spsTxOutB->sink=outputtx;
2972 while(pmr_sps!=NULL && pmr_sps!=0)
2974 //TRACEF(1,("PmrTx() sps %i\n",i++));
2975 pmr_sps->sigProc(pmr_sps);
2976 pmr_sps = (t_pmr_sps *)(pmr_sps->nextSps);
2979 //TRACEF(1,("PmrTx() - outputs \n"));
2980 if(pChan->txMixA==TX_OUT_OFF || !pChan->txPttOut){
2981 for(i=0;i<pChan->nSamplesTx*2*6;i+=2)outputtx[i]=0;
2984 if(pChan->txMixB==TX_OUT_OFF || !pChan->txPttOut ){
2985 for(i=0;i<pChan->nSamplesTx*2*6;i+=2)outputtx[i+1]=0;
2989 if( pChan->b.radioactive && pChan->b.pptp_p1!=pChan->txPttOut)
2991 pChan->b.pptp_p1=pChan->txPttOut;
2992 pptp_write(0,pChan->b.pptp_p1);
2996 #if XPMR_DEBUG0 == 1
2997 // TRACEF(1,("PmrRx() - debug outputs \n"));
2998 if(pChan->b.rxCapture){
2999 for(i=0;i<pChan->nSamplesRx;i++)
3001 pChan->pRxDemod[i]=input[i*2*6];
3002 pChan->pTstTxOut[i]=outputtx[i*2*6+0]; // txa
3003 //pChan->pTstTxOut[i]=outputtx[i*2*6+1]; // txb
3004 TSCOPE((RX_NOISE_TRIG, pChan->sdbg, i, (pChan->rxCarrierDetect*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
3005 TSCOPE((RX_CTCSS_DECODE, pChan->sdbg, i, pChan->rxCtcss->decode*(M_Q14/CTCSS_NUM_CODES)));
3006 TSCOPE((RX_SMODE, pChan->sdbg, i, pChan->smode*(XPMR_TRACE_AMP/4)));
3007 TSCOPE((TX_PTT_IN, pChan->sdbg, i, (pChan->txPttIn*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
3008 TSCOPE((TX_PTT_OUT, pChan->sdbg, i, (pChan->txPttOut*XPMR_TRACE_AMP)-XPMR_TRACE_AMP/2));
3009 TSCOPE((TX_DEDRIFT_LEAD, pChan->sdbg, i, pChan->dd.lead*8));
3010 TSCOPE((TX_DEDRIFT_ERR, pChan->sdbg, i, pChan->dd.err*16));
3011 TSCOPE((TX_DEDRIFT_FACTOR, pChan->sdbg, i, pChan->dd.factor*16));
3012 TSCOPE((TX_DEDRIFT_DRIFT, pChan->sdbg, i, pChan->dd.drift*16));
3017 strace2(pChan->sdbg);
3018 TRACEC(5,("PmrRx() return cd=%i smode=%i txPttIn=%i txPttOut=%i \n",pChan->rxCarrierDetect,pChan->smode,pChan->txPttIn,pChan->txPttOut));
3022 parallel binary programming of an RF Transceiver*/
3024 void ppbinout (u8 chan)
3030 ppdrvdev = open("/dev/ppdrv_device", 0);
3034 ast_log(LOG_ERROR, "open /dev/ppdrv_ppdrvdev returned %i\n",ppdrvdev);
3039 if(chan&0x01)i|=BIN_PROG_0;
3040 if(chan&0x02)i|=BIN_PROG_1;
3041 if(chan&0x04)i|=BIN_PROG_2;
3042 if(chan&0x08)i|=BIN_PROG_3;
3044 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3045 //ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3046 //ioctl(ppdrvdev, PPDRV_IOC_PINSET, i );
3047 ioctl(ppdrvdev, PPDRV_IOC_PINSET, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0);
3048 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, i );
3050 // ioctl(ppdrvdev, PPDRV_IOC_PINSET, BIN_PROG_3|BIN_PROG_2|BIN_PROG_1|BIN_PROG_0 );
3051 ast_log(LOG_NOTICE, "mask=%i 0x%x\n",i,i);
3055 SPI Programming of an RF Transceiver
3056 need to add permissions check and mutex
3059 need to add permissions check and mutex
3061 void ppspiout (u32 spidata)
3064 static char firstrun=0;
3070 ast_log(LOG_ERROR, "no parallel port permission ppdrvdev %i\n",ppdrvdev);
3074 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3075 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3080 for(ii=0;ii<PP_BIT_TIME*200;ii++);
3084 for(ii=0;ii<PP_BIT_TIME*4;ii++);
3087 bitselect=0x00080000;
3089 for(i=0;i<(PP_REG_LEN-12);i++)
3091 if((bitselect&spidata))
3092 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_DATA );
3094 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_DATA );
3096 for(ii=0;ii<PP_BIT_TIME;ii++);
3098 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_CLK );
3099 for(ii=0;ii<PP_BIT_TIME;ii++);
3100 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK );
3101 for(ii=0;ii<PP_BIT_TIME;ii++);
3103 bitselect=(bitselect>>1);
3105 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA );
3106 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_ENABLE );
3107 for(ii=0;ii<PP_BIT_TIME;ii++);
3108 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_ENABLE );
3113 now assumes calling thread secures permissions
3114 could set up a separate thread to program the radio? yuck!
3117 void progdtx(t_pmr_chan *pChan)
3120 //static u32 progcount=0;
3129 TRACEC(1,("\nprogdtx() %i %i %i\n",pChan->rxfreq,pChan->txfreq,0));
3132 ppdrvdev = open("/dev/ppdrv_device", 0);
3136 ast_log(LOG_ERROR, "open /dev/ppdrv_ppdrvdev returned %i\n",ppdrvdev);
3140 if(pChan->rxfreq>200000000)
3153 shiftreg=(reffreq/stepfreq)<<1;
3154 shiftreg=shiftreg|0x00000001;
3159 synthfreq=pChan->txfreq;
3161 synthfreq=pChan->rxfreq-rxiffreq;
3163 shiftreg=(synthfreq/stepfreq)<<1;
3164 tmp=(shiftreg&0xFFFFFF80)<<1;
3165 shiftreg=tmp+(shiftreg&0x0000007F);
3169 ioctl(ppdrvdev, PPDRV_IOC_PINMODE_OUT, DTX_CLK | DTX_DATA | DTX_ENABLE | DTX_TXPWR | DTX_TX );
3170 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_CLK | DTX_DATA | DTX_ENABLE );
3174 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_TXPWR );
3175 ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_TX );
3176 if(pChan->txpower && 0) ioctl(ppdrvdev, PPDRV_IOC_PINSET, DTX_TXPWR );
3180 ioctl(ppdrvdev, PPDRV_IOC_PINCLEAR, DTX_TX | DTX_TXPWR );
3186 reconciles clock differences between the usb adapter and
3187 asterisk's frame rate clock
3188 take out all accumulated drift error on these events:
3189 before transmitter on
3190 when ptt release from mobile units detected
3192 void dedrift(t_pmr_chan *pChan)
3194 TRACEC(5,("dedrift()\n"));
3196 if(pChan->dd.option==9)
3198 TRACEF(1,("dedrift(9)\n"));
3199 pChan->dd.framesize=DDB_FRAME_SIZE;
3200 pChan->dd.frames=DDB_FRAMES_IN_BUFF;
3201 pChan->dd.buffersize = pChan->dd.frames * pChan->dd.framesize;
3202 pChan->dd.buff=calloc(DDB_FRAME_SIZE*DDB_FRAMES_IN_BUFF,2);
3203 pChan->dd.modulus=DDB_ERR_MODULUS;
3204 pChan->dd.inputindex=0;
3205 pChan->dd.outputindex=0;
3206 pChan->dd.skew = pChan->dd.lead=0;
3209 pChan->dd.debugcnt=0;
3210 pChan->dd.lock=pChan->dd.b.txlock=pChan->dd.b.rxlock=0;
3211 pChan->dd.initcnt=2;
3212 pChan->dd.timer=10000/20;
3214 pChan->dd.factor=pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3215 pChan->dd.txframecnt=pChan->dd.rxframecnt=0;
3216 // clear the buffer too!
3219 else if(pChan->dd.option==8)
3221 free(pChan->dd.buff);
3223 pChan->dd.b.txlock=pChan->dd.b.rxlock=0;
3226 else if(pChan->dd.initcnt==0)
3228 const i32 a0 = 26231;
3229 const i32 a1 = 26231;
3230 const i32 b0 = 32768;
3231 const i32 b1 = -32358;
3238 inputindex = pChan->dd.inputindex;
3239 pChan->dd.skew = pChan->dd.txframecnt-pChan->dd.rxframecnt;
3240 pChan->dd.rxframecnt++;
3242 // pull data from buffer
3243 if( (pChan->dd.outputindex + pChan->dd.framesize) > pChan->dd.buffersize )
3247 dofirst = pChan->dd.buffersize - pChan->dd.outputindex;
3248 donext = pChan->dd.framesize - dofirst;
3249 vptr = (void*)(pChan->dd.ptr);
3250 memcpy(vptr,(void*)(pChan->dd.buff + pChan->dd.outputindex),dofirst*2);
3251 vptr=(void*)(pChan->dd.ptr + dofirst);
3252 memcpy(vptr,(void*)(pChan->dd.buff),donext*2);
3256 memcpy(pChan->dd.ptr,(void*)(pChan->dd.buff + pChan->dd.outputindex),pChan->dd.framesize*2);
3259 // compute clock error and correction factor
3260 if(pChan->dd.outputindex > inputindex)
3262 pChan->dd.lead = (inputindex + pChan->dd.buffersize) - pChan->dd.outputindex;
3266 pChan->dd.lead = inputindex - pChan->dd.outputindex;
3268 pChan->dd.err = pChan->dd.lead - (pChan->dd.buffersize/2);
3270 // WinFilter, IIR Fs=50, Fc=0.1
3271 pChan->dd.x1 = pChan->dd.x0;
3272 pChan->dd.y1 = pChan->dd.y0;
3273 pChan->dd.x0 = pChan->dd.err;
3274 pChan->dd.y0 = a0 * pChan->dd.x0;
3275 pChan->dd.y0 += (a1 * pChan->dd.x1 - (b1 * pChan->dd.y1));
3277 accum = pChan->dd.y0/dg;
3279 pChan->dd.factor=accum;
3283 // event sync'd correction
3284 if(pChan->dd.b.doitnow)
3286 pChan->dd.b.doitnow=0;
3287 indextweak=pChan->dd.factor;
3288 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3289 pChan->dd.timer=20000/MS_PER_FRAME;
3291 // coarse lead adjustment if really far out of range
3292 else if( pChan->dd.lead >= pChan->dd.framesize*(DDB_FRAMES_IN_BUFF-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);
3297 else if(pChan->dd.lead <= pChan->dd.framesize*2 )
3299 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3300 indextweak -= (pChan->dd.framesize*5/4);
3305 if(pChan->dd.timer>0)pChan->dd.timer--;
3306 if(pChan->dd.timer==0 && abs(pChan->dd.factor)>=16)
3308 indextweak=pChan->dd.factor;
3309 pChan->dd.factor = pChan->dd.x1 = pChan->dd.x0 = pChan->dd.y1 = pChan->dd.y0 = 0;
3310 pChan->dd.timer=20000/MS_PER_FRAME;
3314 #if XPMR_DEBUG0 == 1
3315 if(indextweak!=0)TRACEF(4,("%08i indextweak %+4i %+4i %+5i %5i %5i %5i %+4i\n",pChan->dd.rxframecnt, indextweak, pChan->dd.err, accum, inputindex, pChan->dd.outputindex, pChan->dd.lead, pChan->dd.skew));
3318 // set the output index based on lead and clock offset
3319 pChan->dd.outputindex = (pChan->dd.outputindex + pChan->dd.framesize + indextweak)%pChan->dd.buffersize;
3324 void dedrift_write(t_pmr_chan *pChan, i16 *src )
3328 TRACEF(5,("dedrift_write()\n"));
3329 vptr = pChan->dd.buff + pChan->dd.inputindex;
3330 memcpy(vptr, src, pChan->dd.framesize*2);
3331 pChan->dd.inputindex = (pChan->dd.inputindex + pChan->dd.framesize) % pChan->dd.buffersize;
3332 pChan->dd.txframecnt++;
3333 if(pChan->dd.initcnt!=0)pChan->dd.initcnt--;
3334 pChan->dd.accum+=pChan->dd.framesize;