mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-22 04:11:16 -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