1
0
mirror of https://github.com/saitohirga/WSJT-X.git synced 2025-04-21 02:38:34 -04:00

SuperFox Tx now works with sftx[.exe] built as part of the wsjtx package.

This commit is contained in:
Joe Taylor 2024-09-17 10:24:02 -04:00
parent 4400f7464c
commit dcb8c6ce6b
5 changed files with 439 additions and 0 deletions

View File

@ -602,17 +602,21 @@ set (wsjt_FSRCS
lib/fst4/fst4_baseline.f90
lib/77bit/hash22calc.f90
lib/superfox/foxgen2.f90
lib/superfox/qpc_decode2.f90
lib/superfox/qpc_likelihoods2.f90
lib/superfox/qpc_snr.f90
lib/superfox/qpc_sync.f90
lib/superfox/sfox_ana.f90
lib/superfox/sfox_assemble.f90
lib/superfox/sfox_demod.f90
lib/superfox/sfox_pack.f90
lib/superfox/sfox_remove_ft8.f90
lib/superfox/sfox_unpack.f90
lib/superfox/sfox_wave.f90
lib/superfox/sfox_wave_gfsk.f90
lib/superfox/sfrx_sub.f90
lib/superfox/sftx.f90
lib/superfox/twkfreq2.f90
)
@ -1253,6 +1257,9 @@ target_link_libraries (ft8sim wsjt_fort wsjt_cxx)
#add_executable (sfrx lib/superfox/sfrx.f90)
#target_link_libraries (sfrx wsjt_fort wsjt_cxx)
add_executable (sftx lib/superfox/sftx.f90)
target_link_libraries (sftx wsjt_fort wsjt_cxx)
add_executable (msk144sim lib/msk144sim.f90)
target_link_libraries (msk144sim wsjt_fort wsjt_cxx)

75
lib/superfox/foxgen2.f90 Normal file
View File

@ -0,0 +1,75 @@
subroutine foxgen2(nslots,cmsg,line,foxcall)
! Parse old-style Fox messages to extract the necessary pieces for a SuperFox
! transmission.
use packjt77
character*120 line
character*40 cmsg(5) !Old-style Fox messages are here
character*37 msg
character*26 sfmsg
character*13 mycall
character*11 foxcall
character*4 mygrid
character*6 hiscall_1,hiscall_2
character*4 rpt1,rpt2
character*13 w(19)
integer nw(19)
integer ntype !Message type: 0 Free Text
! 1 CQ MyCall MyGrid
! 2 Call_1 MyCall RR73
! 3 Call_1 MyCall rpt1
! 4 Call_1 RR73; Call_2 <MyCall> rpt2
if(nslots.lt.1 .or. nslots.gt.5) return
k=0
do i=1,nslots
hiscall_1=''
hiscall_2=''
mycall=''
mygrid=''
rpt1=''
rpt2=''
msg=cmsg(i)(1:37)
call split77(msg,nwords,nw,w)
ntype=0
if(msg(1:3).eq.'CQ ') then
ntype=1
mycall=w(2)(1:12)
mygrid=w(3)(1:4)
else if(index(msg,';').gt.0) then
ntype=4
hiscall_1=w(1)(1:6)
hiscall_2=w(3)(1:6)
rpt1='RR73'
rpt2=w(5)(1:4)
mycall=w(4)(2:nw(4)-1)
else if(index(msg,' RR73').gt.0) then
ntype=2
hiscall_1=w(1)(1:6)
mycall=w(2)(1:12)
rpt1='RR73'
else if(nwords.eq.3 .and. nw(3).eq.3 .and. &
(w(3)(1:1).eq.'-' .or. w(3)(1:1).eq.'+')) then
ntype=3
hiscall_1=w(1)(1:6)
mycall=w(2)(1:12)
rpt1=w(3)(1:4)
endif
k=k+1
if(ntype.le.3) call sfox_assemble(ntype,k,msg(1:26),mycall,mygrid,line)
if(ntype.eq.4) then
sfmsg=w(1)(1:nw(1))//' '//mycall(1:len(trim(mycall))+1)//'RR73'
call sfox_assemble(2,k,sfmsg,mycall,mygrid,line)
sfmsg=w(3)(1:nw(3))//' '//mycall(1:len(trim(mycall))+1)//w(5)(1:3)
k=k+1
call sfox_assemble(3,k,sfmsg,mycall,mygrid,line)
endif
enddo
call sfox_assemble(ntype,11,msg(1:26),mycall,mygrid,line) !k=11 to finish up
foxcall=mycall(1:11)
return
end subroutine foxgen2

