mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-22 12:23:37 -05:00
Add files for command-line program ft2[.exe].
This commit is contained in:
parent
348e7c8ad5
commit
8a6cee7e26
154
lib/ft2/ft2.f90
Normal file
154
lib/ft2/ft2.f90
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
program ft2
|
||||||
|
|
||||||
|
use packjt77
|
||||||
|
include 'gcom1.f90'
|
||||||
|
integer ft2audio,ptt
|
||||||
|
logical allok
|
||||||
|
character*20 pttport
|
||||||
|
character*8 arg
|
||||||
|
integer*2 iwave2(30000)
|
||||||
|
|
||||||
|
allok=.true.
|
||||||
|
! Get home-station details
|
||||||
|
open(10,file='ft2.ini',status='old',err=1)
|
||||||
|
go to 2
|
||||||
|
1 print*,'Cannot open ft2.ini'
|
||||||
|
allok=.false.
|
||||||
|
2 read(10,*,err=3) mycall,mygrid,ndevin,ndevout,pttport,exch
|
||||||
|
go to 4
|
||||||
|
3 print*,'Error reading ft2.ini'
|
||||||
|
allok=.false.
|
||||||
|
4 if(index(pttport,'/').lt.1) read(pttport,*) nport
|
||||||
|
hiscall=' '
|
||||||
|
hiscall_next=' '
|
||||||
|
idevin=ndevin
|
||||||
|
idevout=ndevout
|
||||||
|
call padevsub(idevin,idevout)
|
||||||
|
if(idevin.ne.ndevin .or. idevout.ne.ndevout) allok=.false.
|
||||||
|
i1=ptt(nport,1,1,iptt)
|
||||||
|
if(i1.lt.0 .and. nport.ne.0) allok=.false.
|
||||||
|
if(.not.allok) then
|
||||||
|
write(*,"('Please fix setup error(s) and restart.')")
|
||||||
|
go to 999
|
||||||
|
endif
|
||||||
|
|
||||||
|
nright=1
|
||||||
|
iwrite=0
|
||||||
|
iwave=0
|
||||||
|
nwave=NTZ
|
||||||
|
nfsample=12000
|
||||||
|
ngo=1
|
||||||
|
npabuf=1280
|
||||||
|
ntxok=0
|
||||||
|
ntransmitting=0
|
||||||
|
tx_once=.false.
|
||||||
|
snrdb=99.0
|
||||||
|
txmsg='CQ K1JT FN20'
|
||||||
|
|
||||||
|
nargs=iargc()
|
||||||
|
if(nargs.eq.3) then
|
||||||
|
call getarg(1,txmsg)
|
||||||
|
call getarg(2,arg)
|
||||||
|
read(arg,*) f0
|
||||||
|
call getarg(3,arg)
|
||||||
|
read(arg,*) snrdb
|
||||||
|
nTxOK=1
|
||||||
|
tx_once=.true.
|
||||||
|
call ft2_iwave(txmsg,f0,snrdb,iwave)
|
||||||
|
endif
|
||||||
|
|
||||||
|
iwave2(1:23040)=iwave
|
||||||
|
iwave2(23041:30000)=0
|
||||||
|
nutc=0
|
||||||
|
nfqso=nint(f0)
|
||||||
|
|
||||||
|
call ft2_decode(nutc,nfqso,iwave2)
|
||||||
|
|
||||||
|
ierr=ft2audio(idevin,idevout,npabuf,nright,y1,y2,NRING,iwrite,itx, &
|
||||||
|
iwave,nwave,nfsample,nTxOK,nTransmitting,ngo)
|
||||||
|
if(ierr.ne.0) then
|
||||||
|
print*,'Error',ierr,' in JTaudio, you will only be able to work offline.'
|
||||||
|
else
|
||||||
|
write(*,1006)
|
||||||
|
1006 format('Audio streams terminated normally.')
|
||||||
|
endif
|
||||||
|
|
||||||
|
999 end program ft2
|
||||||
|
|
||||||
|
subroutine update(total_time,ic1,ic2)
|
||||||
|
|
||||||
|
real*8 total_time
|
||||||
|
integer ptt
|
||||||
|
logical transmitted
|
||||||
|
integer*2 id(30000),id2(30000)
|
||||||
|
include 'gcom1.f90'
|
||||||
|
data nt0/-1/,transmitted/.false./,snr/0.0/
|
||||||
|
save nt0,transmitted,snr
|
||||||
|
|
||||||
|
if(ic1.ne.0 .or. ic2.ne.0) then
|
||||||
|
if(ic1.eq.27 .and. ic2.eq.0) ngo=0 !ESC
|
||||||
|
if(nTxOK.eq.0 .and. ntransmitting.eq.0) then
|
||||||
|
nd=0
|
||||||
|
if(ic1.eq.0 .and. ic2.eq.59) nd=7 !F1
|
||||||
|
if(ic1.eq.0 .and. ic2.eq.60) nd=6 !F2
|
||||||
|
if(ic1.eq.0 .and. ic2.eq.61) nd=5 !F3
|
||||||
|
if(ic1.eq.0 .and. ic2.eq.62) nd=4 !F4
|
||||||
|
if(ic1.eq.0 .and. ic2.eq.63) nd=3 !F5
|
||||||
|
if(nd.gt.0) then
|
||||||
|
i1=ptt(nport,1,1,iptt)
|
||||||
|
ntxok=1
|
||||||
|
n=1000
|
||||||
|
nwave=NTZ
|
||||||
|
do i=1,nwave/nd
|
||||||
|
ib=i*nd
|
||||||
|
ia=ib-nd+1
|
||||||
|
iwave(ia:ib)=n
|
||||||
|
n=-n
|
||||||
|
enddo
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
if(ic1.eq.13 .and. ic2.eq.0) hiscall=hiscall_next
|
||||||
|
endif
|
||||||
|
|
||||||
|
if(ntransmitting.eq.1) transmitted=.true.
|
||||||
|
if(ntransmitting.eq.0) then
|
||||||
|
if(iptt.eq.1 .and. nport.gt.0) i1=ptt(nport,0,1,iptt)
|
||||||
|
if(tx_once .and. transmitted) stop
|
||||||
|
endif
|
||||||
|
|
||||||
|
nt=2*total_time
|
||||||
|
if(nt.gt.nt0 .or. ic1.ne.0 .or. ic2.ne.0) then
|
||||||
|
k=iwrite-6000
|
||||||
|
if(k.lt.1) k=k+NRING
|
||||||
|
sq=0.
|
||||||
|
do i=1,6000
|
||||||
|
k=k+1
|
||||||
|
if(k.gt.NRING) k=k-NRING
|
||||||
|
x=y1(k)
|
||||||
|
sq=sq + x*x
|
||||||
|
enddo
|
||||||
|
sigdb=0.
|
||||||
|
if(sq.gt.0.0) sigdb=db(sq/6000.0)
|
||||||
|
k=iwrite-30000
|
||||||
|
if(k.lt.1) k=k+NRING
|
||||||
|
do i=1,30000
|
||||||
|
k=k+1
|
||||||
|
if(k.gt.NRING) k=k-NRING
|
||||||
|
id(i)=y1(k)
|
||||||
|
enddo
|
||||||
|
nutc=0
|
||||||
|
nfqso=1500
|
||||||
|
call ft2_iwave(txmsg,1500.0,snr,id2) !###
|
||||||
|
snr=snr-1.0
|
||||||
|
call ft2_decode(nutc,nfqso,id2) !###
|
||||||
|
!### call ft2_decode(nutc,nfqso,id)
|
||||||
|
|
||||||
|
write(*,1010) nt,total_time,iwrite,itx,ntxok,ntransmitting,sigdb,snr
|
||||||
|
1010 format(i6,f9.3,4i6,f6.1,f6.0)
|
||||||
|
nt0=nt
|
||||||
|
max1=0
|
||||||
|
max2=0
|
||||||
|
endif
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine update
|
2
lib/ft2/ft2.ini
Normal file
2
lib/ft2/ft2.ini
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
K1JT FN20 1 5 0 NJ
|
||||||
|
MyCall MyGrid AudioIn AudioOut PTTport Exch
|
277
lib/ft2/ft2_decode.f90
Normal file
277
lib/ft2/ft2_decode.f90
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
subroutine ft2_decode(nutc,nfqso,iwave)
|
||||||
|
|
||||||
|
use crc
|
||||||
|
use packjt77
|
||||||
|
include 'ft2_params.f90'
|
||||||
|
character message*37,c77*77
|
||||||
|
character*37 decodes(100)
|
||||||
|
character*120 data_dir
|
||||||
|
complex c2(0:NMAX/16-1) !Complex waveform
|
||||||
|
complex cb(0:NMAX/16-1)
|
||||||
|
complex cd(0:144*10-1) !Complex waveform
|
||||||
|
complex c1(0:9),c0(0:9)
|
||||||
|
complex ccor(0:1,144)
|
||||||
|
complex csum,cterm,cc0,cc1,csync1
|
||||||
|
real*8 fMHz
|
||||||
|
|
||||||
|
real a(5)
|
||||||
|
real rxdata(128),llr(128) !Soft symbols
|
||||||
|
real llr2(128)
|
||||||
|
real sbits(144),sbits1(144),sbits3(144)
|
||||||
|
real ps(0:8191),psbest(0:8191)
|
||||||
|
real candidate(3,100)
|
||||||
|
real savg(NH1)
|
||||||
|
integer*2 iwave(NMAX) !Generated full-length waveform
|
||||||
|
integer*1 message77(77),apmask(128),cw(128)
|
||||||
|
integer*1 hbits(144),hbits1(144),hbits3(144)
|
||||||
|
integer*1 s16(16)
|
||||||
|
logical unpk77_success
|
||||||
|
data s16/0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0/
|
||||||
|
|
||||||
|
fs=12000.0/NDOWN !Sample rate
|
||||||
|
dt=1/fs !Sample interval after downsample (s)
|
||||||
|
tt=NSPS*dt !Duration of "itone" symbols (s)
|
||||||
|
baud=1.0/tt !Keying rate for "itone" symbols (baud)
|
||||||
|
txt=NZ*dt !Transmission length (s)
|
||||||
|
twopi=8.0*atan(1.0)
|
||||||
|
h=0.8 !h=0.8 seems to be optimum for AWGN sensitivity (not for fading)
|
||||||
|
|
||||||
|
dphi=twopi/2*baud*h*dt*16 ! dt*16 is samp interval after downsample
|
||||||
|
dphi0=-1*dphi
|
||||||
|
dphi1=+1*dphi
|
||||||
|
phi0=0.0
|
||||||
|
phi1=0.0
|
||||||
|
do i=0,9
|
||||||
|
c1(i)=cmplx(cos(phi1),sin(phi1))
|
||||||
|
c0(i)=cmplx(cos(phi0),sin(phi0))
|
||||||
|
phi1=mod(phi1+dphi1,twopi)
|
||||||
|
phi0=mod(phi0+dphi0,twopi)
|
||||||
|
enddo
|
||||||
|
the=twopi*h/2.0
|
||||||
|
cc1=cmplx(cos(the),-sin(the))
|
||||||
|
cc0=cmplx(cos(the),sin(the))
|
||||||
|
|
||||||
|
data_dir="."
|
||||||
|
fMHz=7.074
|
||||||
|
ncoh=1
|
||||||
|
candidate=0.0
|
||||||
|
ncand=0
|
||||||
|
fa=375.0
|
||||||
|
fb=3000.0
|
||||||
|
syncmin=0.2
|
||||||
|
maxcand=100
|
||||||
|
nfqso=-1
|
||||||
|
call getcandidates2(iwave,fa,fb,maxcand,savg,candidate,ncand)
|
||||||
|
ndecodes=0
|
||||||
|
do icand=1,ncand
|
||||||
|
f0=candidate(1,icand)
|
||||||
|
! print*,'A',ncand,f0
|
||||||
|
xsnr=1.0
|
||||||
|
if( f0.le.375.0 .or. f0.ge.(5000.0-375.0) ) cycle
|
||||||
|
call ft2_downsample(iwave,f0,c2) ! downsample from 160s/Symbol to 10s/Symbol
|
||||||
|
! 750 samples/second here
|
||||||
|
ibest=-1
|
||||||
|
sybest=-99.
|
||||||
|
dfbest=-1.
|
||||||
|
!### do if=-15,+15
|
||||||
|
do if=-30,30
|
||||||
|
df=if
|
||||||
|
a=0.
|
||||||
|
a(1)=-df
|
||||||
|
call twkfreq1(c2,NMAX/16,fs,a,cb)
|
||||||
|
do is=0,374
|
||||||
|
csync1=0.
|
||||||
|
cterm=1
|
||||||
|
do ib=1,16
|
||||||
|
i1=(ib-1)*10+is
|
||||||
|
i2=i1+136*10
|
||||||
|
if(s16(ib).eq.1) then
|
||||||
|
csync1=csync1+sum(cb(i1:i1+9)*conjg(c1(0:9)))*cterm
|
||||||
|
cterm=cterm*cc1
|
||||||
|
else
|
||||||
|
csync1=csync1+sum(cb(i1:i1+9)*conjg(c0(0:9)))*cterm
|
||||||
|
cterm=cterm*cc0
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
! write(60,3001) if,is,abs(csync1)
|
||||||
|
!3001 format(2i6,f10.3)
|
||||||
|
if(abs(csync1).gt.sybest) then
|
||||||
|
ibest=is
|
||||||
|
sybest=abs(csync1)
|
||||||
|
dfbest=df
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
|
||||||
|
!dfbest=0.0
|
||||||
|
!ibest=187
|
||||||
|
a=0.
|
||||||
|
a(1)=-dfbest
|
||||||
|
call twkfreq1(c2,NMAX/16,fs,a,cb)
|
||||||
|
ib=ibest
|
||||||
|
cd=cb(ib:ib+144*10-1)
|
||||||
|
s2=sum(real(cd*conjg(cd)))/(10*144)
|
||||||
|
cd=cd/sqrt(s2)
|
||||||
|
do nseq=1,5
|
||||||
|
if( nseq.eq.1 ) then ! noncoherent single-symbol detection
|
||||||
|
sbits1=0.0
|
||||||
|
do ibit=1,144
|
||||||
|
ib=(ibit-1)*10
|
||||||
|
ccor(1,ibit)=sum(cd(ib:ib+9)*conjg(c1(0:9)))
|
||||||
|
ccor(0,ibit)=sum(cd(ib:ib+9)*conjg(c0(0:9)))
|
||||||
|
sbits1(ibit)=abs(ccor(1,ibit))-abs(ccor(0,ibit))
|
||||||
|
hbits1(ibit)=0
|
||||||
|
if(sbits1(ibit).gt.0) hbits1(ibit)=1
|
||||||
|
enddo
|
||||||
|
sbits=sbits1
|
||||||
|
hbits=hbits1
|
||||||
|
sbits3=sbits1
|
||||||
|
hbits3=hbits1
|
||||||
|
elseif( nseq.ge.2 ) then
|
||||||
|
nbit=2*nseq-1
|
||||||
|
numseq=2**(nbit)
|
||||||
|
ps=0
|
||||||
|
do ibit=nbit/2+1,144-nbit/2
|
||||||
|
ps=0.0
|
||||||
|
pmax=0.0
|
||||||
|
do iseq=0,numseq-1
|
||||||
|
csum=0.0
|
||||||
|
cterm=1.0
|
||||||
|
k=1
|
||||||
|
do i=nbit-1,0,-1
|
||||||
|
ibb=iand(iseq/(2**i),1)
|
||||||
|
csum=csum+ccor(ibb,ibit-(nbit/2+1)+k)*cterm
|
||||||
|
if(ibb.eq.0) cterm=cterm*cc0
|
||||||
|
if(ibb.eq.1) cterm=cterm*cc1
|
||||||
|
k=k+1
|
||||||
|
enddo
|
||||||
|
ps(iseq)=abs(csum)
|
||||||
|
if( ps(iseq) .gt. pmax ) then
|
||||||
|
pmax=ps(iseq)
|
||||||
|
ibflag=1
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
if( ibflag .eq. 1 ) then
|
||||||
|
psbest=ps
|
||||||
|
ibflag=0
|
||||||
|
endif
|
||||||
|
call getbitmetric(2**(nbit/2),psbest,numseq,sbits3(ibit))
|
||||||
|
hbits3(ibit)=0
|
||||||
|
if(sbits3(ibit).gt.0) hbits3(ibit)=1
|
||||||
|
enddo
|
||||||
|
sbits=sbits3
|
||||||
|
hbits=hbits3
|
||||||
|
endif
|
||||||
|
nsync_qual=count(hbits(1:16).eq.s16)
|
||||||
|
if(nsync_qual.lt.10) exit
|
||||||
|
rxdata=sbits(17:144)
|
||||||
|
rxav=sum(rxdata(1:128))/128.0
|
||||||
|
rx2av=sum(rxdata(1:128)*rxdata(1:128))/128.0
|
||||||
|
rxsig=sqrt(rx2av-rxav*rxav)
|
||||||
|
rxdata=rxdata/rxsig
|
||||||
|
sigma=0.80
|
||||||
|
llr(1:128)=2*rxdata/(sigma*sigma)
|
||||||
|
apmask=0
|
||||||
|
max_iterations=40
|
||||||
|
do ibias=0,0
|
||||||
|
llr2=llr
|
||||||
|
if(ibias.eq.1) llr2=llr+0.4
|
||||||
|
if(ibias.eq.2) llr2=llr-0.4
|
||||||
|
call bpdecode128_90(llr2,apmask,max_iterations,message77,cw,nharderror,niterations)
|
||||||
|
if(nharderror.ge.0) exit
|
||||||
|
enddo
|
||||||
|
nhardmin=-1
|
||||||
|
if(sum(message77).eq.0) cycle
|
||||||
|
if( nharderror.ge.0 ) then
|
||||||
|
write(c77,'(77i1)') message77(1:77)
|
||||||
|
call unpack77(c77,message,unpk77_success)
|
||||||
|
idupe=0
|
||||||
|
do i=1,ndecodes
|
||||||
|
if(decodes(i).eq.message) idupe=1
|
||||||
|
enddo
|
||||||
|
if(idupe.eq.1) goto 888
|
||||||
|
ndecodes=ndecodes+1
|
||||||
|
decodes(ndecodes)=message
|
||||||
|
nsnr=nint(xsnr)
|
||||||
|
freq=f0+dfbest
|
||||||
|
write(*,1212) nutc,nsnr,ibest/750.0,nint(freq),message, &
|
||||||
|
nseq,nharderror,nhardmin
|
||||||
|
1212 format(i4.4,i4,f6.2,i6,2x,a37,3i5)
|
||||||
|
goto 888
|
||||||
|
endif
|
||||||
|
enddo ! nseq
|
||||||
|
888 continue
|
||||||
|
enddo !candidate list
|
||||||
|
|
||||||
|
end subroutine ft2_decode
|
||||||
|
|
||||||
|
subroutine getbitmetric(ib,ps,ns,xmet)
|
||||||
|
real ps(0:ns-1)
|
||||||
|
xm1=0
|
||||||
|
xm0=0
|
||||||
|
do i=0,ns-1
|
||||||
|
if( iand(i/ib,1) .eq. 1 .and. ps(i) .gt. xm1 ) xm1=ps(i)
|
||||||
|
if( iand(i/ib,1) .eq. 0 .and. ps(i) .gt. xm0 ) xm0=ps(i)
|
||||||
|
enddo
|
||||||
|
xmet=xm1-xm0
|
||||||
|
return
|
||||||
|
end subroutine getbitmetric
|
||||||
|
|
||||||
|
subroutine downsample2(ci,f0,co)
|
||||||
|
parameter(NI=144*160,NH=NI/2,NO=NI/16) ! downsample from 200 samples per symbol to 10
|
||||||
|
complex ci(0:NI-1),ct(0:NI-1)
|
||||||
|
complex co(0:NO-1)
|
||||||
|
fs=12000.0
|
||||||
|
df=fs/NI
|
||||||
|
ct=ci
|
||||||
|
call four2a(ct,NI,1,-1,1) !c2c FFT to freq domain
|
||||||
|
i0=nint(f0/df)
|
||||||
|
ct=cshift(ct,i0)
|
||||||
|
co=0.0
|
||||||
|
co(0)=ct(0)
|
||||||
|
b=8.0
|
||||||
|
do i=1,NO/2
|
||||||
|
arg=(i*df/b)**2
|
||||||
|
filt=exp(-arg)
|
||||||
|
co(i)=ct(i)*filt
|
||||||
|
co(NO-i)=ct(NI-i)*filt
|
||||||
|
enddo
|
||||||
|
co=co/NO
|
||||||
|
call four2a(co,NO,1,1,1) !c2c FFT back to time domain
|
||||||
|
return
|
||||||
|
end subroutine downsample2
|
||||||
|
|
||||||
|
subroutine ft2_downsample(iwave,f0,c)
|
||||||
|
|
||||||
|
! Input: i*2 data in iwave() at sample rate 12000 Hz
|
||||||
|
! Output: Complex data in c(), sampled at 1200 Hz
|
||||||
|
|
||||||
|
include 'ft2_params.f90'
|
||||||
|
parameter (NFFT2=NMAX/16)
|
||||||
|
integer*2 iwave(NMAX)
|
||||||
|
complex c(0:NMAX/16-1)
|
||||||
|
complex c1(0:NFFT2-1)
|
||||||
|
complex cx(0:NMAX/2)
|
||||||
|
real x(NMAX)
|
||||||
|
equivalence (x,cx)
|
||||||
|
|
||||||
|
BW=4.0*75
|
||||||
|
df=12000.0/NMAX
|
||||||
|
x=iwave
|
||||||
|
call four2a(x,NMAX,1,-1,0) !r2c FFT to freq domain
|
||||||
|
ibw=nint(BW/df)
|
||||||
|
i0=nint(f0/df)
|
||||||
|
c1=0.
|
||||||
|
c1(0)=cx(i0)
|
||||||
|
do i=1,NFFT2/2
|
||||||
|
arg=(i-1)*df/bw
|
||||||
|
win=exp(-arg*arg)
|
||||||
|
c1(i)=cx(i0+i)*win
|
||||||
|
c1(NFFT2-i)=cx(i0-i)*win
|
||||||
|
enddo
|
||||||
|
c1=c1/NFFT2
|
||||||
|
call four2a(c1,NFFT2,1,1,1) !c2c FFT back to time domain
|
||||||
|
c=c1(0:NMAX/16-1)
|
||||||
|
return
|
||||||
|
end subroutine ft2_downsample
|
||||||
|
|
66
lib/ft2/ft2_iwave.f90
Normal file
66
lib/ft2/ft2_iwave.f90
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
subroutine ft2_iwave(msg37,f0,snrdb,iwave)
|
||||||
|
|
||||||
|
! Generate waveform for experimental "FT2" mode
|
||||||
|
|
||||||
|
use packjt77
|
||||||
|
include 'ft2_params.f90' !Set various constants
|
||||||
|
parameter (NWAVE=NN*NSPS)
|
||||||
|
character msg37*37,msgsent37*37
|
||||||
|
real wave(NMAX)
|
||||||
|
integer itone(NN)
|
||||||
|
integer*2 iwave(NMAX) !Generated full-length waveform
|
||||||
|
|
||||||
|
twopi=8.0*atan(1.0)
|
||||||
|
fs=12000.0 !Sample rate (Hz)
|
||||||
|
dt=1.0/fs !Sample interval (s)
|
||||||
|
hmod=0.8 !Modulation index (MSK=0.5, FSK=1.0)
|
||||||
|
tt=NSPS*dt !Duration of symbols (s)
|
||||||
|
baud=1.0/tt !Keying rate (baud)
|
||||||
|
bw=1.5*baud !Occupied bandwidth (Hz)
|
||||||
|
txt=NZ*dt !Transmission length (s)
|
||||||
|
bandwidth_ratio=2500.0/(fs/2.0)
|
||||||
|
sig=sqrt(2*bandwidth_ratio) * 10.0**(0.05*snrdb)
|
||||||
|
if(snrdb.gt.90.0) sig=1.0
|
||||||
|
txt=NN*NSPS/12000.0
|
||||||
|
|
||||||
|
! Source-encode, then get itone():
|
||||||
|
itype=1
|
||||||
|
call genft2(msg37,0,msgsent37,itone,itype)
|
||||||
|
|
||||||
|
k=0
|
||||||
|
phi=0.0
|
||||||
|
do j=1,NN !Generate real waveform
|
||||||
|
dphi=twopi*(f0*dt+(hmod/2.0)*(2*itone(j)-1)/real(NSPS))
|
||||||
|
do i=1,NSPS
|
||||||
|
k=k+1
|
||||||
|
wave(k)=sig*sin(phi)
|
||||||
|
phi=mod(phi+dphi,twopi)
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
kz=k
|
||||||
|
|
||||||
|
peak=maxval(abs(wave(1:kz)))
|
||||||
|
! nslots=1
|
||||||
|
! if(width.gt.0.0) call filt8(f0,nslots,width,wave)
|
||||||
|
|
||||||
|
if(snrdb.lt.90) then
|
||||||
|
do i=1,NMAX !Add gaussian noise at specified SNR
|
||||||
|
xnoise=gran()
|
||||||
|
wave(i)=wave(i) + xnoise
|
||||||
|
enddo
|
||||||
|
endif
|
||||||
|
|
||||||
|
gain=1.0
|
||||||
|
if(snrdb.lt.90.0) then
|
||||||
|
wave=gain*wave
|
||||||
|
else
|
||||||
|
datpk=maxval(abs(wave))
|
||||||
|
fac=32767.0/datpk
|
||||||
|
wave=fac*wave
|
||||||
|
endif
|
||||||
|
|
||||||
|
if(any(abs(wave).gt.32767.0)) print*,"Warning - data will be clipped."
|
||||||
|
iwave(1:kz)=nint(wave(1:kz))
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine ft2_iwave
|
12
lib/ft2/ft2_params.f90
Normal file
12
lib/ft2/ft2_params.f90
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
! LDPC (128,90) code
|
||||||
|
parameter (KK=90) !Information bits (77 + CRC13)
|
||||||
|
parameter (ND=128) !Data symbols
|
||||||
|
parameter (NS=16) !Sync symbols (2x8)
|
||||||
|
parameter (NN=NS+ND) !Total channel symbols (144)
|
||||||
|
parameter (NSPS=160) !Samples per symbol at 12000 S/s
|
||||||
|
parameter (NZ=NSPS*NN) !Samples in full 1.92 s waveform (23040)
|
||||||
|
parameter (NMAX=30000) !Samples in iwave (2.5*12000)
|
||||||
|
parameter (NFFT1=400, NH1=NFFT1/2) !Length of FFTs for symbol spectra
|
||||||
|
parameter (NSTEP=NSPS/4) !Rough time-sync step size
|
||||||
|
parameter (NHSYM=NMAX/NSTEP-3) !Number of symbol spectra (1/4-sym steps)
|
||||||
|
parameter (NDOWN=16) !Downsample factor
|
330
lib/ft2/ft2audio.c
Normal file
330
lib/ft2/ft2audio.c
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "portaudio.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int iaa;
|
||||||
|
int icc;
|
||||||
|
double total_time=0.0;
|
||||||
|
|
||||||
|
// Definition of structure pointing to the audio data
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int *iwrite;
|
||||||
|
int *itx;
|
||||||
|
int *TxOK;
|
||||||
|
int *Transmitting;
|
||||||
|
int *nwave;
|
||||||
|
int *nright;
|
||||||
|
int nbuflen;
|
||||||
|
int nfs;
|
||||||
|
short *y1;
|
||||||
|
short *y2;
|
||||||
|
short *iwave;
|
||||||
|
} paTestData;
|
||||||
|
|
||||||
|
// Input callback routine:
|
||||||
|
static int
|
||||||
|
SoundIn( void *inputBuffer, void *outputBuffer,
|
||||||
|
unsigned long framesPerBuffer,
|
||||||
|
const PaStreamCallbackTimeInfo* timeInfo,
|
||||||
|
PaStreamCallbackFlags statusFlags,
|
||||||
|
void *userData )
|
||||||
|
{
|
||||||
|
paTestData *data = (paTestData*)userData;
|
||||||
|
short *in = (short*)inputBuffer;
|
||||||
|
unsigned int i;
|
||||||
|
static int ia=0;
|
||||||
|
|
||||||
|
if(*data->Transmitting) return 0;
|
||||||
|
|
||||||
|
if(statusFlags!=0) printf("Status flags %d\n",(int)statusFlags);
|
||||||
|
|
||||||
|
if((statusFlags&1) == 0) {
|
||||||
|
//increment buffer pointers only if data available
|
||||||
|
ia=*data->iwrite;
|
||||||
|
if(*data->nright==0) { //Use left channel for input
|
||||||
|
for(i=0; i<framesPerBuffer; i++) {
|
||||||
|
data->y1[ia] = (*in++);
|
||||||
|
data->y2[ia] = (*in++);
|
||||||
|
ia++;
|
||||||
|
}
|
||||||
|
} else { //Use right channel
|
||||||
|
for(i=0; i<framesPerBuffer; i++) {
|
||||||
|
data->y2[ia] = (*in++);
|
||||||
|
data->y1[ia] = (*in++);
|
||||||
|
ia++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ia >= data->nbuflen) ia=0; //Wrap buffer pointer if necessary
|
||||||
|
*data->iwrite = ia; //Save buffer pointer
|
||||||
|
iaa=ia;
|
||||||
|
total_time += (double)framesPerBuffer/12000.0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output callback routine:
|
||||||
|
static int
|
||||||
|
SoundOut( void *inputBuffer, void *outputBuffer,
|
||||||
|
unsigned long framesPerBuffer,
|
||||||
|
const PaStreamCallbackTimeInfo* timeInfo,
|
||||||
|
PaStreamCallbackFlags statusFlags,
|
||||||
|
void *userData )
|
||||||
|
{
|
||||||
|
paTestData *data = (paTestData*)userData;
|
||||||
|
short *wptr = (short*)outputBuffer;
|
||||||
|
unsigned int i,n;
|
||||||
|
static short int n2;
|
||||||
|
static int ic=0;
|
||||||
|
static int TxOKz=0;
|
||||||
|
|
||||||
|
// printf("txOK: %d %d\n",TxOKz,*data->TxOK);
|
||||||
|
|
||||||
|
if(*data->TxOK && (!TxOKz)) ic=0;
|
||||||
|
TxOKz=*data->TxOK;
|
||||||
|
*data->Transmitting=*data->TxOK;
|
||||||
|
|
||||||
|
if(*data->TxOK) {
|
||||||
|
for(i=0 ; i < framesPerBuffer; i++ ) {
|
||||||
|
n2=data->iwave[ic];
|
||||||
|
*wptr++ = n2; //left
|
||||||
|
*wptr++ = n2; //right
|
||||||
|
ic++;
|
||||||
|
|
||||||
|
if(ic >= *data->nwave) {
|
||||||
|
*data->TxOK = 0;
|
||||||
|
*data->Transmitting = 0;
|
||||||
|
*data->iwrite = 0; //Reset Rx buffer pointer to 0
|
||||||
|
ic=0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memset((void*)outputBuffer, 0, 2*sizeof(short)*framesPerBuffer);
|
||||||
|
}
|
||||||
|
*data->itx = icc; //Save buffer pointer
|
||||||
|
icc=ic;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
int ft2audio_(int *ndevin, int *ndevout, int *npabuf, int *nright,
|
||||||
|
short y1[], short y2[], int *nbuflen, int *iwrite,
|
||||||
|
int *itx, short iwave[], int *nwave, int *nfsample,
|
||||||
|
int *TxOK, int *Transmitting, int *ngo)
|
||||||
|
|
||||||
|
{
|
||||||
|
paTestData data;
|
||||||
|
PaStream *instream, *outstream;
|
||||||
|
PaStreamParameters inputParameters, outputParameters;
|
||||||
|
// PaStreamInfo *streamInfo;
|
||||||
|
|
||||||
|
int nfpb = *npabuf;
|
||||||
|
int nSampleRate = *nfsample;
|
||||||
|
int ndevice_in = *ndevin;
|
||||||
|
int ndevice_out = *ndevout;
|
||||||
|
double dSampleRate = (double) *nfsample;
|
||||||
|
PaError err_init, err_open_in, err_open_out, err_start_in, err_start_out;
|
||||||
|
PaError err = 0;
|
||||||
|
|
||||||
|
data.iwrite = iwrite;
|
||||||
|
data.itx = itx;
|
||||||
|
data.TxOK = TxOK;
|
||||||
|
data.Transmitting = Transmitting;
|
||||||
|
data.y1 = y1;
|
||||||
|
data.y2 = y2;
|
||||||
|
data.nbuflen = *nbuflen;
|
||||||
|
data.nright = nright;
|
||||||
|
data.nwave = nwave;
|
||||||
|
data.iwave = iwave;
|
||||||
|
data.nfs = nSampleRate;
|
||||||
|
|
||||||
|
err_init = Pa_Initialize(); // Initialize PortAudio
|
||||||
|
|
||||||
|
if(err_init) {
|
||||||
|
printf("Error initializing PortAudio.\n");
|
||||||
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_init),
|
||||||
|
err_init);
|
||||||
|
Pa_Terminate(); // I don't think we need this but...
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("Opening device %d for input, %d for output...\n",ndevice_in,ndevice_out);
|
||||||
|
|
||||||
|
inputParameters.device = ndevice_in;
|
||||||
|
inputParameters.channelCount = 2;
|
||||||
|
inputParameters.sampleFormat = paInt16;
|
||||||
|
inputParameters.suggestedLatency = 0.2;
|
||||||
|
inputParameters.hostApiSpecificStreamInfo = NULL;
|
||||||
|
|
||||||
|
// Test if this configuration actually works, so we do not run into an ugly assertion
|
||||||
|
err_open_in = Pa_IsFormatSupported(&inputParameters, NULL, dSampleRate);
|
||||||
|
|
||||||
|
if (err_open_in == 0) {
|
||||||
|
err_open_in = Pa_OpenStream(
|
||||||
|
&instream, //address of stream
|
||||||
|
&inputParameters,
|
||||||
|
NULL,
|
||||||
|
dSampleRate, //Sample rate
|
||||||
|
nfpb, //Frames per buffer
|
||||||
|
paNoFlag,
|
||||||
|
(PaStreamCallback *)SoundIn, //Callback routine
|
||||||
|
(void *)&data); //address of data structure
|
||||||
|
|
||||||
|
if(err_open_in) { // We should have no error here usually
|
||||||
|
printf("Error opening input audio stream:\n");
|
||||||
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_open_in), err_open_in);
|
||||||
|
|
||||||
|
err = 1;
|
||||||
|
} else {
|
||||||
|
// printf("Successfully opened audio input.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Error opening input audio stream.\n");
|
||||||
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_open_in), err_open_in);
|
||||||
|
|
||||||
|
err = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputParameters.device = ndevice_out;
|
||||||
|
outputParameters.channelCount = 2;
|
||||||
|
outputParameters.sampleFormat = paInt16;
|
||||||
|
outputParameters.suggestedLatency = 0.2;
|
||||||
|
outputParameters.hostApiSpecificStreamInfo = NULL;
|
||||||
|
|
||||||
|
// Test if this configuration actually works, so we do not run into an ugly assertion
|
||||||
|
err_open_out = Pa_IsFormatSupported(NULL, &outputParameters, dSampleRate);
|
||||||
|
|
||||||
|
if (err_open_out == 0) {
|
||||||
|
err_open_out = Pa_OpenStream(
|
||||||
|
&outstream, //address of stream
|
||||||
|
NULL,
|
||||||
|
&outputParameters,
|
||||||
|
dSampleRate, //Sample rate
|
||||||
|
nfpb, //Frames per buffer
|
||||||
|
paNoFlag,
|
||||||
|
(PaStreamCallback *)SoundOut, //Callback routine
|
||||||
|
(void *)&data); //address of data structure
|
||||||
|
|
||||||
|
if(err_open_out) { // We should have no error here usually
|
||||||
|
printf("Error opening output audio stream!\n");
|
||||||
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_open_out), err_open_out);
|
||||||
|
|
||||||
|
err += 2;
|
||||||
|
} else {
|
||||||
|
// printf("Successfully opened audio output.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Error opening output audio stream.\n");
|
||||||
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_open_out), err_open_out);
|
||||||
|
|
||||||
|
err += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there was no error in opening both streams start them
|
||||||
|
if (err == 0) {
|
||||||
|
err_start_in = Pa_StartStream(instream); //Start input stream
|
||||||
|
|
||||||
|
if(err_start_in) {
|
||||||
|
printf("Error starting input audio stream!\n");
|
||||||
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_start_in), err_start_in);
|
||||||
|
|
||||||
|
err += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_start_out = Pa_StartStream(outstream); //Start output stream
|
||||||
|
|
||||||
|
if(err_start_out) {
|
||||||
|
printf("Error starting output audio stream!\n");
|
||||||
|
printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_start_out), err_start_out);
|
||||||
|
|
||||||
|
err += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == 0) printf("Audio streams running normally.\n******************************************************************\n");
|
||||||
|
|
||||||
|
while( Pa_IsStreamActive(instream) && (*ngo != 0) && (err == 0) ) {
|
||||||
|
int ic1=0;
|
||||||
|
int ic2=0;
|
||||||
|
if(_kbhit()) ic1 = _getch();
|
||||||
|
if(_kbhit()) ic2 = _getch();
|
||||||
|
// if(ic1!=0 || ic2!=0) printf("%d %d %d\n",iaa,ic1,ic2);
|
||||||
|
update_(&total_time,&ic1,&ic2);
|
||||||
|
Pa_Sleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pa_AbortStream(instream); // Abort stream
|
||||||
|
Pa_CloseStream(instream); // Close stream, we're done.
|
||||||
|
Pa_AbortStream(outstream); // Abort stream
|
||||||
|
Pa_CloseStream(outstream); // Close stream, we're done.
|
||||||
|
|
||||||
|
Pa_Terminate();
|
||||||
|
|
||||||
|
return(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int padevsub_(int *idevin, int *idevout)
|
||||||
|
{
|
||||||
|
int numdev,ndefin,ndefout;
|
||||||
|
int nchin[101], nchout[101];
|
||||||
|
int i, devIdx;
|
||||||
|
int numDevices;
|
||||||
|
const PaDeviceInfo *pdi;
|
||||||
|
PaError err;
|
||||||
|
|
||||||
|
Pa_Initialize();
|
||||||
|
numDevices = Pa_GetDeviceCount();
|
||||||
|
numdev = numDevices;
|
||||||
|
|
||||||
|
if( numDevices < 0 ) {
|
||||||
|
err = numDevices;
|
||||||
|
Pa_Terminate();
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((devIdx = Pa_GetDefaultInputDevice()) > 0) {
|
||||||
|
ndefin = devIdx;
|
||||||
|
} else {
|
||||||
|
ndefin = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((devIdx = Pa_GetDefaultOutputDevice()) > 0) {
|
||||||
|
ndefout = devIdx;
|
||||||
|
} else {
|
||||||
|
ndefout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\nAudio Input Output Device Name\n");
|
||||||
|
printf("Device Channels Channels\n");
|
||||||
|
printf("------------------------------------------------------------------\n");
|
||||||
|
|
||||||
|
for( i=0; i < numDevices; i++ ) {
|
||||||
|
pdi = Pa_GetDeviceInfo(i);
|
||||||
|
// if(i == Pa_GetDefaultInputDevice()) ndefin = i;
|
||||||
|
// if(i == Pa_GetDefaultOutputDevice()) ndefout = i;
|
||||||
|
nchin[i]=pdi->maxInputChannels;
|
||||||
|
nchout[i]=pdi->maxOutputChannels;
|
||||||
|
printf(" %2d %2d %2d %s\n",i,nchin[i],nchout[i],pdi->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\nUser requested devices: Input = %2d Output = %2d\n",
|
||||||
|
*idevin,*idevout);
|
||||||
|
printf("Default devices: Input = %2d Output = %2d\n",
|
||||||
|
ndefin,ndefout);
|
||||||
|
if((*idevin<0) || (*idevin>=numdev)) *idevin=ndefin;
|
||||||
|
if((*idevout<0) || (*idevout>=numdev)) *idevout=ndefout;
|
||||||
|
if((*idevin==0) && (*idevout==0)) {
|
||||||
|
*idevin=ndefin;
|
||||||
|
*idevout=ndefout;
|
||||||
|
}
|
||||||
|
printf("Will open devices: Input = %2d Output = %2d\n",
|
||||||
|
*idevin,*idevout);
|
||||||
|
|
||||||
|
Pa_Terminate();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
6
lib/ft2/g4.cmd
Normal file
6
lib/ft2/g4.cmd
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
gcc -c ft2audio.c
|
||||||
|
gcc -c ptt.c
|
||||||
|
gfortran -c ../77bit/packjt77.f90
|
||||||
|
gfortran -c ../crc.f90
|
||||||
|
gfortran -o ft2 -fbounds-check -fno-second-underscore -Wall -Wno-conversion -Wno-character-truncation ft2.f90 ft2_iwave.f90 ft2_decode.f90 getcandidates2.f90 ft2audio.o ptt.o libwsjt_fort.a libwsjt_cxx.a libportaudio.a ../libfftw3f_win.a -lwinmm
|
||||||
|
rm *.o *.mod
|
30
lib/ft2/gcom1.f90
Normal file
30
lib/ft2/gcom1.f90
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
! Variable Purpose
|
||||||
|
!---------------------------------------------------------------------------
|
||||||
|
integer NRING !Length of Rx ring buffer
|
||||||
|
integer NTZ !Length of Tx waveform in samples
|
||||||
|
parameter(NRING=32768) !About 2.7 s at 12000 sam/sec
|
||||||
|
parameter(NTZ=23040) !144*160
|
||||||
|
parameter(NMAX=30000) !2.5*12000
|
||||||
|
real snrdb
|
||||||
|
integer ndevin !Device# for audio input
|
||||||
|
integer ndevout !Device# for audio output
|
||||||
|
integer iwrite !Pointer to Rx ring buffer
|
||||||
|
integer itx !Pointer to Tx buffer
|
||||||
|
integer ngo !Set to 0 to terminate audio streams
|
||||||
|
integer nTransmitting !Actually transmitting?
|
||||||
|
integer nTxOK !OK to transmit?
|
||||||
|
integer nport !COM port for PTT
|
||||||
|
logical tx_once !Transmit one message, then exit
|
||||||
|
integer*2 y1 !Ring buffer for audio channel 0
|
||||||
|
integer*2 y2 !Ring buffer for audio channel 1
|
||||||
|
integer*2 iwave !Data for Tx audio
|
||||||
|
character*6 mycall
|
||||||
|
character*6 hiscall
|
||||||
|
character*6 hiscall_next
|
||||||
|
character*4 mygrid
|
||||||
|
character*3 exch
|
||||||
|
character*37 txmsg
|
||||||
|
|
||||||
|
common/gcom1/snrdb,ndevin,ndevout,iwrite,itx,ngo,nTransmitting,nTxOK,nport, &
|
||||||
|
tx_once, y1(NRING),y2(NRING),iwave(NTZ),mycall,hiscall, &
|
||||||
|
hiscall_next,mygrid,exch,txmsg
|
86
lib/ft2/genft2.f90
Normal file
86
lib/ft2/genft2.f90
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
subroutine genft2(msg0,ichk,msgsent,i4tone,itype)
|
||||||
|
! s8 + 48bits + s8 + 80 bits = 144 bits (72ms message duration)
|
||||||
|
!
|
||||||
|
! Encode an MSK144 message
|
||||||
|
! Input:
|
||||||
|
! - msg0 requested message to be transmitted
|
||||||
|
! - ichk if ichk=1, return only msgsent
|
||||||
|
! if ichk.ge.10000, set imsg=ichk-10000 for short msg
|
||||||
|
! - msgsent message as it will be decoded
|
||||||
|
! - i4tone array of audio tone values, 0 or 1
|
||||||
|
! - itype message type
|
||||||
|
! 1 = 77 bit message
|
||||||
|
! 7 = 16 bit message "<Call_1 Call2> Rpt"
|
||||||
|
|
||||||
|
use iso_c_binding, only: c_loc,c_size_t
|
||||||
|
use packjt77
|
||||||
|
character*37 msg0
|
||||||
|
character*37 message !Message to be generated
|
||||||
|
character*37 msgsent !Message as it will be received
|
||||||
|
character*77 c77
|
||||||
|
integer*4 i4tone(144)
|
||||||
|
integer*1 codeword(128)
|
||||||
|
integer*1 msgbits(77)
|
||||||
|
integer*1 bitseq(144) !Tone #s, data and sync (values 0-1)
|
||||||
|
integer*1 s16(16)
|
||||||
|
real*8 xi(864),xq(864),pi,twopi
|
||||||
|
data s16/0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0/
|
||||||
|
equivalence (ihash,i1hash)
|
||||||
|
logical unpk77_success
|
||||||
|
|
||||||
|
nsym=128
|
||||||
|
pi=4.0*atan(1.0)
|
||||||
|
twopi=8.*atan(1.0)
|
||||||
|
|
||||||
|
message(1:37)=' '
|
||||||
|
itype=1
|
||||||
|
if(msg0(1:1).eq.'@') then !Generate a fixed tone
|
||||||
|
read(msg0(2:5),*,end=1,err=1) nfreq !at specified frequency
|
||||||
|
go to 2
|
||||||
|
1 nfreq=1000
|
||||||
|
2 i4tone(1)=nfreq
|
||||||
|
else
|
||||||
|
message=msg0
|
||||||
|
|
||||||
|
do i=1, 37
|
||||||
|
if(ichar(message(i:i)).eq.0) then
|
||||||
|
message(i:37)=' '
|
||||||
|
exit
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
do i=1,37 !Strip leading blanks
|
||||||
|
if(message(1:1).ne.' ') exit
|
||||||
|
message=message(i+1:)
|
||||||
|
enddo
|
||||||
|
|
||||||
|
if(message(1:1).eq.'<') then
|
||||||
|
i2=index(message,'>')
|
||||||
|
i1=0
|
||||||
|
if(i2.gt.0) i1=index(message(1:i2),' ')
|
||||||
|
if(i1.gt.0) then
|
||||||
|
call genmsk40(message,msgsent,ichk,i4tone,itype)
|
||||||
|
if(itype.lt.0) go to 999
|
||||||
|
i4tone(41)=-40
|
||||||
|
go to 999
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
i3=-1
|
||||||
|
n3=-1
|
||||||
|
call pack77(message,i3,n3,c77)
|
||||||
|
call unpack77(c77,msgsent,unpk77_success) !Unpack to get msgsent
|
||||||
|
|
||||||
|
if(ichk.eq.1) go to 999
|
||||||
|
read(c77,"(77i1)") msgbits
|
||||||
|
call encode_128_90(msgbits,codeword)
|
||||||
|
|
||||||
|
!Create 144-bit channel vector:
|
||||||
|
bitseq=0
|
||||||
|
bitseq(1:16)=s16
|
||||||
|
bitseq(17:144)=codeword
|
||||||
|
|
||||||
|
i4tone=bitseq
|
||||||
|
endif
|
||||||
|
|
||||||
|
999 return
|
||||||
|
end subroutine genft2
|
64
lib/ft2/getcandidates2.f90
Normal file
64
lib/ft2/getcandidates2.f90
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
subroutine getcandidates2(id,fa,fb,maxcand,savg,candidate,ncand)
|
||||||
|
|
||||||
|
! For now, hardwired to find the largest peak in the average spectrum
|
||||||
|
|
||||||
|
include 'ft2_params.f90'
|
||||||
|
real s(NH1,NHSYM)
|
||||||
|
real savg(NH1),savsm(NH1)
|
||||||
|
real x(NFFT1)
|
||||||
|
complex cx(0:NH1)
|
||||||
|
real candidate(3,100)
|
||||||
|
integer*2 id(NMAX)
|
||||||
|
integer*1 s8(8)
|
||||||
|
integer indx(NH1)
|
||||||
|
data s8/0,1,1,1,0,0,1,0/
|
||||||
|
equivalence (x,cx)
|
||||||
|
|
||||||
|
! Compute symbol spectra, stepping by NSTEP steps.
|
||||||
|
savg=0.
|
||||||
|
tstep=NSTEP/12000.0
|
||||||
|
df=12000.0/NFFT1 !3.125 Hz
|
||||||
|
fac=1.0/300.0
|
||||||
|
do j=1,NHSYM
|
||||||
|
ia=(j-1)*NSTEP + 1
|
||||||
|
ib=ia+NSPS-1
|
||||||
|
x(1:NSPS)=fac*id(ia:ib)
|
||||||
|
x(NSPS+1:)=0.
|
||||||
|
call four2a(x,NFFT1,1,-1,0) !r2c FFT
|
||||||
|
do i=1,NH1
|
||||||
|
s(i,j)=real(cx(i))**2 + aimag(cx(i))**2
|
||||||
|
enddo
|
||||||
|
savg=savg + s(1:NH1,j) !Average spectrum
|
||||||
|
enddo
|
||||||
|
savsm=0.
|
||||||
|
do i=2,NH1-1
|
||||||
|
savsm(i)=sum(savg(i-1:i+1))/3.
|
||||||
|
enddo
|
||||||
|
savsm(1)=savg(1)
|
||||||
|
savsm(NH1)=savg(NH1)
|
||||||
|
|
||||||
|
nfa=nint(fa/df)
|
||||||
|
nfb=nint(fb/df)
|
||||||
|
np=nfb-nfa+1
|
||||||
|
indx=0
|
||||||
|
call indexx(savsm(nfa:nfb),np,indx)
|
||||||
|
xn=savsm(nfa+indx(nint(0.3*np)))
|
||||||
|
savsm=savsm/xn
|
||||||
|
imax=-1
|
||||||
|
xmax=-99.
|
||||||
|
do i=2,NH1-1
|
||||||
|
if(savsm(i).gt.savsm(i-1).and. &
|
||||||
|
savsm(i).gt.savsm(i+1).and. &
|
||||||
|
savsm(i).gt.xmax) then
|
||||||
|
xmax=savsm(i)
|
||||||
|
imax=i
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
f0=imax*df
|
||||||
|
if(xmax.gt.1.2) then
|
||||||
|
if(ncand.lt.maxcand) ncand=ncand+1
|
||||||
|
candidate(1,ncand)=f0
|
||||||
|
endif
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine getcandidates2
|
BIN
lib/ft2/libportaudio.a
Normal file
BIN
lib/ft2/libportaudio.a
Normal file
Binary file not shown.
BIN
lib/ft2/libwsjt_cxx.a
Normal file
BIN
lib/ft2/libwsjt_cxx.a
Normal file
Binary file not shown.
BIN
lib/ft2/libwsjt_fort.a
Normal file
BIN
lib/ft2/libwsjt_fort.a
Normal file
Binary file not shown.
1123
lib/ft2/portaudio.h
Normal file
1123
lib/ft2/portaudio.h
Normal file
File diff suppressed because it is too large
Load Diff
58
lib/ft2/ptt.c
Normal file
58
lib/ft2/ptt.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int ptt_(int *nport, int *ntx, int *ndtr, int *iptt)
|
||||||
|
{
|
||||||
|
static HANDLE hFile;
|
||||||
|
static int open=0, nhold=0;
|
||||||
|
char s[10];
|
||||||
|
int i3,i4,i5,i6,i9,i00;
|
||||||
|
|
||||||
|
if(*nport==0) {
|
||||||
|
*iptt=*ntx;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
nhold=0;
|
||||||
|
if(*nport>100) nhold=1;
|
||||||
|
|
||||||
|
if(*ntx && (!open)) {
|
||||||
|
sprintf(s,"\\\\.\\COM%d",*nport%100);
|
||||||
|
hFile=CreateFile(
|
||||||
|
TEXT(s),
|
||||||
|
GENERIC_WRITE,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
if(hFile==INVALID_HANDLE_VALUE) {
|
||||||
|
printf("PTT: Cannot open COM port %d.\n",*nport%100);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
open=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*ntx && open) {
|
||||||
|
if(*ndtr)
|
||||||
|
EscapeCommFunction(hFile,5); //set DTR
|
||||||
|
else
|
||||||
|
EscapeCommFunction(hFile,3); //set RTS
|
||||||
|
*iptt=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
if(*ndtr)
|
||||||
|
EscapeCommFunction(hFile,6); //clear DTR
|
||||||
|
else
|
||||||
|
EscapeCommFunction(hFile,4); //clear RTS
|
||||||
|
EscapeCommFunction(hFile,9); //clear BREAK
|
||||||
|
if(nhold==0) {
|
||||||
|
i00=CloseHandle(hFile);
|
||||||
|
open=0;
|
||||||
|
}
|
||||||
|
*iptt=0;
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
341
lib/ft2/ptt_unix.c
Normal file
341
lib/ft2/ptt_unix.c
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
//#include <sys/ioctl.h>
|
||||||
|
//#include <linux/ppdev.h>
|
||||||
|
//#include <linux/parport.h>
|
||||||
|
//#include <dev/ppbus/ppi.h>
|
||||||
|
//#include <dev/ppbus/ppbconf.h>
|
||||||
|
|
||||||
|
int lp_reset (int fd);
|
||||||
|
int lp_ptt (int fd, int onoff);
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_STAT_H
|
||||||
|
# include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
#if (defined(__unix__) || defined(unix)) && !defined(USG)
|
||||||
|
# include <sys/param.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
/* parport functions */
|
||||||
|
|
||||||
|
int dev_is_parport(int fd);
|
||||||
|
int ptt_parallel(int fd, int *ntx, int *iptt);
|
||||||
|
int ptt_serial(int fd, int *ntx, int *iptt);
|
||||||
|
|
||||||
|
int fd=-1; /* Used for both serial and parallel */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ptt_
|
||||||
|
*
|
||||||
|
* generic unix PTT routine called from Fortran
|
||||||
|
*
|
||||||
|
* Inputs
|
||||||
|
* unused Unused, to satisfy old windows calling convention
|
||||||
|
* ptt_port device name serial or parallel
|
||||||
|
* ntx pointer to fortran command on or off
|
||||||
|
* iptt pointer to fortran command status on or off
|
||||||
|
* Returns - non 0 if error
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Tiny state machine */
|
||||||
|
#define STATE_PORT_CLOSED 0
|
||||||
|
#define STATE_PORT_OPEN_PARALLEL 1
|
||||||
|
#define STATE_PORT_OPEN_SERIAL 2
|
||||||
|
|
||||||
|
int
|
||||||
|
ptt_(int *unused, char *ptt_port, int *ntx, int *ndtr, int *iptt)
|
||||||
|
{
|
||||||
|
static int state=0;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
/* In the very unlikely event of a NULL pointer, just return.
|
||||||
|
* Yes, I realise this should not be possible in WSJT.
|
||||||
|
*/
|
||||||
|
if (ptt_port == NULL) {
|
||||||
|
*iptt = *ntx;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case STATE_PORT_CLOSED:
|
||||||
|
|
||||||
|
/* Remove trailing ' ' */
|
||||||
|
if ((p = strchr(ptt_port, ' ')) != NULL)
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
/* If all that is left is a '\0' then also just return */
|
||||||
|
if (*ptt_port == '\0') {
|
||||||
|
*iptt = *ntx;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fd = open(ptt_port, O_RDWR|O_NONBLOCK)) < 0) {
|
||||||
|
fprintf(stderr, "Can't open %s.\n", ptt_port);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev_is_parport(fd)) {
|
||||||
|
state = STATE_PORT_OPEN_PARALLEL;
|
||||||
|
lp_reset(fd);
|
||||||
|
ptt_parallel(fd, ntx, iptt);
|
||||||
|
} else {
|
||||||
|
state = STATE_PORT_OPEN_SERIAL;
|
||||||
|
ptt_serial(fd, ntx, iptt);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_PORT_OPEN_PARALLEL:
|
||||||
|
ptt_parallel(fd, ntx, iptt);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_PORT_OPEN_SERIAL:
|
||||||
|
ptt_serial(fd, ntx, iptt);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
state = STATE_PORT_CLOSED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ptt_serial
|
||||||
|
*
|
||||||
|
* generic serial unix PTT routine called indirectly from Fortran
|
||||||
|
*
|
||||||
|
* fd - already opened file descriptor
|
||||||
|
* ntx - pointer to fortran command on or off
|
||||||
|
* iptt - pointer to fortran command status on or off
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ptt_serial(int fd, int *ntx, int *iptt)
|
||||||
|
{
|
||||||
|
int control = TIOCM_RTS | TIOCM_DTR;
|
||||||
|
|
||||||
|
if(*ntx) {
|
||||||
|
ioctl(fd, TIOCMBIS, &control); /* Set DTR and RTS */
|
||||||
|
*iptt = 1;
|
||||||
|
} else {
|
||||||
|
ioctl(fd, TIOCMBIC, &control);
|
||||||
|
*iptt = 0;
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* parport functions */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dev_is_parport(fd):
|
||||||
|
*
|
||||||
|
* inputs - Already open fd
|
||||||
|
* output - 1 if parallel port, 0 if not
|
||||||
|
* side effects - Unfortunately, this is platform specific.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(HAVE_LINUX_PPDEV_H) /* Linux (ppdev) */
|
||||||
|
|
||||||
|
int
|
||||||
|
dev_is_parport(int fd)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
int m;
|
||||||
|
|
||||||
|
if ((fstat(fd, &st) == -1) ||
|
||||||
|
((st.st_mode & S_IFMT) != S_IFCHR) ||
|
||||||
|
(ioctl(fd, PPGETMODE, &m) == -1))
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(HAVE_DEV_PPBUS_PPI_H) /* FreeBSD (ppbus/ppi) */
|
||||||
|
|
||||||
|
int
|
||||||
|
dev_is_parport(int fd)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
unsigned char c;
|
||||||
|
|
||||||
|
if ((fstat(fd, &st) == -1) ||
|
||||||
|
((st.st_mode & S_IFMT) != S_IFCHR) ||
|
||||||
|
(ioctl(fd, PPISSTATUS, &c) == -1))
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* Fallback (nothing) */
|
||||||
|
|
||||||
|
int
|
||||||
|
dev_is_parport(int fd)
|
||||||
|
{
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/* Linux wrapper around PPFCONTROL */
|
||||||
|
#ifdef HAVE_LINUX_PPDEV_H
|
||||||
|
static void
|
||||||
|
parport_control (int fd, unsigned char controlbits, int values)
|
||||||
|
{
|
||||||
|
struct ppdev_frob_struct frob;
|
||||||
|
frob.mask = controlbits;
|
||||||
|
frob.val = values;
|
||||||
|
|
||||||
|
if (ioctl (fd, PPFCONTROL, &frob) == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Parallel port PPFCONTROL");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* FreeBSD wrapper around PPISCTRL */
|
||||||
|
#ifdef HAVE_DEV_PPBUS_PPI_H
|
||||||
|
static void
|
||||||
|
parport_control (int fd, unsigned char controlbits, int values)
|
||||||
|
{
|
||||||
|
unsigned char val;
|
||||||
|
|
||||||
|
if (ioctl (fd, PPIGCTRL, &val) == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Parallel port PPIGCTRL");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
val &= ~controlbits;
|
||||||
|
val |= values;
|
||||||
|
|
||||||
|
if (ioctl (fd, PPISCTRL, &val) == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Parallel port PPISCTRL");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Initialise a parallel port, given open fd */
|
||||||
|
int
|
||||||
|
lp_init (int fd)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LINUX_PPDEV_H
|
||||||
|
int mode;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LINUX_PPDEV_H
|
||||||
|
mode = PARPORT_MODE_PCSPP;
|
||||||
|
|
||||||
|
if (ioctl (fd, PPSETMODE, &mode) == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Setting parallel port mode");
|
||||||
|
close (fd);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl (fd, PPEXCL, NULL) == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Parallel port is already in use.\n");
|
||||||
|
close (fd);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
if (ioctl (fd, PPCLAIM, NULL) == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Claiming parallel port.\n");
|
||||||
|
fprintf(stderr, "HINT: did you unload the lp kernel module?");
|
||||||
|
close (fd);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable CW & PTT - /STROBE bit (pin 1) */
|
||||||
|
parport_control (fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_DEV_PPBUS_PPI_H
|
||||||
|
parport_control (fd, STROBE, STROBE);
|
||||||
|
#endif
|
||||||
|
lp_reset (fd);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* release ppdev and close port */
|
||||||
|
int
|
||||||
|
lp_free (int fd)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LINUX_PPDEV_H
|
||||||
|
lp_reset (fd);
|
||||||
|
|
||||||
|
/* Disable CW & PTT - /STROBE bit (pin 1) */
|
||||||
|
parport_control (fd, PARPORT_CONTROL_STROBE, 0);
|
||||||
|
|
||||||
|
ioctl (fd, PPRELEASE);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_DEV_PPBUS_PPI_H
|
||||||
|
/* Disable CW & PTT - /STROBE bit (pin 1) */
|
||||||
|
parport_control (fd, STROBE, 0);
|
||||||
|
#endif
|
||||||
|
close (fd);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set to a known state */
|
||||||
|
int
|
||||||
|
lp_reset (int fd)
|
||||||
|
{
|
||||||
|
#if defined (HAVE_LINUX_PPDEV_H) || defined (HAVE_DEV_PPBUS_PPI_H)
|
||||||
|
lp_ptt (fd, 0);
|
||||||
|
#endif
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SSB PTT keying - /INIT bit (pin 16) (inverted) */
|
||||||
|
int
|
||||||
|
lp_ptt (int fd, int onoff)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LINUX_PPDEV_H
|
||||||
|
if (onoff == 1)
|
||||||
|
parport_control (fd, PARPORT_CONTROL_INIT,
|
||||||
|
PARPORT_CONTROL_INIT);
|
||||||
|
else
|
||||||
|
parport_control (fd, PARPORT_CONTROL_INIT, 0);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_DEV_PPBUS_PPI_H
|
||||||
|
if (onoff == 1)
|
||||||
|
parport_control (fd, nINIT,
|
||||||
|
nINIT);
|
||||||
|
else
|
||||||
|
parport_control (fd, nINIT, 0);
|
||||||
|
#endif
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ptt_parallel
|
||||||
|
*
|
||||||
|
* generic parallel unix PTT routine called indirectly from Fortran
|
||||||
|
*
|
||||||
|
* fd - already opened file descriptor
|
||||||
|
* ntx - pointer to fortran command on or off
|
||||||
|
* iptt - pointer to fortran command status on or off
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ptt_parallel(int fd, int *ntx, int *iptt)
|
||||||
|
{
|
||||||
|
if(*ntx) {
|
||||||
|
lp_ptt(fd, 1);
|
||||||
|
*iptt=1;
|
||||||
|
} else {
|
||||||
|
lp_ptt(fd, 0);
|
||||||
|
*iptt=0;
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user