diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ac4ad4f8..4af7e5dcb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -587,6 +587,9 @@ set (qra_CSRCS lib/qra/qracodes/qra13_64_64_irr_e.c lib/qra/qracodes/qracodes.c lib/qra/qracodes/normrnd.c + lib/qra/q65/qra15_65_64_irr_e23.c + lib/qra/q65/q65.c + lib/qra/q65/q65_subs.c ) set (wsjt_CSRCS @@ -1123,6 +1126,9 @@ target_link_libraries (test_qra64 wsjt_fort wsjt_cxx) add_executable (test_q65 lib/test_q65.f90) target_link_libraries (test_q65 wsjt_fort wsjt_cxx) +add_executable (q65_ftn_test lib/qra/q65/q65_ftn_test.f90) +target_link_libraries (q65_ftn_test wsjt_fort wsjt_cxx) + add_executable (jt49sim lib/jt49sim.f90) target_link_libraries (jt49sim wsjt_fort wsjt_cxx) diff --git a/lib/qra/q65/Makefile.Win b/lib/qra/q65/Makefile.Win index 99b34d726..8f2214d99 100644 --- a/lib/qra/q65/Makefile.Win +++ b/lib/qra/q65/Makefile.Win @@ -1,5 +1,7 @@ CC = gcc CFLAGS = -O2 -Wall -I. -D_WIN32 +FC = gfortran +FFLAGS = -Wall -fbounds-check # Default rules %.o: %.c @@ -13,7 +15,7 @@ CFLAGS = -O2 -Wall -I. -D_WIN32 %.o: %.F90 ${FC} ${FFLAGS} -c $< -all: libq65.a q65.exe +all: libq65.a q65.exe q65_ftn_test.exe OBJS1 = normrnd.o npfwht.o pdmath.o qra15_65_64_irr_e23.o \ q65.o qracodes.o @@ -27,6 +29,11 @@ OBJS2 = q65test.o q65.exe: $(OBJS2) ${CC} -o q65.exe $(OBJS2) libq65.a -lm +OBJS3 = q65_ftn_test.o q65_subs.o + +q65_ftn_test.exe: $(OBJS3) + ${FC} -o q65_ftn_test.exe $(OBJS3) libq65.a -lm + .PHONY : clean clean: diff --git a/lib/qra/q65/q65_ftn_test.f90 b/lib/qra/q65/q65_ftn_test.f90 new file mode 100644 index 000000000..6291950a2 --- /dev/null +++ b/lib/qra/q65/q65_ftn_test.f90 @@ -0,0 +1,50 @@ +program q65_ftn_test + + use packjt77 + parameter (LL=64,NN=63) + integer x(13) !User's 78-bit message as 13 six-bit integers + integer y(63) !Q65 codeword for x + integer xdec(13) !Decoded message + integer APmask(13) + integer APsymbols(13) + real s3(0:LL-1,NN) + real s3prob(0:LL-1,NN) + character*37 msg0,msg,msgsent + character*77 c77 + logical unpk77_success + + narg=iargc() + if(narg.ne.1) then + print*,'Usage: q65_ftn_test "message"' + print*,'Example: q65_ftn_test "K1ABC W9XYZ EN37"' + go to 999 + endif + call getarg(1,msg0) + call pack77(msg0,i3,n3,c77) + call unpack77(c77,0,msgsent,unpk77_success) !Unpack to get msgsent + read(c77,1000) x +1000 format(12b6.6,b5.5) + + call q65_enc(x,y) + + write(*,1010) x,msg0 +1010 format('User message:'/13i3,2x,a) + write(*,1020) y +1020 format(/'Generated codeword:'/(20i3)) + + s3=0. + s3prob=0. + do j=1,NN + s3(y(j),j)=1.0 + enddo + APmask=0 + APsymbols=0 + + call q65_dec(s3,APmask,APsymbols,s3prob,snr2500,xdec,irc) + + write(c77,1000) xdec + call unpack77(c77,0,msg,unpk77_success) !Unpack to get msgsent + write(*,1100) xdec,trim(msg) +1100 format(/'Decoded message:'/13i3,2x,a) + +999 end program q65_ftn_test diff --git a/lib/qra/q65/q65_subs.c b/lib/qra/q65/q65_subs.c new file mode 100644 index 000000000..97889871f --- /dev/null +++ b/lib/qra/q65/q65_subs.c @@ -0,0 +1,90 @@ +// q65_subs.c + +/* Fortran interface for Q65 codec + + To encode a Q65 message: + + integer x(13) !Message payload, 78 bits as 13 six-bit integers + integer y(63) !Codeword, 63 six-bit integers + call q65_enc(imsg,icodeword) + + To decode a Q65 message: + + parameter (LL=64,NN=63) + real s3(LL,NN) !Received energies + real s3prob(LL,NN) !Symbol-value probabilities + integer APmask(13) + integer APsymbols(13) + real snr2500 + integer xdec(13) !Decoded 78-bit message as 13 six-bit integers + integer irc !Return code from q65_decode() + + call q65_dec(s3,APmask,APsymbols,s3prob,snr2500,xdec,irc) +*/ + +#include "qra15_65_64_irr_e23.h" // QRA code used by Q65 +#include "q65.h" +#include +#include + +static q65_codec_ds codec; + +void q65_enc_(int x[], int y[]) +{ + + static int first=1; + if (first) { + // Set the QRA code, allocate memory, and initialize + int rc = q65_init(&codec,&qra15_65_64_irr_e23); + if (rc<0) { + printf("error in q65_init()\n"); + exit(0); + } + first=0; + } + // Encode message x[13], producing codeword y[63] + q65_encode(&codec,y,x); +} + +void q65_dec_(float s3[], int APmask[], int APsymbols[], float s3prob[], + float* snr2500, int xdec[], int* rc0) +{ + +/* Input: s3[LL,NN] Received energies + * APmask[13] AP information to be used in decoding + * APsymbols[13] Available AP informtion + * Output: s3prob[LL,NN] Symbol-value intrinsic probabilities + * snr2500 SNR_2500 of decoded signal, or lower limit + * xdec[13] Decoded 78-bit message as 13 six-bit integers + * rc0 Return code from q65_decode() + */ + + int rc; + int ydec[63]; + float esnodb; + + // rc = q65_intrinsics_fastfding(&codec,s3prob,s3,submode,B90,fadingModel); + rc = q65_intrinsics(&codec,s3prob,s3); + if(rc<0) { + printf("error in q65_intrinsics()\n"); + exit(0); + } + + rc = q65_decode(&codec,ydec,xdec,s3prob,APmask,APsymbols); + *rc0=rc; + if(rc<0) { + printf("Error in q65_decode(), rc = %d\n",rc); + // rc = -1: Invalid params + // rc = -2: Decode failed + // rc = -3: CRC mismatch + return; + } + + // rc = q65_esnodb_fastfading(&codec,&esnodb,ydec,s3); + rc = q65_esnodb(&codec,&esnodb,ydec,s3); + if(rc<0) { + printf("error in q65_esnodb_fastfading()\n"); + exit(0); + } + *snr2500 = esnodb - 31.0; +}