View File

@ -0,0 +1,92 @@
subroutine sfox_assemble(ntype,k,msg,mycall0,mygrid0,line)
! In subsequent calls, assemble all necessary information for a SuperFox
! transmission.
character*120 line
character*26 msg
character*26 msg0,msg1,msg2(5),msg3(5)
character*4 rpt2(5)
character*6 hiscall(10)
character*13 mycall0,mycall
character*4 mygrid0,mygrid
integer ntype !Message type: 0 Free Text
! 1 CQ MyCall MyGrid
! 2 Call_1 MyCall RR73
! 3 Call_1 MyCall rpt
integer nmsg(0:3) !Number of messages of type ntype
data nmsg/0,0,0,0/,nbits/0/,ntx/0/,nb_mycall/0/
save
if(mycall0(1:1).ne.' ') mycall=mycall0
if(mygrid0(1:1).ne.' ') mygrid=mygrid0
if(ntype.ge.1) nb_mycall=28 !### Allow for nonstandard MyCall ###
if(sum(nmsg).eq.0) then
hiscall=' '
rpt2=' '
endif
if(k.le.10) then
if(ntype.eq.0) then
if(nbits+nb_mycall.le.191) then !Enough room for a free text message?
nmsg(ntype)=nmsg(ntype)+1
nbits=nbits+142
msg0=msg
endif
else if(ntype.eq.1) then
if(nbits+nb_mycall.le.318) then !Enough room for a CQ ?
nmsg(ntype)=nmsg(ntype)+1
nbits=nbits+15
msg1=msg
endif
else if(ntype.eq.2) then
if(nbits+nb_mycall.le.305) then !Enough room for a RR73 message?
nmsg(ntype)=nmsg(ntype)+1
nbits=nbits+28
j=nmsg(ntype)
msg2(j)=msg
i1=index(msg,' ')
hiscall(j+5)=msg(1:i1-1)
endif
else if(ntype.eq.3) then
if(nbits+nb_mycall.le.300) then !Enough room for a message with report?
nmsg(ntype)=nmsg(ntype)+1
nbits=nbits+33
j=nmsg(ntype)
msg3(j)=msg
i1=index(msg,' ')
hiscall(j)=msg(1:i1-1)
i1=max(index(msg,'-'),index(msg,'+'))
rpt2(j)=msg(i1:i1+3)
endif
endif
return
endif
if(k.ge.11) then
! All pieces are now available. Put them into a command line for external
! program sfox_tx.
ntx=ntx+1 !Transmission number
nbits=nbits+nb_mycall !Add bits for MyCall
if(nmsg(1).ge.1) then
line=msg1
else
line=trim(mycall)
do i=1,nmsg(3)
line=trim(line)//' '//trim(hiscall(i))//' '//rpt2(i)
enddo
do i=1,nmsg(2)
line=trim(line)//' '//trim(hiscall(i+5))
enddo
endif
nmsg=0
nbits=0
nb_mycall=0
hiscall=' '
rpt2=' '
endif
return
end subroutine sfox_assemble

158
lib/superfox/sfox_pack.f90 Normal file
View File

@ -0,0 +1,158 @@
subroutine sfox_pack(line,ckey,bMoreCQs,bSendMsg,freeTextMsg,xin)
use qpc_mod
use packjt
use packjt77
use julian
integer stat
integer*8 n47,n58,now
integer*1 xin(0:49) !Packed message as 7-bit symbols
logical*1 bMoreCQs,bSendMsg
logical text
character*120 line !SuperFox message pieces
character*10 ckey
character*26 freeTextMsg
character*13 w(16)
character*11 c11
character*329 msgbits !Packed message as bits
character*38 c
data c/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ/'/
i0=index(line,'/')
i3=0 !Default to i3=0, standard message
! Split the command line into words
w=' '
i1=1
do j=1,16
do i=i1,min(i1+12,120)
if(line(i:i).eq.' ') exit
enddo
i2=i-1
w(j)=line(i1:i2)
do i=i2+1,120
if(line(i:i).ne.' ') exit
enddo
i1=i
if(i1.ge.120) exit
enddo
nwords=j
do i=1,nwords
if(w(i)(1:1).eq.' ') then
nwords=i-1
exit
endif
enddo
do i=1,329 !Set all msgbits to '0'
msgbits(i:i)='0'
enddo
now=itime8()/30
now=30*now
read(ckey(5:10),*) nsignature
write(msgbits(307:326),'(b20.20)') nsignature !Insert the digital signature
if(w(1)(1:3).eq.'CQ ') then
i3=3
c11=w(2)(1:11)
n58=0
do i=1,11
n58=n58*38 + index(c,c11(i:i)) - 1
enddo
write(msgbits(1:58),'(b58.58)') n58
call packgrid(w(3)(1:4),n15,text)
write(msgbits(59:73),'(b15.15)') n15
write(msgbits(327:329),'(b3.3)') i3 !Message type i3=3
go to 800
endif
call pack28(w(1),n28) !Fox call
write(msgbits(1:28),'(b28.28)') n28
nh1=0 !Number of Hound calls with RR73
nh2=0 !Number of Hound calls with report
! Default report is RR73 if we're also sending a free text message.
if(bSendMsg) msgbits(141:160)='11111111111111111111'
j=29
! Process callsigns with RR73
do i=2,nwords
if(w(i)(1:1).eq.'+' .or. w(i)(1:1).eq.'-') cycle !Skip report words
i1=min(i+1,nwords)
if(w(i1)(1:1) .eq.'+' .or. w(i1)(1:1).eq.'-') cycle !Skip if i+1 is report
call pack28(w(i),n28)
write(msgbits(j:j+27),1002) n28 !Insert this call for RR73 message
1002 format(b28.28)
j=j+28
nh1=nh1+1
if( nht.ge.5 ) exit !At most 5 RR73 callsigns
enddo
! Process callsigns with a report
j=169
j2=281
if(bSendMsg) then
i3=2
j=29 + 28*nh1
j2=141 + 5*nh1
endif
do i=2,nwords
i1=min(i+1,nwords)
if(w(i1)(1:1).eq.'+' .or. w(i1)(1:1).eq.'-') then
call pack28(w(i),n28)
write(msgbits(j:j+27),1002) n28 !Insert this call
read(w(i1),*) n !Valid reports are -18 to +12, plus RR73
if(n.lt.-18) n=-18 !... Even numbers only ...
if(n.gt.12) n=12
write(msgbits(j2:j2+4),1000) n+18
1000 format(b5.5)
w(i1)=""
nh2=nh2+1
! print*,'C',i3,i,j,n,w(i)
if( nh2.ge.4 .or. (nh1+nh2).ge.9 ) exit ! At most 4 callsigns w/reports
j=j+28
j2=j2+5
endif
enddo
800 if(bSendMsg) then
i1=26
do i=1,26
if(freeTextMsg(i:i).ne.' ') i1=i
enddo
do i=i1+1,26
freeTextMsg(i:i)='.'
enddo
if(i3.eq.3) then
call packtext77(freeTextMsg(1:13),msgbits(74:144))
call packtext77(freeTextMsg(14:26),msgbits(145:215))
elseif(i3.eq.2) then
call packtext77(freeTextMsg(1:13),msgbits(161:231))
call packtext77(freeTextMsg(14:26),msgbits(232:302))
endif
write(msgbits(327:329),'(b3.3)') i3 !Message type i3=2
endif
if(bMoreCQs) msgbits(306:306)='1'
read(msgbits,1004) xin(0:46)
1004 format(47b7)
mask21=2**21 - 1
n47=47
ncrc21=iand(nhash2(xin,n47,571),mask21) !Compute 21-bit CRC
xin(47)=ncrc21/16384 !First 7 of 21 bits
xin(48)=iand(ncrc21/128,127) !Next 7 bits
xin(49)=iand(ncrc21,127) !Last 7 bits
xin=xin(49:0:-1) !Reverse the symbol order
! NB: CRC is now in first three symbols, fox call in the last four.
read(msgbits(327:329),'(b3)') i3
return
end subroutine sfox_pack

107
lib/superfox/sftx.f90 Normal file
View File

@ -0,0 +1,107 @@
program sftx
! This program is required in order to create a SuperFox transmission.
! The present version goes through the following steps:
! 1. Read old-style Fox messages from file 'sfox_1.dat' in the WSJT-X
! writable data directory.
! 2. Parse up to NSlots=5 messages to extract MyCall, up to 9 Hound
! calls, and the report or RR73 to be sent to each Hound.
! 3. Assemble and encode a single SuperFox message to produce itone(1:151),
! the array of channel symbol values.
! 4. Write the contents of array itone to file 'sfox_2.dat'.
use qpc_mod
use sfox_mod
character*120 fname !Corrected path for sfox_1.dat
character*120 line !List of SuperFox message pieces
character*40 cmsg(5) !Old-style Fox messages
character*26 freeTextMsg
character*2 arg
character*10 ckey
! character*9 foxkey
character*11 foxcall0,foxcall
logical*1 bMoreCQs,bSendMsg
logical crc_ok
real py(0:127,0:127) !Probabilities for received synbol values
integer*8 n47
integer itone(151) !SuperFox channel-symbol values
integer*1 xin(0:49) !Packed message as 7-bit symbols
integer*1 xdec(0:49) !Decoded message
integer*1 y(0:127) !Encoded symbols as i*1 integers
integer*1 ydec(0:127) !Decoded codeword
integer*1 yy(0:10)
integer chansym0(127) !Transmitted symbols, data only
integer chansym(127) !Received symbols, data only
integer isync(24) !Symbol numbers for sync tones
data isync/1,2,4,7,11,16,22,29,37,39,42,43,45,48,52,57,63,70,78,80, &
83,84,86,89/
include 'gtag.f90'
narg=iargc()
if(narg.ne.3) then
print '(" Git tag: ",z9)',ntag
go to 999
endif
! sftx <message_file_name> <foxcall> <ckey>
call getarg(1,fname)
do i=1,len(trim(fname))
if(fname(i:i).eq.'\\') fname(i:i)='/'
enddo
call getarg(2,foxcall0)
call getarg(3,ckey)
! if((foxkey(foxcall0).ne.ckey).and.(INDEX(ckey,'OTP:').eq.0)) then ! neither kind
! itone=-99
! go to 100
! endif
fsample=12000.0
call sfox_init(7,127,50,'no',fspread,delay,fsample,24)
open(25,file=trim(fname),status='unknown')
do i=1,5
read(25,1000,end=10) cmsg(i)
1000 format(a40)
enddo
i=6
10 close(25)
nslots=i-1
freeTextMsg=' '
bMoreCQs=cmsg(1)(40:40).eq.'1'
bSendMsg=cmsg(nslots)(39:39).eq.'1'
if(bSendMsg) then
freeTextMsg=cmsg(nslots)(1:26)
if(nslots.gt.2) nslots=2
endif
call foxgen2(nslots,cmsg,line,foxcall) !Parse old-style Fox messages
! Pack message information and CRC into xin(0:49)
call sfox_pack(line,ckey,bMoreCQs,bSendMsg,freeTextMsg,xin)
call qpc_encode(y,xin) !Encode the message to 128 symbols
y=cshift(y,1) !Puncture the code by removing y(0)
y(127)=0
chansym0=y(0:126)
! Create the full itone sequence containing both data and sync symbols
j=1
k=0
do i=1,NDS
if(j.le.NS .and. i.eq.isync(j)) then
if(j.lt.NS) j=j+1 !Index for next sync symbol
itone(i)=0 !Insert sync symbol at tone 0
else
k=k+1
itone(i)=chansym0(k) + 1 !Symbol value 0 transmitted as tone 1, etc.
endif
enddo
100 i1=max(index(fname,'sfox_1'),1)
fname(i1:i1+9)='sfox_2.dat'
open(25,file=trim(fname),status='unknown')
write(25,1100) itone
1100 format(20i4)
close(25)
999 end program sftx