From e20fd7ebcaad6c7961cec69979f8b02df7b7dea2 Mon Sep 17 00:00:00 2001 From: Kristian Sabo Date: Thu, 7 Sep 2023 13:45:16 +0200 Subject: [PATCH] msvc export/import --- CMakeLists.txt | 22 +- demo/freedv_700d_rx.py | 0 octave/crc16.m | 110 +-- octave/ldpc_fsk_lib.m | 538 +++++++------- src/CMakeLists.txt | 12 +- src/codec2.c | 2 +- src/codec2.h | 61 +- src/codec2_fdmdv.h | 70 +- src/codec2_fifo.h | 16 +- src/codec2_fm.h | 12 +- src/codec2_ofdm.h | 62 +- src/cohpsk.c | 5 +- src/comp_prim.h | 2 +- src/defines.h | 2 +- src/export.h | 14 + src/freedv_api.c | 2 +- src/freedv_api.h | 245 ++++--- src/freedv_api_internal.h | 3 +- src/fsk.h | 39 +- src/ldpc_dec_test.c | 748 ++++++++++---------- src/modem_stats.h | 10 +- src/ofdm.c | 4 +- src/reliable_text.h | 20 +- stm32/unittest/lib/python/sum_profiles.py | 0 stm32/unittest/scripts/check_ram_limit | 0 stm32/unittest/scripts/kill_run_stm32_tst | 0 stm32/unittest/scripts/plot_ofdm_demod_syms | 0 stm32/unittest/scripts/run_all_codec2_tests | 0 stm32/unittest/scripts/run_all_ldpc_tests | 0 stm32/unittest/scripts/run_all_ofdm_tests | 0 stm32/unittest/scripts/run_all_stm32_tests | 0 stm32/unittest/scripts/run_stm32_prog | 0 stm32/unittest/scripts/run_stm32_tst | 0 stm32/unittest/scripts/tst_api_demod_check | 0 stm32/unittest/scripts/tst_api_demod_setup | 0 stm32/unittest/scripts/tst_api_mod_check | 0 stm32/unittest/scripts/tst_api_mod_setup | 0 stm32/unittest/scripts/tst_codec2_dec_check | 0 stm32/unittest/scripts/tst_codec2_dec_setup | 0 stm32/unittest/scripts/tst_codec2_enc_check | 0 stm32/unittest/scripts/tst_codec2_enc_setup | 0 stm32/unittest/scripts/tst_ldpc_dec_check | 0 stm32/unittest/scripts/tst_ldpc_dec_setup | 0 stm32/unittest/scripts/tst_ldpc_enc_check | 0 stm32/unittest/scripts/tst_ldpc_enc_setup | 0 stm32/unittest/scripts/tst_ofdm_demod_check | 0 stm32/unittest/scripts/tst_ofdm_demod_setup | 0 stm32/unittest/scripts/tst_ofdm_mod_check | 0 stm32/unittest/scripts/tst_ofdm_mod_setup | 0 unittest/check_comp.sh | 0 unittest/check_peak.sh | 0 unittest/check_real_comp.sh | 0 unittest/fading_files.sh | 0 unittest/ofdm_check | 0 unittest/ofdm_fade.sh | 0 unittest/ofdm_phase_est_bw.sh | 0 unittest/ofdm_time_sync.sh | 0 unittest/reliable_text_fade.sh | 0 unittest/sum_debug_alloc | 0 unittest/test_700c_eq.sh | 0 60 files changed, 1043 insertions(+), 956 deletions(-) mode change 100755 => 100644 demo/freedv_700d_rx.py create mode 100644 src/export.h mode change 100755 => 100644 stm32/unittest/lib/python/sum_profiles.py mode change 100755 => 100644 stm32/unittest/scripts/check_ram_limit mode change 100755 => 100644 stm32/unittest/scripts/kill_run_stm32_tst mode change 100755 => 100644 stm32/unittest/scripts/plot_ofdm_demod_syms mode change 100755 => 100644 stm32/unittest/scripts/run_all_codec2_tests mode change 100755 => 100644 stm32/unittest/scripts/run_all_ldpc_tests mode change 100755 => 100644 stm32/unittest/scripts/run_all_ofdm_tests mode change 100755 => 100644 stm32/unittest/scripts/run_all_stm32_tests mode change 100755 => 100644 stm32/unittest/scripts/run_stm32_prog mode change 100755 => 100644 stm32/unittest/scripts/run_stm32_tst mode change 100755 => 100644 stm32/unittest/scripts/tst_api_demod_check mode change 100755 => 100644 stm32/unittest/scripts/tst_api_demod_setup mode change 100755 => 100644 stm32/unittest/scripts/tst_api_mod_check mode change 100755 => 100644 stm32/unittest/scripts/tst_api_mod_setup mode change 100755 => 100644 stm32/unittest/scripts/tst_codec2_dec_check mode change 100755 => 100644 stm32/unittest/scripts/tst_codec2_dec_setup mode change 100755 => 100644 stm32/unittest/scripts/tst_codec2_enc_check mode change 100755 => 100644 stm32/unittest/scripts/tst_codec2_enc_setup mode change 100755 => 100644 stm32/unittest/scripts/tst_ldpc_dec_check mode change 100755 => 100644 stm32/unittest/scripts/tst_ldpc_dec_setup mode change 100755 => 100644 stm32/unittest/scripts/tst_ldpc_enc_check mode change 100755 => 100644 stm32/unittest/scripts/tst_ldpc_enc_setup mode change 100755 => 100644 stm32/unittest/scripts/tst_ofdm_demod_check mode change 100755 => 100644 stm32/unittest/scripts/tst_ofdm_demod_setup mode change 100755 => 100644 stm32/unittest/scripts/tst_ofdm_mod_check mode change 100755 => 100644 stm32/unittest/scripts/tst_ofdm_mod_setup mode change 100755 => 100644 unittest/check_comp.sh mode change 100755 => 100644 unittest/check_peak.sh mode change 100755 => 100644 unittest/check_real_comp.sh mode change 100755 => 100644 unittest/fading_files.sh mode change 100755 => 100644 unittest/ofdm_check mode change 100755 => 100644 unittest/ofdm_fade.sh mode change 100755 => 100644 unittest/ofdm_phase_est_bw.sh mode change 100755 => 100644 unittest/ofdm_time_sync.sh mode change 100755 => 100644 unittest/reliable_text_fade.sh mode change 100755 => 100644 unittest/sum_debug_alloc mode change 100755 => 100644 unittest/test_700c_eq.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index b92814c5..4f22bcb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,8 +79,13 @@ add_custom_target(dist | bzip2 > ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.bz2 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + # Set default C flags. +if(NOT MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-strict-overflow") +else() +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") +endif() # Check for what C standard is supported. if(NOT WIN32) @@ -103,8 +108,16 @@ if((NOT WIN32) AND (NOT MICROCONTROLLER_BUILD)) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") endif() +if(NOT MSVC) set(CMAKE_C_FLAGS_DEBUG "-g -O2 -DDUMP") set(CMAKE_C_FLAGS_RELEASE "-O3") +else() +set(CMAKE_C_FLAGS_DEBUG "/Zi") +set(CMAKE_C_FLAGS_RELEASE "/O2") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4244 /wd4305 /wd5045") + + +endif() # # Setup Windows/MinGW specifics here. @@ -125,7 +138,7 @@ option(UNITTEST "Build unittest binaries." OFF) option(LPCNET "Build codec2 with LPCNet support." OFF) set(LPCNET_BUILD_DIR FALSE CACHE PATH "Location of lpcnet build tree.") # Setting LPCNET_BUILD_DIR implies LPCNET=ON -if(LPCNET_BUILD_DIR) +if(${LPCNET_BUILD_DIR}) set(LPCNET ON) endif() @@ -214,8 +227,9 @@ endif() # codec2 library and demo apps # add_subdirectory(src) +if(NOT MSVC) add_subdirectory(demo) - +endif() if(UNITTEST) # Pthread Library @@ -252,7 +266,7 @@ message(STATUS "Compilation date = XX${DATE_RESULT}XX") set(CPACK_PACKAGE_VERSION_PATCH "${CPACK_PACKAGE_VERSION_PATCH}-${DATE_RESULT}-${CODEC2_HASH}") -if(WIN32) +if(WIN32 AND NOT MSVC) # # Cpack NSIS installer configuration for Windows. # See: http://nsis.sourceforge.net/Download @@ -284,7 +298,7 @@ elseif(UNIX AND NOT APPLE) include(CPack) cpack_add_component(lib REQUIRED) cpack_add_component(dev DEPENDS lib) -endif(WIN32) +endif() ######################################################################## # Create Pkg Config File diff --git a/demo/freedv_700d_rx.py b/demo/freedv_700d_rx.py old mode 100755 new mode 100644 diff --git a/octave/crc16.m b/octave/crc16.m index aafc432f..bf1e29b2 100644 --- a/octave/crc16.m +++ b/octave/crc16.m @@ -1,55 +1,55 @@ -% crc16.m -% -%The CRC calculation is based on following generator polynomial: -%G(x) = x16 + x12 + x5 + 1 -% -%The register initial value of the implementation is: 0xFFFF -% -%used data = string -> 1 2 3 4 5 6 7 8 9 -% -% Online calculator to check the script: -%http://www.lammertbies.nl/comm/info/crc-calculation.html -% -% - -function crc = crc16(data) - - % crc look up table - - Crc_ui16LookupTable=[0,4129,8258,12387,16516,20645,24774,28903,33032,37161,41290,45419,49548,... - 53677,57806,61935,4657,528,12915,8786,21173,17044,29431,25302,37689,33560,45947,41818,54205,... - 50076,62463,58334,9314,13379,1056,5121,25830,29895,17572,21637,42346,46411,34088,38153,58862,... - 62927,50604,54669,13907,9842,5649,1584,30423,26358,22165,18100,46939,42874,38681,34616,63455,... - 59390,55197,51132,18628,22757,26758,30887,2112,6241,10242,14371,51660,55789,59790,63919,35144,... - 39273,43274,47403,23285,19156,31415,27286,6769,2640,14899,10770,56317,52188,64447,60318,39801,... - 35672,47931,43802,27814,31879,19684,23749,11298,15363,3168,7233,60846,64911,52716,56781,44330,... - 48395,36200,40265,32407,28342,24277,20212,15891,11826,7761,3696,65439,61374,57309,53244,48923,... - 44858,40793,36728,37256,33193,45514,41451,53516,49453,61774,57711,4224,161,12482,8419,20484,... - 16421,28742,24679,33721,37784,41979,46042,49981,54044,58239,62302,689,4752,8947,13010,16949,... - 21012,25207,29270,46570,42443,38312,34185,62830,58703,54572,50445,13538,9411,5280,1153,29798,... - 25671,21540,17413,42971,47098,34713,38840,59231,63358,50973,55100,9939,14066,1681,5808,26199,... - 30326,17941,22068,55628,51565,63758,59695,39368,35305,47498,43435,22596,18533,30726,26663,6336,... - 2273,14466,10403,52093,56156,60223,64286,35833,39896,43963,48026,19061,23124,27191,31254,2801,6864,... - 10931,14994,64814,60687,56684,52557,48554,44427,40424,36297,31782,27655,23652,19525,15522,11395,... - 7392,3265,61215,65342,53085,57212,44955,49082,36825,40952,28183,32310,20053,24180,11923,16050,3793,7920]; - - ui16RetCRC16 = hex2dec('FFFF'); - for I=1:length(data) - ui8LookupTableIndex = bitxor(data(I),uint8(bitshift(ui16RetCRC16,-8))); - ui16RetCRC16 = bitxor(Crc_ui16LookupTable(double(ui8LookupTableIndex)+1),mod(bitshift(ui16RetCRC16,8),65536)); - end - crc=dec2hex(ui16RetCRC16); - -endfunction - - - - - - - - - - - - +% crc16.m +% +%The CRC calculation is based on following generator polynomial: +%G(x) = x16 + x12 + x5 + 1 +% +%The register initial value of the implementation is: 0xFFFF +% +%used data = string -> 1 2 3 4 5 6 7 8 9 +% +% Online calculator to check the script: +%http://www.lammertbies.nl/comm/info/crc-calculation.html +% +% + +function crc = crc16(data) + + % crc look up table + + Crc_ui16LookupTable=[0,4129,8258,12387,16516,20645,24774,28903,33032,37161,41290,45419,49548,... + 53677,57806,61935,4657,528,12915,8786,21173,17044,29431,25302,37689,33560,45947,41818,54205,... + 50076,62463,58334,9314,13379,1056,5121,25830,29895,17572,21637,42346,46411,34088,38153,58862,... + 62927,50604,54669,13907,9842,5649,1584,30423,26358,22165,18100,46939,42874,38681,34616,63455,... + 59390,55197,51132,18628,22757,26758,30887,2112,6241,10242,14371,51660,55789,59790,63919,35144,... + 39273,43274,47403,23285,19156,31415,27286,6769,2640,14899,10770,56317,52188,64447,60318,39801,... + 35672,47931,43802,27814,31879,19684,23749,11298,15363,3168,7233,60846,64911,52716,56781,44330,... + 48395,36200,40265,32407,28342,24277,20212,15891,11826,7761,3696,65439,61374,57309,53244,48923,... + 44858,40793,36728,37256,33193,45514,41451,53516,49453,61774,57711,4224,161,12482,8419,20484,... + 16421,28742,24679,33721,37784,41979,46042,49981,54044,58239,62302,689,4752,8947,13010,16949,... + 21012,25207,29270,46570,42443,38312,34185,62830,58703,54572,50445,13538,9411,5280,1153,29798,... + 25671,21540,17413,42971,47098,34713,38840,59231,63358,50973,55100,9939,14066,1681,5808,26199,... + 30326,17941,22068,55628,51565,63758,59695,39368,35305,47498,43435,22596,18533,30726,26663,6336,... + 2273,14466,10403,52093,56156,60223,64286,35833,39896,43963,48026,19061,23124,27191,31254,2801,6864,... + 10931,14994,64814,60687,56684,52557,48554,44427,40424,36297,31782,27655,23652,19525,15522,11395,... + 7392,3265,61215,65342,53085,57212,44955,49082,36825,40952,28183,32310,20053,24180,11923,16050,3793,7920]; + + ui16RetCRC16 = hex2dec('FFFF'); + for I=1:length(data) + ui8LookupTableIndex = bitxor(data(I),uint8(bitshift(ui16RetCRC16,-8))); + ui16RetCRC16 = bitxor(Crc_ui16LookupTable(double(ui8LookupTableIndex)+1),mod(bitshift(ui16RetCRC16,8),65536)); + end + crc=dec2hex(ui16RetCRC16); + +endfunction + + + + + + + + + + + + diff --git a/octave/ldpc_fsk_lib.m b/octave/ldpc_fsk_lib.m index 6b095056..fea8a978 100644 --- a/octave/ldpc_fsk_lib.m +++ b/octave/ldpc_fsk_lib.m @@ -1,269 +1,269 @@ -% lpdc_fsk_lib.m -% April 2015 -% -% Library version of ldpc4.m written by vk5dsp. Application is high bit rate -% balloon telemtry -% -% LDPC demo -% Call the CML routines and simulate one set of SNRs. -% This function is an updated version of ldpc3() which uses less -% of the CML functions -% -% sim_in the input parameter structure -% sim_out contains BERs and other stats for each value of SNR -% resfile is the result file -% - -1; - -function sim_out = ldpc5(sim_in, resfile, testmode, genie_Es, logging=0); - - if nargin<4, testmode = 0; end - estEsN0 = 0; - - HRA = sim_in.HRA; - framesize = sim_in.framesize; - rate = sim_in.rate; - mod_order = sim_in.mod_order; - - Lim_Ferrs = sim_in.Lim_Ferrs; - Ntrials = sim_in.Ntrials; - Esvec = sim_in.Esvec; - - demod_type = 0; - decoder_type = 0; - max_iterations = 100; - code_param = ldpc_init(HRA, mod_order); - bps = code_param.bits_per_symbol; - - - if (logging) - fod = fopen('decode.log', 'w'); - fwrite(fod, 'Es estEs Its secs \n'); - end - - - for ne = 1:length(Esvec) - Es = Esvec(ne); - EsNo = 10^(Es/10); - - - Terrs = 0; Tbits =0; Ferrs =0; - for nn = 1: Ntrials - - data = round( rand( 1, code_param.data_bits_per_frame ) ); - codeword = ldpc_encode(code_param, data); - - code_param.code_bits_per_frame = length( codeword ); - Nsymb = code_param.code_bits_per_frame/bps; - - if testmode==1 - f1 = fopen("dat_in2064.txt", "w"); - for k=1:length(data); fprintf(f1, "%u\n", data(k)); end - fclose(f1); - system("./ra_enc"); - - load("dat_op2064.txt"); - pbits = codeword(length(data)+1:end); % print these to compare with C code - dat_op2064(1:16)', pbits(1:16) - differences_in_parity = sum(abs(pbits - dat_op2064')) - pause; - end - - - % modulate - % s = Modulate( codeword, code_param.S_matrix ); - s= 1 - 2 * codeword; - code_param.symbols_per_frame = length( s ); - - variance = 1/(2*EsNo); - noise = sqrt(variance)* randn(1,code_param.symbols_per_frame); - % + j*randn(1,code_param.symbols_per_frame) ); - r = s + noise; - Nr = length(r); - - [detected_data Niters] = ldpc_decode(r, code_param, max_iterations, decoder_type); - - error_positions = xor( detected_data(1:code_param.data_bits_per_frame), data ); - Nerrs = sum( error_positions); - - t = clock; t = fix(t(5)*60+t(6)); - if (logging) - fprintf(fod, ' %3d %4d\n', Niters, t); - end - - if Nerrs>0, fprintf(1,'x'), else fprintf(1,'.'), end - if (rem(nn, 50)==0), fprintf(1,'\n'), end - - if Nerrs>0, Ferrs = Ferrs +1; end - Terrs = Terrs + Nerrs; - Tbits = Tbits + code_param.data_bits_per_frame; - - if Ferrs > Lim_Ferrs, disp(['exit loop with #cw errors = ' ... - num2str(Ferrs)]); break, end - end - - TERvec(ne) = Terrs; - FERvec(ne) = Ferrs; - BERvec(ne) = Terrs/ Tbits; - Ebvec = Esvec - 10*log10(code_param.bits_per_symbol * rate); - - cparams= [code_param.data_bits_per_frame code_param.symbols_per_frame ... - code_param.code_bits_per_frame]; - - sim_out.BERvec = BERvec; - sim_out.Ebvec = Ebvec; - sim_out.FERvec = FERvec; - sim_out.TERvec = TERvec; - sim_out.cpumins = cputime/60; - - if nargin > 2 - save(resfile, 'sim_in', 'sim_out', 'cparams'); - disp(['Saved results to ' resfile ' at Es =' num2str(Es) 'dB']); - end - end -end - - -function code_param = ldpc_init(HRA, mod_order) - code_param.bits_per_symbol = log2(mod_order); - [H_rows, H_cols] = Mat2Hrows(HRA); - code_param.H_rows = H_rows; - code_param.H_cols = H_cols; - code_param.P_matrix = []; - code_param.data_bits_per_frame = length(code_param.H_cols) - length( code_param.P_matrix ); - code_param.symbols_per_frame = length(HRA); -end - - -function codeword = ldpc_encode(code_param, data) - codeword = LdpcEncode( data, code_param.H_rows, code_param.P_matrix ); -endfunction - - -% Takes soft decision symbols (e.g. output of 2fsk demod) and converts -% them to LLRs. Note we calculate mean and var manually instead of -% using internal functions. This was required to get a bit exact -% results against the C code. - -function llr = sd_to_llr(sd) - sd = sd / mean(abs(sd)); - x = sd - sign(sd); - sumsq = sum(x.^2); - summ = sum(x); - mn = summ/length(sd); - estvar = sumsq/length(sd) - mn*mn; - estEsN0 = 1/(2* estvar + 1E-3); - llr = 4 * estEsN0 * sd; -endfunction - - -% LDPC decoder - note it estimates EsNo from received symbols - -function [detected_data Niters] = ldpc_decode(r, code_param, max_iterations, decoder_type) - % in the binary case the LLRs are just a scaled version of the rx samples .. - - #{ - r = r / mean(abs(r)); % scale for signal unity signal - estvar = var(r-sign(r)); - estEsN0 = 1/(2* estvar + 1E-3); - input_decoder_c = 4 * estEsN0 * r; - #} - llr = sd_to_llr(r); - - [x_hat, PCcnt] = MpDecode(llr, code_param.H_rows, code_param.H_cols, ... - max_iterations, decoder_type, 1, 1); - Niters = sum(PCcnt!=0); - detected_data = x_hat(Niters,:); - - if isfield(code_param, "c_include_file") - ldpc_gen_h_file(code_param, max_iterations, decoder_type, llr, x_hat, detected_data); - end -end - - -% One application of FSK LDPC work is SSTV. This function generates a -% simulated frame for testing - -function frame_rs232 = gen_sstv_frame - load('H2064_516_sparse.mat'); - HRA = full(HRA); - mod_order = 2; - code_param = ldpc_init(HRA, mod_order); - - % generate payload data bytes and checksum - - data = floor(rand(1,256)*256); - %data = zeros(1,256); - checksum = crc16(data); - data = [data hex2dec(checksum(3:4)) hex2dec(checksum(1:2))]; - - % unpack bytes to bits and LPDC encode - - mask = 2.^(7:-1:0); % MSB to LSB unpacking to match python tx code. - unpacked_data = []; - for b=1:length(data) - unpacked_data = [unpacked_data bitand(data(b), mask) > 0]; - end - codeword = [ldpc_encode(code_param, unpacked_data) 0 0 0 0]; % pad with 0s to get integer number of bytes - - % pack back into bytes to match python code - - lpacked_codeword = length(codeword)/8; - packed_codeword = zeros(1,lpacked_codeword); - for b=1:lpacked_codeword - st = (b-1)*8 + 1; - packed_codeword(b) = sum(codeword(st:st+7) .* mask); - end - - % generate header bits - - header = [hex2dec('55')*ones(1,16) hex2dec('ab') hex2dec('cd') hex2dec('ef') hex2dec('01')]; - - % now construct entire unpacked frame - - packed_frame = [header packed_codeword]; - mask = 2.^(0:7); % LSB to MSB packing for header - lpacked_frame = length(packed_frame); - frame = []; - for b=1:lpacked_frame - frame = [frame bitand(packed_frame(b), mask) > 0]; - end - - % insert rs232 framing bits - - frame_rs232 = []; - for b=1:8:length(frame) - frame_rs232 = [frame_rs232 0 frame(b:b+7) 1]; - end - - %printf("codeword: %d unpacked_header: %d frame: %d frame_rs232: %d \n", length(codeword), length(unpacked_header), length(frame), length(frame_rs232)); -endfunction - - -% calculates and compares the checksum of a SSTV frame, that has RS232 -% start and stop bits - -function checksum_ok = sstv_checksum(frame_rs232) - l = length(frame_rs232); - expected_l = (256+2)*10; - assert(l == expected_l); - - % extract rx bytes - - rx_data = zeros(1,256); - mask = 2.^(0:7); % LSB to MSB - k = 1; - for i=1:10:expected_l - rx_bits = frame_rs232(i+1:i+8); - rx_data(k) = sum(rx_bits .* mask); - k++; - end - - % calc rx checksum and extract tx checksum - - rx_checksum = crc16(rx_data(1:256)); - tx_checksum = sprintf("%02X%02X", rx_data(258), rx_data(257)); - %printf("tx_checksum: %s rx_checksum: %s\n", tx_checksum, rx_checksum); - checksum_ok = strcmp(tx_checksum, rx_checksum); -endfunction +% lpdc_fsk_lib.m +% April 2015 +% +% Library version of ldpc4.m written by vk5dsp. Application is high bit rate +% balloon telemtry +% +% LDPC demo +% Call the CML routines and simulate one set of SNRs. +% This function is an updated version of ldpc3() which uses less +% of the CML functions +% +% sim_in the input parameter structure +% sim_out contains BERs and other stats for each value of SNR +% resfile is the result file +% + +1; + +function sim_out = ldpc5(sim_in, resfile, testmode, genie_Es, logging=0); + + if nargin<4, testmode = 0; end + estEsN0 = 0; + + HRA = sim_in.HRA; + framesize = sim_in.framesize; + rate = sim_in.rate; + mod_order = sim_in.mod_order; + + Lim_Ferrs = sim_in.Lim_Ferrs; + Ntrials = sim_in.Ntrials; + Esvec = sim_in.Esvec; + + demod_type = 0; + decoder_type = 0; + max_iterations = 100; + code_param = ldpc_init(HRA, mod_order); + bps = code_param.bits_per_symbol; + + + if (logging) + fod = fopen('decode.log', 'w'); + fwrite(fod, 'Es estEs Its secs \n'); + end + + + for ne = 1:length(Esvec) + Es = Esvec(ne); + EsNo = 10^(Es/10); + + + Terrs = 0; Tbits =0; Ferrs =0; + for nn = 1: Ntrials + + data = round( rand( 1, code_param.data_bits_per_frame ) ); + codeword = ldpc_encode(code_param, data); + + code_param.code_bits_per_frame = length( codeword ); + Nsymb = code_param.code_bits_per_frame/bps; + + if testmode==1 + f1 = fopen("dat_in2064.txt", "w"); + for k=1:length(data); fprintf(f1, "%u\n", data(k)); end + fclose(f1); + system("./ra_enc"); + + load("dat_op2064.txt"); + pbits = codeword(length(data)+1:end); % print these to compare with C code + dat_op2064(1:16)', pbits(1:16) + differences_in_parity = sum(abs(pbits - dat_op2064')) + pause; + end + + + % modulate + % s = Modulate( codeword, code_param.S_matrix ); + s= 1 - 2 * codeword; + code_param.symbols_per_frame = length( s ); + + variance = 1/(2*EsNo); + noise = sqrt(variance)* randn(1,code_param.symbols_per_frame); + % + j*randn(1,code_param.symbols_per_frame) ); + r = s + noise; + Nr = length(r); + + [detected_data Niters] = ldpc_decode(r, code_param, max_iterations, decoder_type); + + error_positions = xor( detected_data(1:code_param.data_bits_per_frame), data ); + Nerrs = sum( error_positions); + + t = clock; t = fix(t(5)*60+t(6)); + if (logging) + fprintf(fod, ' %3d %4d\n', Niters, t); + end + + if Nerrs>0, fprintf(1,'x'), else fprintf(1,'.'), end + if (rem(nn, 50)==0), fprintf(1,'\n'), end + + if Nerrs>0, Ferrs = Ferrs +1; end + Terrs = Terrs + Nerrs; + Tbits = Tbits + code_param.data_bits_per_frame; + + if Ferrs > Lim_Ferrs, disp(['exit loop with #cw errors = ' ... + num2str(Ferrs)]); break, end + end + + TERvec(ne) = Terrs; + FERvec(ne) = Ferrs; + BERvec(ne) = Terrs/ Tbits; + Ebvec = Esvec - 10*log10(code_param.bits_per_symbol * rate); + + cparams= [code_param.data_bits_per_frame code_param.symbols_per_frame ... + code_param.code_bits_per_frame]; + + sim_out.BERvec = BERvec; + sim_out.Ebvec = Ebvec; + sim_out.FERvec = FERvec; + sim_out.TERvec = TERvec; + sim_out.cpumins = cputime/60; + + if nargin > 2 + save(resfile, 'sim_in', 'sim_out', 'cparams'); + disp(['Saved results to ' resfile ' at Es =' num2str(Es) 'dB']); + end + end +end + + +function code_param = ldpc_init(HRA, mod_order) + code_param.bits_per_symbol = log2(mod_order); + [H_rows, H_cols] = Mat2Hrows(HRA); + code_param.H_rows = H_rows; + code_param.H_cols = H_cols; + code_param.P_matrix = []; + code_param.data_bits_per_frame = length(code_param.H_cols) - length( code_param.P_matrix ); + code_param.symbols_per_frame = length(HRA); +end + + +function codeword = ldpc_encode(code_param, data) + codeword = LdpcEncode( data, code_param.H_rows, code_param.P_matrix ); +endfunction + + +% Takes soft decision symbols (e.g. output of 2fsk demod) and converts +% them to LLRs. Note we calculate mean and var manually instead of +% using internal functions. This was required to get a bit exact +% results against the C code. + +function llr = sd_to_llr(sd) + sd = sd / mean(abs(sd)); + x = sd - sign(sd); + sumsq = sum(x.^2); + summ = sum(x); + mn = summ/length(sd); + estvar = sumsq/length(sd) - mn*mn; + estEsN0 = 1/(2* estvar + 1E-3); + llr = 4 * estEsN0 * sd; +endfunction + + +% LDPC decoder - note it estimates EsNo from received symbols + +function [detected_data Niters] = ldpc_decode(r, code_param, max_iterations, decoder_type) + % in the binary case the LLRs are just a scaled version of the rx samples .. + + #{ + r = r / mean(abs(r)); % scale for signal unity signal + estvar = var(r-sign(r)); + estEsN0 = 1/(2* estvar + 1E-3); + input_decoder_c = 4 * estEsN0 * r; + #} + llr = sd_to_llr(r); + + [x_hat, PCcnt] = MpDecode(llr, code_param.H_rows, code_param.H_cols, ... + max_iterations, decoder_type, 1, 1); + Niters = sum(PCcnt!=0); + detected_data = x_hat(Niters,:); + + if isfield(code_param, "c_include_file") + ldpc_gen_h_file(code_param, max_iterations, decoder_type, llr, x_hat, detected_data); + end +end + + +% One application of FSK LDPC work is SSTV. This function generates a +% simulated frame for testing + +function frame_rs232 = gen_sstv_frame + load('H2064_516_sparse.mat'); + HRA = full(HRA); + mod_order = 2; + code_param = ldpc_init(HRA, mod_order); + + % generate payload data bytes and checksum + + data = floor(rand(1,256)*256); + %data = zeros(1,256); + checksum = crc16(data); + data = [data hex2dec(checksum(3:4)) hex2dec(checksum(1:2))]; + + % unpack bytes to bits and LPDC encode + + mask = 2.^(7:-1:0); % MSB to LSB unpacking to match python tx code. + unpacked_data = []; + for b=1:length(data) + unpacked_data = [unpacked_data bitand(data(b), mask) > 0]; + end + codeword = [ldpc_encode(code_param, unpacked_data) 0 0 0 0]; % pad with 0s to get integer number of bytes + + % pack back into bytes to match python code + + lpacked_codeword = length(codeword)/8; + packed_codeword = zeros(1,lpacked_codeword); + for b=1:lpacked_codeword + st = (b-1)*8 + 1; + packed_codeword(b) = sum(codeword(st:st+7) .* mask); + end + + % generate header bits + + header = [hex2dec('55')*ones(1,16) hex2dec('ab') hex2dec('cd') hex2dec('ef') hex2dec('01')]; + + % now construct entire unpacked frame + + packed_frame = [header packed_codeword]; + mask = 2.^(0:7); % LSB to MSB packing for header + lpacked_frame = length(packed_frame); + frame = []; + for b=1:lpacked_frame + frame = [frame bitand(packed_frame(b), mask) > 0]; + end + + % insert rs232 framing bits + + frame_rs232 = []; + for b=1:8:length(frame) + frame_rs232 = [frame_rs232 0 frame(b:b+7) 1]; + end + + %printf("codeword: %d unpacked_header: %d frame: %d frame_rs232: %d \n", length(codeword), length(unpacked_header), length(frame), length(frame_rs232)); +endfunction + + +% calculates and compares the checksum of a SSTV frame, that has RS232 +% start and stop bits + +function checksum_ok = sstv_checksum(frame_rs232) + l = length(frame_rs232); + expected_l = (256+2)*10; + assert(l == expected_l); + + % extract rx bytes + + rx_data = zeros(1,256); + mask = 2.^(0:7); % LSB to MSB + k = 1; + for i=1:10:expected_l + rx_bits = frame_rs232(i+1:i+8); + rx_data(k) = sum(rx_bits .* mask); + k++; + end + + % calc rx checksum and extract tx checksum + + rx_checksum = crc16(rx_data(1:256)); + tx_checksum = sprintf("%02X%02X", rx_data(258), rx_data(257)); + %printf("tx_checksum: %s rx_checksum: %s\n", tx_checksum, rx_checksum); + checksum_ok = strcmp(tx_checksum, rx_checksum); +endfunction diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fb10d287..735629de 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -81,7 +81,9 @@ else(CMAKE_CROSSCOMPILING) # Build code generator binaries. These do not get installed. # generate_codebook add_executable(generate_codebook generate_codebook.c) - target_link_libraries(generate_codebook m) + if(UNIX) + target_link_libraries(generate_codebook m) + endif() # Make native builds available for cross-compiling. export(TARGETS generate_codebook FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake) @@ -228,6 +230,7 @@ set(CODEC2_PUBLIC_HEADERS freedv_api.h reliable_text.h codec2_math.h + export.h ${CODEC2_VERSION_PATH}/version.h ) @@ -243,9 +246,14 @@ set(CODEC2_PUBLIC_HEADERS set(SOVERSION "${CODEC2_VERSION_MAJOR}.${CODEC2_VERSION_MINOR}") message(STATUS "codec2 version: ${CODEC2_VERSION}") add_library(codec2 ${CODEC2_SRCS}) + if(UNIX) target_link_libraries(codec2 PUBLIC m) endif(UNIX) +if(MSVC) + target_compile_definitions(codec2 PUBLIC _USE_MATH_DEFINES __STDC_NO_VLA__ CODEC2_LIBRARY_EXPORTS) +endif(MSVC) + if(LPCNET AND lpcnetfreedv_FOUND) target_link_libraries(codec2 PRIVATE lpcnetfreedv) endif() @@ -272,6 +280,7 @@ export(TARGETS codec2 FILE ${CMAKE_BINARY_DIR}/codec2.cmake ) +if(NOT MSVC) add_executable(c2enc c2enc.c) target_link_libraries(c2enc codec2) @@ -378,6 +387,7 @@ target_link_libraries(ldpc_enc codec2) add_executable(ldpc_dec ldpc_dec.c) target_link_libraries(ldpc_dec codec2) +endif() install(TARGETS codec2 EXPORT codec2-config LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib diff --git a/src/codec2.c b/src/codec2.c index d9c92699..edb7c958 100644 --- a/src/codec2.c +++ b/src/codec2.c @@ -1599,7 +1599,7 @@ float codec2_get_energy(struct CODEC2 *c2, const unsigned char *bits) { (CODEC2_MODE_ACTIVE(CODEC2_MODE_1200, c2->mode)) || (CODEC2_MODE_ACTIVE(CODEC2_MODE_700C, c2->mode))); MODEL model; - float xq_dec[2] = {}; + float xq_dec[2] = {0, 0}; int e_index, WoE_index; float e = 0.0f; unsigned int nbit; diff --git a/src/codec2.h b/src/codec2.h index d99f5f6e..199cd7a1 100644 --- a/src/codec2.h +++ b/src/codec2.h @@ -31,6 +31,8 @@ #include #include +#include "export.h" + #ifdef __cplusplus extern "C" { #endif @@ -82,36 +84,43 @@ extern "C" { struct CODEC2; -struct CODEC2 *codec2_create(int mode); -void codec2_destroy(struct CODEC2 *codec2_state); -void codec2_encode(struct CODEC2 *codec2_state, unsigned char bytes[], - short speech_in[]); -void codec2_decode(struct CODEC2 *codec2_state, short speech_out[], - const unsigned char bytes[]); -void codec2_decode_ber(struct CODEC2 *codec2_state, short speech_out[], - const unsigned char *bytes, float ber_est); -int codec2_samples_per_frame(struct CODEC2 *codec2_state); -int codec2_bits_per_frame(struct CODEC2 *codec2_state); -int codec2_bytes_per_frame(struct CODEC2 *codec2_state); - -void codec2_set_lpc_post_filter(struct CODEC2 *codec2_state, int enable, - int bass_boost, float beta, float gamma); -int codec2_get_spare_bit_index(struct CODEC2 *codec2_state); -int codec2_rebuild_spare_bit(struct CODEC2 *codec2_state, char unpacked_bits[]); -void codec2_set_natural_or_gray(struct CODEC2 *codec2_state, int gray); -void codec2_set_softdec(struct CODEC2 *c2, float *softdec); -float codec2_get_energy(struct CODEC2 *codec2_state, const unsigned char *bits); +CODEC2_API struct CODEC2 *codec2_create(int mode); +CODEC2_API void codec2_destroy(struct CODEC2 *codec2_state); +CODEC2_API void codec2_encode(struct CODEC2 *codec2_state, + unsigned char bytes[], short speech_in[]); +CODEC2_API void codec2_decode(struct CODEC2 *codec2_state, short speech_out[], + const unsigned char bytes[]); +CODEC2_API void codec2_decode_ber(struct CODEC2 *codec2_state, + short speech_out[], + const unsigned char *bytes, float ber_est); +CODEC2_API int codec2_samples_per_frame(struct CODEC2 *codec2_state); +CODEC2_API int codec2_bits_per_frame(struct CODEC2 *codec2_state); +CODEC2_API int codec2_bytes_per_frame(struct CODEC2 *codec2_state); + +CODEC2_API void codec2_set_lpc_post_filter(struct CODEC2 *codec2_state, + int enable, int bass_boost, + float beta, float gamma); +CODEC2_API int codec2_get_spare_bit_index(struct CODEC2 *codec2_state); +CODEC2_API int codec2_rebuild_spare_bit(struct CODEC2 *codec2_state, + char unpacked_bits[]); +CODEC2_API void codec2_set_natural_or_gray(struct CODEC2 *codec2_state, + int gray); +CODEC2_API void codec2_set_softdec(struct CODEC2 *c2, float *softdec); +CODEC2_API float codec2_get_energy(struct CODEC2 *codec2_state, + const unsigned char *bits); // support for ML and VQ experiments -void codec2_open_mlfeat(struct CODEC2 *codec2_state, char *feat_filename, - char *model_filename); -void codec2_load_codebook(struct CODEC2 *codec2_state, int num, char *filename); -float codec2_get_var(struct CODEC2 *codec2_state); -float *codec2_enable_user_ratek(struct CODEC2 *codec2_state, int *K); +CODEC2_API void codec2_open_mlfeat(struct CODEC2 *codec2_state, + char *feat_filename, char *model_filename); +CODEC2_API void codec2_load_codebook(struct CODEC2 *codec2_state, int num, + char *filename); +CODEC2_API float codec2_get_var(struct CODEC2 *codec2_state); +CODEC2_API float *codec2_enable_user_ratek(struct CODEC2 *codec2_state, + int *K); // 700C post filter and equaliser -void codec2_700c_post_filter(struct CODEC2 *codec2_state, bool en); -void codec2_700c_eq(struct CODEC2 *codec2_state, bool en); +CODEC2_API void codec2_700c_post_filter(struct CODEC2 *codec2_state, bool en); +CODEC2_API void codec2_700c_eq(struct CODEC2 *codec2_state, bool en); #ifdef __cplusplus } diff --git a/src/codec2_fdmdv.h b/src/codec2_fdmdv.h index 79e699db..a0c427b8 100644 --- a/src/codec2_fdmdv.h +++ b/src/codec2_fdmdv.h @@ -39,6 +39,7 @@ #define __FDMDV__ #include "comp.h" +#include "export.h" #include "modem_stats.h" #ifdef __cplusplus @@ -93,43 +94,44 @@ extern "C" { struct FDMDV; -struct FDMDV *fdmdv_create(int Nc); -void fdmdv_destroy(struct FDMDV *fdmdv_state); -void fdmdv_use_old_qpsk_mapping(struct FDMDV *fdmdv_state); -int fdmdv_bits_per_frame(struct FDMDV *fdmdv_state); -float fdmdv_get_fsep(struct FDMDV *fdmdv_state); -void fdmdv_set_fsep(struct FDMDV *fdmdv_state, float fsep); - -void fdmdv_mod(struct FDMDV *fdmdv_state, COMP tx_fdm[], int tx_bits[], - int *sync_bit); -void fdmdv_demod(struct FDMDV *fdmdv_state, int rx_bits[], - int *reliable_sync_bit, COMP rx_fdm[], int *nin); - -void fdmdv_get_test_bits(struct FDMDV *fdmdv_state, int tx_bits[]); -int fdmdv_error_pattern_size(struct FDMDV *fdmdv_state); -void fdmdv_put_test_bits(struct FDMDV *f, int *sync, short error_pattern[], - int *bit_errors, int *ntest_bits, int rx_bits[]); - -void fdmdv_get_demod_stats(struct FDMDV *fdmdv_state, - struct MODEM_STATS *stats); - -void fdmdv_8_to_16(float out16k[], float in8k[], int n); -void fdmdv_8_to_16_short(short out16k[], short in8k[], int n); -void fdmdv_16_to_8(float out8k[], float in16k[], int n); -void fdmdv_16_to_8_short(short out8k[], short in16k[], int n); -void fdmdv_8_to_48(float out48k[], float in8k[], int n); -void fdmdv_48_to_8(float out8k[], float in48k[], int n); -void fdmdv_8_to_48_short(short out48k[], short in8k[], int n); -void fdmdv_48_to_8_short(short out8k[], short in48k[], int n); - -void fdmdv_freq_shift(COMP rx_fdm_fcorr[], COMP rx_fdm[], float foff, - COMP *foff_phase_rect, int nin); +CODEC2_API struct FDMDV *fdmdv_create(int Nc); +CODEC2_API void fdmdv_destroy(struct FDMDV *fdmdv_state); +CODEC2_API void fdmdv_use_old_qpsk_mapping(struct FDMDV *fdmdv_state); +CODEC2_API int fdmdv_bits_per_frame(struct FDMDV *fdmdv_state); +CODEC2_API float fdmdv_get_fsep(struct FDMDV *fdmdv_state); +CODEC2_API void fdmdv_set_fsep(struct FDMDV *fdmdv_state, float fsep); + +CODEC2_API void fdmdv_mod(struct FDMDV *fdmdv_state, COMP tx_fdm[], + int tx_bits[], int *sync_bit); +CODEC2_API void fdmdv_demod(struct FDMDV *fdmdv_state, int rx_bits[], + int *reliable_sync_bit, COMP rx_fdm[], int *nin); + +CODEC2_API void fdmdv_get_test_bits(struct FDMDV *fdmdv_state, int tx_bits[]); +CODEC2_API int fdmdv_error_pattern_size(struct FDMDV *fdmdv_state); +CODEC2_API void fdmdv_put_test_bits(struct FDMDV *f, int *sync, + short error_pattern[], int *bit_errors, + int *ntest_bits, int rx_bits[]); + +CODEC2_API void fdmdv_get_demod_stats(struct FDMDV *fdmdv_state, + struct MODEM_STATS *stats); + +CODEC2_API void fdmdv_8_to_16(float out16k[], float in8k[], int n); +CODEC2_API void fdmdv_8_to_16_short(short out16k[], short in8k[], int n); +CODEC2_API void fdmdv_16_to_8(float out8k[], float in16k[], int n); +CODEC2_API void fdmdv_16_to_8_short(short out8k[], short in16k[], int n); +CODEC2_API void fdmdv_8_to_48(float out48k[], float in8k[], int n); +CODEC2_API void fdmdv_48_to_8(float out8k[], float in48k[], int n); +CODEC2_API void fdmdv_8_to_48_short(short out48k[], short in8k[], int n); +CODEC2_API void fdmdv_48_to_8_short(short out8k[], short in48k[], int n); + +CODEC2_API void fdmdv_freq_shift(COMP rx_fdm_fcorr[], COMP rx_fdm[], + float foff, COMP *foff_phase_rect, int nin); /* debug/development function(s) */ -void fdmdv_dump_osc_mags(struct FDMDV *f); -void fdmdv_simulate_channel(float *sig_pwr_av, COMP samples[], int nin, - float target_snr); +CODEC2_API void fdmdv_dump_osc_mags(struct FDMDV *f); +CODEC2_API void fdmdv_simulate_channel(float *sig_pwr_av, COMP samples[], + int nin, float target_snr); #ifdef __cplusplus } diff --git a/src/codec2_fifo.h b/src/codec2_fifo.h index c96f7857..20f4d29a 100644 --- a/src/codec2_fifo.h +++ b/src/codec2_fifo.h @@ -32,23 +32,25 @@ #ifndef __FIFO__ #define __FIFO__ +#include "export.h" + #ifdef __cplusplus extern "C" { #endif struct FIFO; -struct FIFO *codec2_fifo_create(int nshort); -struct FIFO *codec2_fifo_create_buf(int nshort, short *buf); -void codec2_fifo_destroy(struct FIFO *fifo); -int codec2_fifo_write(struct FIFO *fifo, short data[], int n); -int codec2_fifo_read(struct FIFO *fifo, short data[], int n); +CODEC2_API struct FIFO *codec2_fifo_create(int nshort); +CODEC2_API struct FIFO *codec2_fifo_create_buf(int nshort, short *buf); +CODEC2_API void codec2_fifo_destroy(struct FIFO *fifo); +CODEC2_API int codec2_fifo_write(struct FIFO *fifo, short data[], int n); +CODEC2_API int codec2_fifo_read(struct FIFO *fifo, short data[], int n); /* Return the number of bytes stored in the FIFO */ -int codec2_fifo_used(const struct FIFO *const fifo); +CODEC2_API int codec2_fifo_used(const struct FIFO *const fifo); /* Return the space available in the FIFO */ -int codec2_fifo_free(const struct FIFO *const fifo); +CODEC2_API int codec2_fifo_free(const struct FIFO *const fifo); #ifdef __cplusplus } diff --git a/src/codec2_fm.h b/src/codec2_fm.h index f61fc237..41f1d1cb 100644 --- a/src/codec2_fm.h +++ b/src/codec2_fm.h @@ -29,6 +29,7 @@ #define __CODEC2_FM__ #include "comp.h" +#include "export.h" struct FM { float Fs; /* setme: sample rate */ @@ -43,10 +44,11 @@ struct FM { COMP lo_phase; }; -struct FM *fm_create(int nsam); -void fm_destroy(struct FM *fm_states); -void fm_demod(struct FM *fm, float rx_out[], float rx[]); -void fm_mod(struct FM *fm, float tx_in[], float tx_out[]); -void fm_mod_comp(struct FM *fm_states, float tx_in[], COMP tx_out[]); +CODEC2_API struct FM *fm_create(int nsam); +CODEC2_API void fm_destroy(struct FM *fm_states); +CODEC2_API void fm_demod(struct FM *fm, float rx_out[], float rx[]); +CODEC2_API void fm_mod(struct FM *fm, float tx_in[], float tx_out[]); +CODEC2_API void fm_mod_comp(struct FM *fm_states, float tx_in[], + COMP tx_out[]); #endif diff --git a/src/codec2_ofdm.h b/src/codec2_ofdm.h index a56c740d..aed27941 100644 --- a/src/codec2_ofdm.h +++ b/src/codec2_ofdm.h @@ -34,6 +34,7 @@ #include #include "comp.h" +#include "export.h" #include "modem_stats.h" /* Defines */ @@ -62,45 +63,46 @@ struct OFDM; /* create and destroy modem states */ -struct OFDM *ofdm_create(const struct OFDM_CONFIG *config); -void ofdm_destroy(struct OFDM *); -void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config); +CODEC2_API struct OFDM *ofdm_create(const struct OFDM_CONFIG *config); +CODEC2_API void ofdm_destroy(struct OFDM *); +CODEC2_API void ofdm_init_mode(char mode[], struct OFDM_CONFIG *config); /* signal processing */ -void ofdm_mod(struct OFDM *, COMP *, const int *); -void ofdm_demod(struct OFDM *, int *, COMP *); -void ofdm_demod_shorts(struct OFDM *, int *, short *, float); -int ofdm_sync_search(struct OFDM *, COMP *); -int ofdm_sync_search_shorts(struct OFDM *, short *, float); -void ofdm_sync_state_machine(struct OFDM *, uint8_t *); -void ofdm_sync_state_machine2(struct OFDM *, uint8_t *); +CODEC2_API void ofdm_mod(struct OFDM *, COMP *, const int *); +CODEC2_API void ofdm_demod(struct OFDM *, int *, COMP *); +CODEC2_API void ofdm_demod_shorts(struct OFDM *, int *, short *, float); +CODEC2_API int ofdm_sync_search(struct OFDM *, COMP *); +CODEC2_API int ofdm_sync_search_shorts(struct OFDM *, short *, float); +CODEC2_API void ofdm_sync_state_machine(struct OFDM *, uint8_t *); +CODEC2_API void ofdm_sync_state_machine2(struct OFDM *, uint8_t *); /* getters */ -struct OFDM_CONFIG *ofdm_get_config_param(struct OFDM *ofdm); -int ofdm_get_nin(struct OFDM *); -int ofdm_get_samples_per_frame(struct OFDM *ofdm); -int ofdm_get_samples_per_packet(struct OFDM *ofdm); -int ofdm_get_max_samples_per_frame(struct OFDM *ofdm); -int ofdm_get_bits_per_frame(struct OFDM *ofdm); -int ofdm_get_bits_per_packet(struct OFDM *ofdm); -int ofdm_get_phase_est_bandwidth_mode(struct OFDM *ofdm); +CODEC2_API struct OFDM_CONFIG *ofdm_get_config_param(struct OFDM *ofdm); +CODEC2_API int ofdm_get_nin(struct OFDM *); +CODEC2_API int ofdm_get_samples_per_frame(struct OFDM *ofdm); +CODEC2_API int ofdm_get_samples_per_packet(struct OFDM *ofdm); +CODEC2_API int ofdm_get_max_samples_per_frame(struct OFDM *ofdm); +CODEC2_API int ofdm_get_bits_per_frame(struct OFDM *ofdm); +CODEC2_API int ofdm_get_bits_per_packet(struct OFDM *ofdm); +CODEC2_API int ofdm_get_phase_est_bandwidth_mode(struct OFDM *ofdm); /* option setters */ -void ofdm_set_verbose(struct OFDM *, int); -void ofdm_set_timing_enable(struct OFDM *, bool); -void ofdm_set_foff_est_enable(struct OFDM *, bool); -void ofdm_set_phase_est_enable(struct OFDM *, bool); -void ofdm_set_phase_est_bandwidth_mode(struct OFDM *ofdm, int val); -void ofdm_set_off_est_hz(struct OFDM *, float); -void ofdm_set_sync(struct OFDM *, int); -void ofdm_set_tx_bpf(struct OFDM *, bool); -void ofdm_set_dpsk(struct OFDM *ofdm, bool val); -void ofdm_set_packets_per_burst(struct OFDM *ofdm, int packetsperburst); - -void ofdm_print_info(struct OFDM *); +CODEC2_API void ofdm_set_verbose(struct OFDM *, int); +CODEC2_API void ofdm_set_timing_enable(struct OFDM *, bool); +CODEC2_API void ofdm_set_foff_est_enable(struct OFDM *, bool); +CODEC2_API void ofdm_set_phase_est_enable(struct OFDM *, bool); +CODEC2_API void ofdm_set_phase_est_bandwidth_mode(struct OFDM *ofdm, int val); +CODEC2_API void ofdm_set_off_est_hz(struct OFDM *, float); +CODEC2_API void ofdm_set_sync(struct OFDM *, int); +CODEC2_API void ofdm_set_tx_bpf(struct OFDM *, bool); +CODEC2_API void ofdm_set_dpsk(struct OFDM *ofdm, bool val); +CODEC2_API void ofdm_set_packets_per_burst(struct OFDM *ofdm, + int packetsperburst); + +CODEC2_API void ofdm_print_info(struct OFDM *); #ifdef __cplusplus } diff --git a/src/cohpsk.c b/src/cohpsk.c index d5f73593..68e58c9f 100644 --- a/src/cohpsk.c +++ b/src/cohpsk.c @@ -30,7 +30,6 @@ INCLUDES \*---------------------------------------------------------------------------*/ - #include #include #include @@ -313,8 +312,8 @@ void qpsk_symbols_to_bits(struct COHPSK *coh, float rx_bits[], COMP y[NPILOTSFRAME + 2], yfit; COMP rx_symb_linear[NSYMROW * COHPSK_NC * COHPSK_ND]; COMP m, b; - COMP __attribute__((unused)) corr, rot, pi_on_4, phi_rect, div_symb; - float mag, __attribute__((unused)) phi_, __attribute__((unused)) amp_; + COMP corr, rot, pi_on_4, phi_rect, div_symb; + float mag, phi_, amp_; float sum_x, sum_xx, noise_var; float spi_4 = M_PI / 4.0f; COMP s; diff --git a/src/comp_prim.h b/src/comp_prim.h index 33f712d7..5099e0ae 100644 --- a/src/comp_prim.h +++ b/src/comp_prim.h @@ -117,7 +117,7 @@ inline static COMP comp(float re, float im) { /* * Quick and easy complex 0 */ -inline static COMP comp0() { +inline static COMP comp0(void) { return comp(0.f, 0.f); // } diff --git a/src/defines.h b/src/defines.h index e4cbdc6d..41f7db1f 100644 --- a/src/defines.h +++ b/src/defines.h @@ -36,7 +36,7 @@ /* VLA workaround */ -#if __STDC_NO_VLA__ | 1 +#if defined(__STDC_NO_VLA__) || defined(_MSC_VER) #include "stdlib.h" #include "string.h" diff --git a/src/export.h b/src/export.h new file mode 100644 index 00000000..6e5f0aa2 --- /dev/null +++ b/src/export.h @@ -0,0 +1,14 @@ +#ifndef CODEC2_EXPORT_H +#define CODEC2_EXPORT_H + +#if defined(_MSC_VER) +#ifdef CODEC2_LIBRARY_EXPORTS +#define CODEC2_API __declspec(dllexport) +#else +#define CODEC2_API __declspec(dllimport) +#endif +#else +#define CODEC2_API +#endif + +#endif // CODEC2_EXPORT_H diff --git a/src/freedv_api.c b/src/freedv_api.c index 50f7af9c..6b0667f7 100644 --- a/src/freedv_api.c +++ b/src/freedv_api.c @@ -1593,7 +1593,7 @@ void freedv_get_modem_extended_stats(struct freedv *f, // different function // TODO we need a better design here: Issue #182 #ifndef __EMBEDDED__ - size_t ncopy = (void *)stats->rx_eye - (void *)stats; + size_t ncopy = (char *)stats->rx_eye - (char *)stats; memcpy(stats, &f->stats, ncopy); #endif stats->snr_est = f->snr_est; diff --git a/src/freedv_api.h b/src/freedv_api.h index ce95a559..afd9fa8c 100644 --- a/src/freedv_api.h +++ b/src/freedv_api.h @@ -38,6 +38,7 @@ #include // This declares a single-precision (float) complex number #include "comp.h" +#include "export.h" #ifdef __cplusplus extern "C" { @@ -191,144 +192,164 @@ typedef void (*freedv_callback_datatx)(void *, unsigned char *packet, // open, close ---------------------------------------------------------------- -struct freedv *freedv_open_advanced(int mode, struct freedv_advanced *adv); -struct freedv *freedv_open(int mode); -void freedv_close(struct freedv *freedv); +CODEC2_API struct freedv *freedv_open_advanced(int mode, + struct freedv_advanced *adv); +CODEC2_API struct freedv *freedv_open(int mode); +CODEC2_API void freedv_close(struct freedv *freedv); // Transmit ------------------------------------------------------------------- -void freedv_tx(struct freedv *freedv, short mod_out[], short speech_in[]); -void freedv_comptx(struct freedv *freedv, COMP mod_out[], short speech_in[]); -void freedv_datatx(struct freedv *f, short mod_out[]); -int freedv_data_ntxframes(struct freedv *freedv); -void freedv_rawdatatx(struct freedv *f, short mod_out[], - unsigned char *packed_payload_bits); -void freedv_rawdatacomptx(struct freedv *f, COMP mod_out[], - unsigned char *packed_payload_bits); -int freedv_rawdatapreambletx(struct freedv *f, short mod_out[]); -int freedv_rawdatapreamblecomptx(struct freedv *f, COMP mod_out[]); -int freedv_rawdatapostambletx(struct freedv *f, short mod_out[]); -int freedv_rawdatapostamblecomptx(struct freedv *f, COMP mod_out[]); +CODEC2_API void freedv_tx(struct freedv *freedv, short mod_out[], + short speech_in[]); +CODEC2_API void freedv_comptx(struct freedv *freedv, COMP mod_out[], + short speech_in[]); +CODEC2_API void freedv_datatx(struct freedv *f, short mod_out[]); +CODEC2_API int freedv_data_ntxframes(struct freedv *freedv); +CODEC2_API void freedv_rawdatatx(struct freedv *f, short mod_out[], + unsigned char *packed_payload_bits); +CODEC2_API void freedv_rawdatacomptx(struct freedv *f, COMP mod_out[], + unsigned char *packed_payload_bits); +CODEC2_API int freedv_rawdatapreambletx(struct freedv *f, short mod_out[]); +CODEC2_API int freedv_rawdatapreamblecomptx(struct freedv *f, COMP mod_out[]); +CODEC2_API int freedv_rawdatapostambletx(struct freedv *f, short mod_out[]); +CODEC2_API int freedv_rawdatapostamblecomptx(struct freedv *f, COMP mod_out[]); // Receive ------------------------------------------------------------------- -int freedv_nin(struct freedv *freedv); -int freedv_rx(struct freedv *freedv, short speech_out[], short demod_in[]); -int freedv_shortrx(struct freedv *freedv, short speech_out[], short demod_in[], - float gain); -int freedv_floatrx(struct freedv *freedv, short speech_out[], float demod_in[]); -int freedv_comprx(struct freedv *freedv, short speech_out[], COMP demod_in[]); -int freedv_rawdatarx(struct freedv *freedv, unsigned char *packed_payload_bits, - short demod_in[]); -int freedv_rawdatacomprx(struct freedv *freedv, - unsigned char *packed_payload_bits, COMP demod_in[]); +CODEC2_API int freedv_nin(struct freedv *freedv); +CODEC2_API int freedv_rx(struct freedv *freedv, short speech_out[], + short demod_in[]); +CODEC2_API int freedv_shortrx(struct freedv *freedv, short speech_out[], + short demod_in[], float gain); +CODEC2_API int freedv_floatrx(struct freedv *freedv, short speech_out[], + float demod_in[]); +CODEC2_API int freedv_comprx(struct freedv *freedv, short speech_out[], + COMP demod_in[]); +CODEC2_API int freedv_rawdatarx(struct freedv *freedv, + unsigned char *packed_payload_bits, + short demod_in[]); +CODEC2_API int freedv_rawdatacomprx(struct freedv *freedv, + unsigned char *packed_payload_bits, + COMP demod_in[]); // Helper functions // ------------------------------------------------------------------- -int freedv_codec_frames_from_rawdata(struct freedv *freedv, - unsigned char *codec_frames, - unsigned char *rawdata); -int freedv_rawdata_from_codec_frames(struct freedv *freedv, - unsigned char *rawdata, - unsigned char *codec_frames); -unsigned short freedv_gen_crc16(unsigned char *bytes, int nbytes); -void freedv_pack(unsigned char *bytes, unsigned char *bits, int nbits); -void freedv_unpack(unsigned char *bits, unsigned char *bytes, int nbits); -unsigned short freedv_crc16_unpacked(unsigned char *bits, int nbits); -int freedv_check_crc16_unpacked(unsigned char *unpacked_bits, int nbits); +CODEC2_API int freedv_codec_frames_from_rawdata(struct freedv *freedv, + unsigned char *codec_frames, + unsigned char *rawdata); +CODEC2_API int freedv_rawdata_from_codec_frames(struct freedv *freedv, + unsigned char *rawdata, + unsigned char *codec_frames); +CODEC2_API unsigned short freedv_gen_crc16(unsigned char *bytes, int nbytes); +CODEC2_API void freedv_pack(unsigned char *bytes, unsigned char *bits, + int nbits); +CODEC2_API void freedv_unpack(unsigned char *bits, unsigned char *bytes, + int nbits); +CODEC2_API unsigned short freedv_crc16_unpacked(unsigned char *bits, + int nbits); +CODEC2_API int freedv_check_crc16_unpacked(unsigned char *unpacked_bits, + int nbits); // Set parameters ------------------------------------------------------------ -void freedv_set_callback_txt(struct freedv *freedv, freedv_callback_rx rx, - freedv_callback_tx tx, void *callback_state); -void freedv_set_callback_protocol(struct freedv *freedv, - freedv_callback_protorx rx, - freedv_callback_prototx tx, - void *callback_state); -void freedv_set_callback_data(struct freedv *freedv, - freedv_callback_datarx datarx, - freedv_callback_datatx datatx, - void *callback_state); -void freedv_set_test_frames(struct freedv *freedv, int test_frames); -void freedv_set_test_frames_diversity(struct freedv *freedv, - int test_frames_diversity); -void freedv_set_smooth_symbols(struct freedv *freedv, int smooth_symbols); -void freedv_set_squelch_en(struct freedv *freedv, bool squelch_en); -void freedv_set_snr_squelch_thresh(struct freedv *freedv, - float snr_squelch_thresh); -void freedv_set_clip(struct freedv *freedv, bool val); -void freedv_set_total_bit_errors(struct freedv *freedv, int val); -void freedv_set_total_bits(struct freedv *freedv, int val); -void freedv_set_total_bit_errors_coded(struct freedv *freedv, int val); -void freedv_set_total_bits_coded(struct freedv *freedv, int val); -void freedv_set_total_packets(struct freedv *freedv, int val); -void freedv_set_total_packet_errors(struct freedv *freedv, int val); -void freedv_set_callback_error_pattern(struct freedv *freedv, - freedv_calback_error_pattern cb, - void *state); -void freedv_set_varicode_code_num(struct freedv *freedv, int val); -void freedv_set_data_header(struct freedv *freedv, unsigned char *header); -void freedv_set_carrier_ampl(struct freedv *freedv, int c, float ampl); -void freedv_set_sync(struct freedv *freedv, int sync_cmd); -void freedv_set_verbose(struct freedv *freedv, int verbosity); -void freedv_set_tx_bpf(struct freedv *freedv, int val); -void freedv_set_tx_amp(struct freedv *freedv, float amp); -void freedv_set_ext_vco(struct freedv *f, int val); -void freedv_set_phase_est_bandwidth_mode(struct freedv *f, int val); -void freedv_set_eq(struct freedv *f, bool val); -void freedv_set_frames_per_burst(struct freedv *f, int framesperburst); -void freedv_passthrough_gain(struct freedv *f, float g); -int freedv_set_tuning_range(struct freedv *freedv, float val_fmin, - float val_fmax); +CODEC2_API void freedv_set_callback_txt(struct freedv *freedv, + freedv_callback_rx rx, + freedv_callback_tx tx, + void *callback_state); +CODEC2_API void freedv_set_callback_protocol(struct freedv *freedv, + freedv_callback_protorx rx, + freedv_callback_prototx tx, + void *callback_state); +CODEC2_API void freedv_set_callback_data(struct freedv *freedv, + freedv_callback_datarx datarx, + freedv_callback_datatx datatx, + void *callback_state); +CODEC2_API void freedv_set_test_frames(struct freedv *freedv, int test_frames); +CODEC2_API void freedv_set_test_frames_diversity(struct freedv *freedv, + int test_frames_diversity); +CODEC2_API void freedv_set_smooth_symbols(struct freedv *freedv, + int smooth_symbols); +CODEC2_API void freedv_set_squelch_en(struct freedv *freedv, bool squelch_en); +CODEC2_API void freedv_set_snr_squelch_thresh(struct freedv *freedv, + float snr_squelch_thresh); +CODEC2_API void freedv_set_clip(struct freedv *freedv, bool val); +CODEC2_API void freedv_set_total_bit_errors(struct freedv *freedv, int val); +CODEC2_API void freedv_set_total_bits(struct freedv *freedv, int val); +CODEC2_API void freedv_set_total_bit_errors_coded(struct freedv *freedv, + int val); +CODEC2_API void freedv_set_total_bits_coded(struct freedv *freedv, int val); +CODEC2_API void freedv_set_total_packets(struct freedv *freedv, int val); +CODEC2_API void freedv_set_total_packet_errors(struct freedv *freedv, int val); +CODEC2_API void freedv_set_callback_error_pattern( + struct freedv *freedv, freedv_calback_error_pattern cb, void *state); +CODEC2_API void freedv_set_varicode_code_num(struct freedv *freedv, int val); +CODEC2_API void freedv_set_data_header(struct freedv *freedv, + unsigned char *header); +CODEC2_API void freedv_set_carrier_ampl(struct freedv *freedv, int c, + float ampl); +CODEC2_API void freedv_set_sync(struct freedv *freedv, int sync_cmd); +CODEC2_API void freedv_set_verbose(struct freedv *freedv, int verbosity); +CODEC2_API void freedv_set_tx_bpf(struct freedv *freedv, int val); +CODEC2_API void freedv_set_tx_amp(struct freedv *freedv, float amp); +CODEC2_API void freedv_set_ext_vco(struct freedv *f, int val); +CODEC2_API void freedv_set_phase_est_bandwidth_mode(struct freedv *f, int val); +CODEC2_API void freedv_set_eq(struct freedv *f, bool val); +CODEC2_API void freedv_set_frames_per_burst(struct freedv *f, + int framesperburst); +CODEC2_API void freedv_passthrough_gain(struct freedv *f, float g); +CODEC2_API int freedv_set_tuning_range(struct freedv *freedv, float val_fmin, + float val_fmax); // Get parameters // ------------------------------------------------------------------------- struct MODEM_STATS; -int freedv_get_version(void); -char *freedv_get_hash(void); -int freedv_get_mode(struct freedv *freedv); -void freedv_get_modem_stats(struct freedv *freedv, int *sync, float *snr_est); -void freedv_get_modem_extended_stats(struct freedv *freedv, - struct MODEM_STATS *stats); -int freedv_get_test_frames(struct freedv *freedv); - -int freedv_get_speech_sample_rate(struct freedv *freedv); -int freedv_get_n_speech_samples(struct freedv *freedv); -int freedv_get_n_max_speech_samples(struct freedv *freedv); - -int freedv_get_modem_sample_rate(struct freedv *freedv); -int freedv_get_modem_symbol_rate(struct freedv *freedv); -int freedv_get_n_max_modem_samples(struct freedv *freedv); -int freedv_get_n_nom_modem_samples(struct freedv *freedv); -int freedv_get_n_tx_modem_samples(struct freedv *freedv); -int freedv_get_n_tx_preamble_modem_samples(struct freedv *freedv); -int freedv_get_n_tx_postamble_modem_samples(struct freedv *freedv); +CODEC2_API int freedv_get_version(void); +CODEC2_API char *freedv_get_hash(void); +CODEC2_API int freedv_get_mode(struct freedv *freedv); +CODEC2_API void freedv_get_modem_stats(struct freedv *freedv, int *sync, + float *snr_est); +CODEC2_API void freedv_get_modem_extended_stats(struct freedv *freedv, + struct MODEM_STATS *stats); +CODEC2_API int freedv_get_test_frames(struct freedv *freedv); + +CODEC2_API int freedv_get_speech_sample_rate(struct freedv *freedv); +CODEC2_API int freedv_get_n_speech_samples(struct freedv *freedv); +CODEC2_API int freedv_get_n_max_speech_samples(struct freedv *freedv); + +CODEC2_API int freedv_get_modem_sample_rate(struct freedv *freedv); +CODEC2_API int freedv_get_modem_symbol_rate(struct freedv *freedv); +CODEC2_API int freedv_get_n_max_modem_samples(struct freedv *freedv); +CODEC2_API int freedv_get_n_nom_modem_samples(struct freedv *freedv); +CODEC2_API int freedv_get_n_tx_modem_samples(struct freedv *freedv); +CODEC2_API int freedv_get_n_tx_preamble_modem_samples(struct freedv *freedv); +CODEC2_API int freedv_get_n_tx_postamble_modem_samples(struct freedv *freedv); // bit error rate stats -int freedv_get_total_bits(struct freedv *freedv); -int freedv_get_total_bit_errors(struct freedv *freedv); -int freedv_get_total_bits_coded(struct freedv *freedv); -int freedv_get_total_bit_errors_coded(struct freedv *freedv); -int freedv_get_total_packets(struct freedv *freedv); -int freedv_get_total_packet_errors(struct freedv *freedv); +CODEC2_API int freedv_get_total_bits(struct freedv *freedv); +CODEC2_API int freedv_get_total_bit_errors(struct freedv *freedv); +CODEC2_API int freedv_get_total_bits_coded(struct freedv *freedv); +CODEC2_API int freedv_get_total_bit_errors_coded(struct freedv *freedv); +CODEC2_API int freedv_get_total_packets(struct freedv *freedv); +CODEC2_API int freedv_get_total_packet_errors(struct freedv *freedv); -int freedv_get_rx_status(struct freedv *freedv); -void freedv_get_fsk_S_and_N(struct freedv *freedv, float *S, float *N); +CODEC2_API int freedv_get_rx_status(struct freedv *freedv); +CODEC2_API void freedv_get_fsk_S_and_N(struct freedv *freedv, float *S, + float *N); -int freedv_get_sync(struct freedv *freedv); -int freedv_get_sync_interleaver(struct freedv *freedv); +CODEC2_API int freedv_get_sync(struct freedv *freedv); +CODEC2_API int freedv_get_sync_interleaver(struct freedv *freedv); // access to speech codec states -struct FSK *freedv_get_fsk(struct freedv *f); -struct CODEC2 *freedv_get_codec2(struct freedv *freedv); +CODEC2_API struct FSK *freedv_get_fsk(struct freedv *f); +CODEC2_API struct CODEC2 *freedv_get_codec2(struct freedv *freedv); -int freedv_get_bits_per_codec_frame(struct freedv *freedv); -int freedv_get_bits_per_modem_frame(struct freedv *freedv); -int freedv_get_sz_error_pattern(struct freedv *freedv); -int freedv_get_protocol_bits(struct freedv *freedv); +CODEC2_API int freedv_get_bits_per_codec_frame(struct freedv *freedv); +CODEC2_API int freedv_get_bits_per_modem_frame(struct freedv *freedv); +CODEC2_API int freedv_get_sz_error_pattern(struct freedv *freedv); +CODEC2_API int freedv_get_protocol_bits(struct freedv *freedv); #ifdef __cplusplus } diff --git a/src/freedv_api_internal.h b/src/freedv_api_internal.h index fd8c134a..6271cec1 100644 --- a/src/freedv_api_internal.h +++ b/src/freedv_api_internal.h @@ -188,8 +188,7 @@ struct freedv { char (*freedv_get_next_tx_char)(void *callback_state); void (*freedv_put_next_rx_char)(void *callback_state, char c); - void (*freedv_put_next_rx_symbol)(void *callback_state, COMP sym, - float amp); + void (*freedv_put_next_rx_symbol)(void *callback_state, COMP sym, float amp); void *callback_state; void *callback_state_sym; diff --git a/src/fsk.h b/src/fsk.h index 1b4dfdc8..3ff5d018 100644 --- a/src/fsk.h +++ b/src/fsk.h @@ -32,6 +32,7 @@ octave/fsk_horus.m #include #include "comp.h" +#include "export.h" #include "kiss_fftr.h" #include "modem_stats.h" @@ -114,7 +115,8 @@ struct FSK { * int tone_spacing - frequency spacing (for modulator and optional "mask" freq * estimator) */ -struct FSK *fsk_create(int Fs, int Rs, int M, int f1_tx, int tone_spacing); +CODEC2_API struct FSK *fsk_create(int Fs, int Rs, int M, int f1_tx, + int tone_spacing); /* * Create a FSK modem - advanced version @@ -128,31 +130,32 @@ struct FSK *fsk_create(int Fs, int Rs, int M, int f1_tx, int tone_spacing); * int tone_spacing - frequency spacing (for modulator and optional "mask" freq * estimator) */ -struct FSK *fsk_create_hbr(int Fs, int Rs, int M, int P, int Nsym, int f1_tx, - int tone_spacing); +CODEC2_API struct FSK *fsk_create_hbr(int Fs, int Rs, int M, int P, int Nsym, + int f1_tx, int tone_spacing); /* * Set the minimum and maximum frequencies at which the freq. estimator can find * tones */ -void fsk_set_freq_est_limits(struct FSK *fsk, int fmin, int fmax); +CODEC2_API void fsk_set_freq_est_limits(struct FSK *fsk, int fmin, int fmax); /* * Clear the estimator states */ -void fsk_clear_estimators(struct FSK *fsk); +CODEC2_API void fsk_clear_estimators(struct FSK *fsk); /* * Fills MODEM_STATS struct with demod statistics */ -void fsk_get_demod_stats(struct FSK *fsk, struct MODEM_STATS *stats); +CODEC2_API void fsk_get_demod_stats(struct FSK *fsk, + struct MODEM_STATS *stats); /* * Destroy an FSK state struct and free it's memory * * struct FSK *fsk - FSK config/state struct to be destroyed */ -void fsk_destroy(struct FSK *fsk); +CODEC2_API void fsk_destroy(struct FSK *fsk); /* * Modulates Nsym bits into N samples @@ -162,7 +165,8 @@ void fsk_destroy(struct FSK *fsk); * fsk->Ts*(nbits/(M>>1)) in length uint8_t tx_bits[] - Buffer containing Nbits * unpacked bits int nbits - number of bits to transmit */ -void fsk_mod(struct FSK *fsk, float fsk_out[], uint8_t tx_bits[], int nbits); +CODEC2_API void fsk_mod(struct FSK *fsk, float fsk_out[], uint8_t tx_bits[], + int nbits); /* * Modulates Nsym bits into N samples @@ -174,8 +178,8 @@ void fsk_mod(struct FSK *fsk, float fsk_out[], uint8_t tx_bits[], int nbits); * uint8_t tx_bits[] - Buffer containing Nbits unpacked bits * int nbits - number of bits to transmit */ -void fsk_mod_ext_vco(struct FSK *fsk, float vco_out[], uint8_t tx_bits[], - int nbits); +CODEC2_API void fsk_mod_ext_vco(struct FSK *fsk, float vco_out[], + uint8_t tx_bits[], int nbits); /* * Modulates Nsym bits into N complex samples @@ -185,7 +189,8 @@ void fsk_mod_ext_vco(struct FSK *fsk, float vco_out[], uint8_t tx_bits[], * fsk->Ts*(nbits/(M>>1)) in length uint8_t tx_bits[] - Buffer containing Nbits * unpacked bits int nbits - number of bits to transmit */ -void fsk_mod_c(struct FSK *fsk, COMP fsk_out[], uint8_t tx_bits[], int nbits); +CODEC2_API void fsk_mod_c(struct FSK *fsk, COMP fsk_out[], uint8_t tx_bits[], + int nbits); /* * Returns the number of samples needed for the next fsk_demod() cycle @@ -193,7 +198,7 @@ void fsk_mod_c(struct FSK *fsk, COMP fsk_out[], uint8_t tx_bits[], int nbits); * struct FSK *fsk - FSK config/state struct, set up by fsk_create * returns - number of samples to be fed into fsk_demod next cycle */ -uint32_t fsk_nin(struct FSK *fsk); +CODEC2_API uint32_t fsk_nin(struct FSK *fsk); /* * Demodulate some number of FSK samples. The number of samples to be @@ -203,7 +208,7 @@ uint32_t fsk_nin(struct FSK *fsk); * uint8_t rx_bits[] - Buffer for fsk->Nbits unpacked bits to be written * float fsk_in[] - nin samples of modulated FSK */ -void fsk_demod(struct FSK *fsk, uint8_t rx_bits[], COMP fsk_in[]); +CODEC2_API void fsk_demod(struct FSK *fsk, uint8_t rx_bits[], COMP fsk_in[]); /* * Soft decision demodulation @@ -212,17 +217,17 @@ void fsk_demod(struct FSK *fsk, uint8_t rx_bits[], COMP fsk_in[]); * float rx_flit[] - M x Nsym array of filtermagnitude outputs * float fsk_in[] - nin samples of modualted FSK */ -void fsk_demod_sd(struct FSK *fsk, float rx_filt[], COMP fsk_in[]); +CODEC2_API void fsk_demod_sd(struct FSK *fsk, float rx_filt[], COMP fsk_in[]); /* enables/disables normalisation of eye diagram samples */ -void fsk_stats_normalise_eye(struct FSK *fsk, int normalise_enable); +CODEC2_API void fsk_stats_normalise_eye(struct FSK *fsk, int normalise_enable); /* Set the FSK modem into burst demod mode */ -void fsk_enable_burst_mode(struct FSK *fsk); +CODEC2_API void fsk_enable_burst_mode(struct FSK *fsk); /* Set freq est algorithm 0: peak 1:mask */ -void fsk_set_freq_est_alg(struct FSK *fsk, int est_type); +CODEC2_API void fsk_set_freq_est_alg(struct FSK *fsk, int est_type); #endif diff --git a/src/ldpc_dec_test.c b/src/ldpc_dec_test.c index 9ba63b00..28703315 100644 --- a/src/ldpc_dec_test.c +++ b/src/ldpc_dec_test.c @@ -1,374 +1,374 @@ -/* - FILE...: ldpc_dec.c - AUTHOR.: Matthew C. Valenti, Rohit Iyer Seshadri, David Rowe - CREATED: Sep 2016 - - Command line C LDPC decoder derived from MpDecode.c in the CML - library. Allows us to run the same decoder in Octave and C. The - code is defined by the parameters and array stored in the include - file below, which can be machine generated from the Octave function - ldpc_fsk_lib.m:ldpc_decode() - - The include file also contains test input/output vectors for the LDPC - decoder for testing this program. - - Build: - - $ gcc -O2 -o ldpc_dec ldpc_dec.c mpdecode_core.c -Wall -lm -g - - Note: -O2 option was required to get identical results to MpDecode, - which is also compiled with -O2. Without it the number of bit errors - between C and Octave was different, especially when the code did - not converge and hit max_iters. - -*/ - -#include -#include -#include -#include -#include -#include - -#include "mpdecode_core_test.h" -#include "ofdm_internal.h" - -/* Machine generated consts, H_rows, H_cols, test input/output data to - change LDPC code regenerate this file. */ - -/* TODO: Better octave/C support for multuple codes */ - -#include "H2064_516_sparse_test.h" -#include "HRA_112_112_test.h" - -int opt_exists(char *argv[], int argc, char opt[]) { - int i; - for (i = 0; i < argc; i++) { - if (strcmp(argv[i], opt) == 0) { - return i; - } - } - return 0; -} - -int main(int argc, char *argv[]) { - int CodeLength, NumberParityBits; - int i, r, num_ok, num_runs, codename, parityCheckCount, mute; - int state, next_state, hframe, testframes; - // int frame; - int data_bits_per_frame; - char *adetected_data; - struct LDPC ldpc; - float *ainput; - int iter, total_iters; - int Tbits, Terrs, Tbits_raw, Terrs_raw; - - if (argc < 2) { - fprintf(stderr, "\n"); - fprintf(stderr, "usage: %s --test [--code CodeName]\n\n", argv[0]); - fprintf(stderr, " Run internal self test and print code parameters.\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "usage: %s --listcodes\n\n", argv[0]); - fprintf(stderr, - " List supported codes (more can be added via using Octave ldpc " - "scripts)\n"); - fprintf(stderr, "\n"); - fprintf(stderr, - "usage: %s InOneSymbolPerDouble OutOneBitPerByte [--sd] [--half] " - "[--code CodeName] [--testframes]\n\n", - argv[0]); - fprintf(stderr, - " InOneSymbolPerDouble Input file of double LLRs, use - for " - "the \n"); - fprintf(stderr, - " file names to use stdin/stdout\n"); - fprintf(stderr, " --code Use LDPC code CodeName\n"); - fprintf(stderr, " --listcodes List available LDPC codes\n"); - fprintf(stderr, - " --sd Treat input file samples as Soft " - "Decision\n"); - fprintf(stderr, - " demod outputs rather than LLRs\n"); - fprintf(stderr, - " --half Load framesize/2 input samples for " - "each decode\n"); - fprintf(stderr, - " attempt, only output decoded bits\n"); - fprintf(stderr, - " converges. Form of frame sync.\n"); - fprintf(stderr, - " --mute Only output frames with < 10%% parity " - "check fails\n"); - fprintf(stderr, - " --testframes built in test frame modem, requires " - "--testframes at encoder\n"); - fprintf(stderr, "\n"); - - fprintf(stderr, "Example in testframe mode:\n\n"); - fprintf(stderr, - " $ ./ldpc_enc /dev/zero - --sd --code HRA_112_112 --testframes 10 " - "|\n"); - fprintf(stderr, - " ./ldpc_dec - /dev/null --code HRA_112_112 --sd --testframes\n"); - exit(0); - } - - if ((codename = opt_exists(argv, argc, "--listcodes")) != 0) { - fprintf(stderr, "\n"); - fprintf(stderr, "H2064_516_sparse\n"); - fprintf(stderr, "HRA_112_112\n"); - fprintf(stderr, "\n"); - exit(0); - } - - /* default Wenet High Alitiude Balloon rate 0.8 code */ - - ldpc.max_iter = MAX_ITER; - ldpc.dec_type = 0; - ldpc.q_scale_factor = 1; - ldpc.r_scale_factor = 1; - ldpc.CodeLength = CODELENGTH; - ldpc.NumberParityBits = NUMBERPARITYBITS; - ldpc.NumberRowsHcols = NUMBERROWSHCOLS; - ldpc.max_row_weight = MAX_ROW_WEIGHT; - ldpc.max_col_weight = MAX_COL_WEIGHT; - ldpc.H_rows = H_rows; - ldpc.H_cols = H_cols; - ainput = input; - adetected_data = detected_data; - - if ((codename = opt_exists(argv, argc, "--code")) != 0) { - /* short rate 1/2 code for FreeDV HF digital voice */ - - if (strcmp(argv[codename + 1], "HRA_112_112") == 0) { - fprintf(stderr, "code: %s\n", argv[codename + 1]); - ldpc.max_iter = HRA_112_112_MAX_ITER; - ldpc.dec_type = 0; - ldpc.q_scale_factor = 1; - ldpc.r_scale_factor = 1; - ldpc.CodeLength = HRA_112_112_CODELENGTH; - ldpc.NumberParityBits = HRA_112_112_NUMBERPARITYBITS; - ldpc.NumberRowsHcols = HRA_112_112_NUMBERROWSHCOLS; - ldpc.max_row_weight = HRA_112_112_MAX_ROW_WEIGHT; - ldpc.max_col_weight = HRA_112_112_MAX_COL_WEIGHT; - ldpc.H_rows = HRA_112_112_H_rows; - ldpc.H_cols = HRA_112_112_H_cols; - ainput = HRA_112_112_input; - adetected_data = HRA_112_112_detected_data; - } - } - - if ((i = opt_exists(argv, argc, "--max_iter")) > 0) { - ldpc.max_iter = atoi(argv[i + 1]); - fprintf(stderr, "max_iter: %d\n", ldpc.max_iter); - } - - CodeLength = ldpc.CodeLength; /* length of entire codeword */ - NumberParityBits = ldpc.NumberParityBits; - data_bits_per_frame = ldpc.NumberRowsHcols; - unsigned char ibits[data_bits_per_frame]; - unsigned char pbits[NumberParityBits]; - char out_char[CodeLength]; - - testframes = 0; - total_iters = 0; - Tbits = Terrs = Tbits_raw = Terrs_raw = 0; - - if (!strcmp(argv[1], "--test")) { - /* test mode --------------------------------------------------------*/ - - fprintf(stderr, "Starting test using pre-compiled test data .....\n"); - fprintf(stderr, "Codeword length: %d\n", CodeLength); - fprintf(stderr, "Parity Bits....: %d\n", NumberParityBits); - - num_runs = 1; - num_ok = 0; - - for (r = 0; r < num_runs; r++) { - iter = run_ldpc_decoder(&ldpc, out_char, ainput, &parityCheckCount); - // fprintf(stderr, "iter: %d\n", iter); - total_iters += iter; - - int ok = 0; - for (i = 0; i < CodeLength; i++) { - if (out_char[i] == adetected_data[i]) ok++; - } - - if (ok == CodeLength) num_ok++; - } - - fprintf(stderr, "test runs......: %d\n", num_runs); - fprintf(stderr, "test runs OK...: %d\n", num_ok); - if (num_runs == num_ok) - fprintf(stderr, "test runs OK...: PASS\n"); - else - fprintf(stderr, "test runs OK...: FAIL\n"); - } else { - FILE *fin, *fout; - int sdinput, readhalfframe, nread, offset; - - /* File I/O mode ------------------------------------------------*/ - - if (strcmp(argv[1], "-") == 0) - fin = stdin; - else if ((fin = fopen(argv[1], "rb")) == NULL) { - fprintf(stderr, "Error opening input SD file: %s: %s.\n", argv[1], - strerror(errno)); - exit(1); - } - - if (strcmp(argv[2], "-") == 0) - fout = stdout; - else if ((fout = fopen(argv[2], "wb")) == NULL) { - fprintf(stderr, "Error opening output bit file: %s: %s.\n", argv[2], - strerror(errno)); - exit(1); - } - - sdinput = 0; - readhalfframe = 0; - mute = 0; - state = 0; - hframe = 0; - if (opt_exists(argv, argc, "--sd")) { - sdinput = 1; - } - if (opt_exists(argv, argc, "--half")) { - readhalfframe = 1; - } - if (opt_exists(argv, argc, "--mute")) { - mute = 1; - } - if (opt_exists(argv, argc, "--testframes")) { - testframes = 1; - uint16_t r[data_bits_per_frame]; - ofdm_rand(r, data_bits_per_frame); - - for (i = 0; i < data_bits_per_frame; i++) { - ibits[i] = r[i] > 16384; - } - encode(&ldpc, ibits, pbits); - } - - double *input_double = calloc(CodeLength, sizeof(double)); - float *input_float = calloc(CodeLength, sizeof(float)); - - nread = CodeLength; - offset = 0; - if (readhalfframe) { - nread = CodeLength / 2; - offset = CodeLength / 2; - for (i = 0; i < offset; i++) { - input_double[i] = 0.0; - } - } - - fprintf(stderr, "Codeword length: %d\n", CodeLength); - fprintf(stderr, "Parity Bits....: %d\n", NumberParityBits); - - // frame = 0; - while (fread(&input_double[offset], sizeof(double), nread, fin) == nread) { - // fprintf(stderr, "Frame %d\n", frame); - if (sdinput) { - if (testframes) { - char in_char; - for (i = 0; i < data_bits_per_frame; i++) { - in_char = input_double[i] < 0; - if (in_char != ibits[i]) { - Terrs_raw++; - } - Tbits_raw++; - } - for (i = 0; i < NumberParityBits; i++) { - in_char = input_double[i + data_bits_per_frame] < 0; - if (in_char != pbits[i]) { - Terrs_raw++; - } - Tbits_raw++; - } - } - sd_to_llr(input_float, input_double, CodeLength); - } - - iter = run_ldpc_decoder(&ldpc, out_char, input_float, &parityCheckCount); - // fprintf(stderr, "iter: %d\n", iter); - total_iters += iter; - - if (mute) { - // Output data bits if decoder converged, or was - // within 10% of all parity checks converging (10% est - // BER). useful for real world operation as it can - // resync and won't send crappy packets to the decoder - - float ber_est = (float)(ldpc.NumberParityBits - parityCheckCount) / - ldpc.NumberParityBits; - // fprintf(stderr, "iter: %4d parityCheckErrors: %4d ber: %3.2f\n", - // iter, ldpc.NumberParityBits - parityCheckCount, ber_est); - if (ber_est < 0.1) { - fwrite(out_char, sizeof(char), ldpc.NumberRowsHcols, fout); - } - - } else { - if (readhalfframe) { - // Establish which half hframe we want to sync on, - // used for testing with cohpsk_put_bits, as it - // maintains sync with test bits state machine. - - next_state = state; - switch (state) { - case 0: - if (iter < ldpc.max_iter) { - /* OK we've found which hframe to sync on */ - next_state = 1; - hframe = 0; - } - break; - case 1: - hframe++; - if ((hframe % 2) == 0) { - /* write decoded packets every second input hframe */ - fwrite(out_char, sizeof(char), ldpc.NumberRowsHcols, fout); - } - break; - } - state = next_state; - // fprintf(stderr, "state: %d iter: %d\n", state, iter); - } - - for (i = 0; i < offset; i++) { - input_double[i] = input_double[i + offset]; - } - } - - fwrite(out_char, sizeof(char), data_bits_per_frame, fout); - - if (testframes) { - for (i = 0; i < data_bits_per_frame; i++) { - // fprintf(stderr, "%d %d\n", out_char[i], ibits[i]); - if (out_char[i] != ibits[i]) { - Terrs++; - } - Tbits++; - } - } - // frame ++; - } - - free(input_double); - if (fin != NULL) fclose(fin); - if (fout != NULL) fclose(fout); - } - - fprintf(stderr, "total iters %d\n", total_iters); - - if (testframes) { - fprintf(stderr, "Raw Tbits..: %d Terr: %d BER: %4.3f\n", Tbits_raw, - Terrs_raw, (float)Terrs_raw / (Tbits_raw + 1E-12)); - fprintf(stderr, "Coded Tbits: %d Terr: %d BER: %4.3f\n", Tbits, Terrs, - (float)Terrs / (Tbits + 1E-12)); - } - - // ldpc_free_mem(&ldpc); - - return 0; -} +/* + FILE...: ldpc_dec.c + AUTHOR.: Matthew C. Valenti, Rohit Iyer Seshadri, David Rowe + CREATED: Sep 2016 + + Command line C LDPC decoder derived from MpDecode.c in the CML + library. Allows us to run the same decoder in Octave and C. The + code is defined by the parameters and array stored in the include + file below, which can be machine generated from the Octave function + ldpc_fsk_lib.m:ldpc_decode() + + The include file also contains test input/output vectors for the LDPC + decoder for testing this program. + + Build: + + $ gcc -O2 -o ldpc_dec ldpc_dec.c mpdecode_core.c -Wall -lm -g + + Note: -O2 option was required to get identical results to MpDecode, + which is also compiled with -O2. Without it the number of bit errors + between C and Octave was different, especially when the code did + not converge and hit max_iters. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "mpdecode_core_test.h" +#include "ofdm_internal.h" + +/* Machine generated consts, H_rows, H_cols, test input/output data to + change LDPC code regenerate this file. */ + +/* TODO: Better octave/C support for multuple codes */ + +#include "H2064_516_sparse_test.h" +#include "HRA_112_112_test.h" + +int opt_exists(char *argv[], int argc, char opt[]) { + int i; + for (i = 0; i < argc; i++) { + if (strcmp(argv[i], opt) == 0) { + return i; + } + } + return 0; +} + +int main(int argc, char *argv[]) { + int CodeLength, NumberParityBits; + int i, r, num_ok, num_runs, codename, parityCheckCount, mute; + int state, next_state, hframe, testframes; + // int frame; + int data_bits_per_frame; + char *adetected_data; + struct LDPC ldpc; + float *ainput; + int iter, total_iters; + int Tbits, Terrs, Tbits_raw, Terrs_raw; + + if (argc < 2) { + fprintf(stderr, "\n"); + fprintf(stderr, "usage: %s --test [--code CodeName]\n\n", argv[0]); + fprintf(stderr, " Run internal self test and print code parameters.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "usage: %s --listcodes\n\n", argv[0]); + fprintf(stderr, + " List supported codes (more can be added via using Octave ldpc " + "scripts)\n"); + fprintf(stderr, "\n"); + fprintf(stderr, + "usage: %s InOneSymbolPerDouble OutOneBitPerByte [--sd] [--half] " + "[--code CodeName] [--testframes]\n\n", + argv[0]); + fprintf(stderr, + " InOneSymbolPerDouble Input file of double LLRs, use - for " + "the \n"); + fprintf(stderr, + " file names to use stdin/stdout\n"); + fprintf(stderr, " --code Use LDPC code CodeName\n"); + fprintf(stderr, " --listcodes List available LDPC codes\n"); + fprintf(stderr, + " --sd Treat input file samples as Soft " + "Decision\n"); + fprintf(stderr, + " demod outputs rather than LLRs\n"); + fprintf(stderr, + " --half Load framesize/2 input samples for " + "each decode\n"); + fprintf(stderr, + " attempt, only output decoded bits\n"); + fprintf(stderr, + " converges. Form of frame sync.\n"); + fprintf(stderr, + " --mute Only output frames with < 10%% parity " + "check fails\n"); + fprintf(stderr, + " --testframes built in test frame modem, requires " + "--testframes at encoder\n"); + fprintf(stderr, "\n"); + + fprintf(stderr, "Example in testframe mode:\n\n"); + fprintf(stderr, + " $ ./ldpc_enc /dev/zero - --sd --code HRA_112_112 --testframes 10 " + "|\n"); + fprintf(stderr, + " ./ldpc_dec - /dev/null --code HRA_112_112 --sd --testframes\n"); + exit(0); + } + + if ((codename = opt_exists(argv, argc, "--listcodes")) != 0) { + fprintf(stderr, "\n"); + fprintf(stderr, "H2064_516_sparse\n"); + fprintf(stderr, "HRA_112_112\n"); + fprintf(stderr, "\n"); + exit(0); + } + + /* default Wenet High Alitiude Balloon rate 0.8 code */ + + ldpc.max_iter = MAX_ITER; + ldpc.dec_type = 0; + ldpc.q_scale_factor = 1; + ldpc.r_scale_factor = 1; + ldpc.CodeLength = CODELENGTH; + ldpc.NumberParityBits = NUMBERPARITYBITS; + ldpc.NumberRowsHcols = NUMBERROWSHCOLS; + ldpc.max_row_weight = MAX_ROW_WEIGHT; + ldpc.max_col_weight = MAX_COL_WEIGHT; + ldpc.H_rows = H_rows; + ldpc.H_cols = H_cols; + ainput = input; + adetected_data = detected_data; + + if ((codename = opt_exists(argv, argc, "--code")) != 0) { + /* short rate 1/2 code for FreeDV HF digital voice */ + + if (strcmp(argv[codename + 1], "HRA_112_112") == 0) { + fprintf(stderr, "code: %s\n", argv[codename + 1]); + ldpc.max_iter = HRA_112_112_MAX_ITER; + ldpc.dec_type = 0; + ldpc.q_scale_factor = 1; + ldpc.r_scale_factor = 1; + ldpc.CodeLength = HRA_112_112_CODELENGTH; + ldpc.NumberParityBits = HRA_112_112_NUMBERPARITYBITS; + ldpc.NumberRowsHcols = HRA_112_112_NUMBERROWSHCOLS; + ldpc.max_row_weight = HRA_112_112_MAX_ROW_WEIGHT; + ldpc.max_col_weight = HRA_112_112_MAX_COL_WEIGHT; + ldpc.H_rows = HRA_112_112_H_rows; + ldpc.H_cols = HRA_112_112_H_cols; + ainput = HRA_112_112_input; + adetected_data = HRA_112_112_detected_data; + } + } + + if ((i = opt_exists(argv, argc, "--max_iter")) > 0) { + ldpc.max_iter = atoi(argv[i + 1]); + fprintf(stderr, "max_iter: %d\n", ldpc.max_iter); + } + + CodeLength = ldpc.CodeLength; /* length of entire codeword */ + NumberParityBits = ldpc.NumberParityBits; + data_bits_per_frame = ldpc.NumberRowsHcols; + unsigned char ibits[data_bits_per_frame]; + unsigned char pbits[NumberParityBits]; + char out_char[CodeLength]; + + testframes = 0; + total_iters = 0; + Tbits = Terrs = Tbits_raw = Terrs_raw = 0; + + if (!strcmp(argv[1], "--test")) { + /* test mode --------------------------------------------------------*/ + + fprintf(stderr, "Starting test using pre-compiled test data .....\n"); + fprintf(stderr, "Codeword length: %d\n", CodeLength); + fprintf(stderr, "Parity Bits....: %d\n", NumberParityBits); + + num_runs = 1; + num_ok = 0; + + for (r = 0; r < num_runs; r++) { + iter = run_ldpc_decoder(&ldpc, out_char, ainput, &parityCheckCount); + // fprintf(stderr, "iter: %d\n", iter); + total_iters += iter; + + int ok = 0; + for (i = 0; i < CodeLength; i++) { + if (out_char[i] == adetected_data[i]) ok++; + } + + if (ok == CodeLength) num_ok++; + } + + fprintf(stderr, "test runs......: %d\n", num_runs); + fprintf(stderr, "test runs OK...: %d\n", num_ok); + if (num_runs == num_ok) + fprintf(stderr, "test runs OK...: PASS\n"); + else + fprintf(stderr, "test runs OK...: FAIL\n"); + } else { + FILE *fin, *fout; + int sdinput, readhalfframe, nread, offset; + + /* File I/O mode ------------------------------------------------*/ + + if (strcmp(argv[1], "-") == 0) + fin = stdin; + else if ((fin = fopen(argv[1], "rb")) == NULL) { + fprintf(stderr, "Error opening input SD file: %s: %s.\n", argv[1], + strerror(errno)); + exit(1); + } + + if (strcmp(argv[2], "-") == 0) + fout = stdout; + else if ((fout = fopen(argv[2], "wb")) == NULL) { + fprintf(stderr, "Error opening output bit file: %s: %s.\n", argv[2], + strerror(errno)); + exit(1); + } + + sdinput = 0; + readhalfframe = 0; + mute = 0; + state = 0; + hframe = 0; + if (opt_exists(argv, argc, "--sd")) { + sdinput = 1; + } + if (opt_exists(argv, argc, "--half")) { + readhalfframe = 1; + } + if (opt_exists(argv, argc, "--mute")) { + mute = 1; + } + if (opt_exists(argv, argc, "--testframes")) { + testframes = 1; + uint16_t r[data_bits_per_frame]; + ofdm_rand(r, data_bits_per_frame); + + for (i = 0; i < data_bits_per_frame; i++) { + ibits[i] = r[i] > 16384; + } + encode(&ldpc, ibits, pbits); + } + + double *input_double = calloc(CodeLength, sizeof(double)); + float *input_float = calloc(CodeLength, sizeof(float)); + + nread = CodeLength; + offset = 0; + if (readhalfframe) { + nread = CodeLength / 2; + offset = CodeLength / 2; + for (i = 0; i < offset; i++) { + input_double[i] = 0.0; + } + } + + fprintf(stderr, "Codeword length: %d\n", CodeLength); + fprintf(stderr, "Parity Bits....: %d\n", NumberParityBits); + + // frame = 0; + while (fread(&input_double[offset], sizeof(double), nread, fin) == nread) { + // fprintf(stderr, "Frame %d\n", frame); + if (sdinput) { + if (testframes) { + char in_char; + for (i = 0; i < data_bits_per_frame; i++) { + in_char = input_double[i] < 0; + if (in_char != ibits[i]) { + Terrs_raw++; + } + Tbits_raw++; + } + for (i = 0; i < NumberParityBits; i++) { + in_char = input_double[i + data_bits_per_frame] < 0; + if (in_char != pbits[i]) { + Terrs_raw++; + } + Tbits_raw++; + } + } + sd_to_llr(input_float, input_double, CodeLength); + } + + iter = run_ldpc_decoder(&ldpc, out_char, input_float, &parityCheckCount); + // fprintf(stderr, "iter: %d\n", iter); + total_iters += iter; + + if (mute) { + // Output data bits if decoder converged, or was + // within 10% of all parity checks converging (10% est + // BER). useful for real world operation as it can + // resync and won't send crappy packets to the decoder + + float ber_est = (float)(ldpc.NumberParityBits - parityCheckCount) / + ldpc.NumberParityBits; + // fprintf(stderr, "iter: %4d parityCheckErrors: %4d ber: %3.2f\n", + // iter, ldpc.NumberParityBits - parityCheckCount, ber_est); + if (ber_est < 0.1) { + fwrite(out_char, sizeof(char), ldpc.NumberRowsHcols, fout); + } + + } else { + if (readhalfframe) { + // Establish which half hframe we want to sync on, + // used for testing with cohpsk_put_bits, as it + // maintains sync with test bits state machine. + + next_state = state; + switch (state) { + case 0: + if (iter < ldpc.max_iter) { + /* OK we've found which hframe to sync on */ + next_state = 1; + hframe = 0; + } + break; + case 1: + hframe++; + if ((hframe % 2) == 0) { + /* write decoded packets every second input hframe */ + fwrite(out_char, sizeof(char), ldpc.NumberRowsHcols, fout); + } + break; + } + state = next_state; + // fprintf(stderr, "state: %d iter: %d\n", state, iter); + } + + for (i = 0; i < offset; i++) { + input_double[i] = input_double[i + offset]; + } + } + + fwrite(out_char, sizeof(char), data_bits_per_frame, fout); + + if (testframes) { + for (i = 0; i < data_bits_per_frame; i++) { + // fprintf(stderr, "%d %d\n", out_char[i], ibits[i]); + if (out_char[i] != ibits[i]) { + Terrs++; + } + Tbits++; + } + } + // frame ++; + } + + free(input_double); + if (fin != NULL) fclose(fin); + if (fout != NULL) fclose(fout); + } + + fprintf(stderr, "total iters %d\n", total_iters); + + if (testframes) { + fprintf(stderr, "Raw Tbits..: %d Terr: %d BER: %4.3f\n", Tbits_raw, + Terrs_raw, (float)Terrs_raw / (Tbits_raw + 1E-12)); + fprintf(stderr, "Coded Tbits: %d Terr: %d BER: %4.3f\n", Tbits, Terrs, + (float)Terrs / (Tbits + 1E-12)); + } + + // ldpc_free_mem(&ldpc); + + return 0; +} diff --git a/src/modem_stats.h b/src/modem_stats.h index c85fe528..f5605fb0 100644 --- a/src/modem_stats.h +++ b/src/modem_stats.h @@ -29,6 +29,7 @@ #define __MODEM_STATS__ #include "comp.h" +#include "export.h" #ifdef __cplusplus extern "C" { @@ -78,10 +79,11 @@ struct MODEM_STATS { #endif }; -void modem_stats_open(struct MODEM_STATS *f); -void modem_stats_close(struct MODEM_STATS *f); -void modem_stats_get_rx_spectrum(struct MODEM_STATS *f, float mag_spec_dB[], - COMP rx_fdm[], int nin); +CODEC2_API void modem_stats_open(struct MODEM_STATS *f); +CODEC2_API void modem_stats_close(struct MODEM_STATS *f); +CODEC2_API void modem_stats_get_rx_spectrum(struct MODEM_STATS *f, + float mag_spec_dB[], COMP rx_fdm[], + int nin); #ifdef __cplusplus } diff --git a/src/ofdm.c b/src/ofdm.c index dc3d0094..769aa2cc 100644 --- a/src/ofdm.c +++ b/src/ofdm.c @@ -706,6 +706,8 @@ static COMP vector_sum(COMP *a, int num_elements) { (__clang_minor__ > 7 || \ (__clang_minor__ == 7 && __clang_patchlevel__ > 0))) #define USE_VECTOR_OPS 1 +//#elif _MSC_VER > 1800 +//#define USE_VECTOR_OPS 1 #endif #else #include "codec2_math.h" @@ -764,7 +766,7 @@ static COMP ofdm_complex_dot_product(COMP *left, COMP *right, int numSamples) { result = resultReal + I * resultImag; #else for (int i = 0; i < numSamples; i++) { - result += left[i] * right[i]; + result = cmac(result, left[i], right[i]); } #endif /* USE_VECTOR_OPS */ diff --git a/src/reliable_text.h b/src/reliable_text.h index 205a93f6..b40793ec 100644 --- a/src/reliable_text.h +++ b/src/reliable_text.h @@ -23,6 +23,8 @@ #ifndef RELIABLE_TEXT_H #define RELIABLE_TEXT_H +#include "export.h" + #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -41,24 +43,26 @@ typedef void (*on_text_rx_t)(reliable_text_t rt, const char* txt_ptr, reliable_text_t reliable_text_create(); /* Destroy reliable_text object. */ -void reliable_text_destroy(reliable_text_t ptr); +CODEC2_API void reliable_text_destroy(reliable_text_t ptr); /* Reset reliable_text object for next sync. */ -void reliable_text_reset(reliable_text_t ptr); +CODEC2_API void reliable_text_reset(reliable_text_t ptr); /* Sets string that is sent on TX. */ -void reliable_text_set_string(reliable_text_t ptr, const char* str, - int strlength); +CODEC2_API void reliable_text_set_string(reliable_text_t ptr, const char* str, + int strlength); /* Link FreeDV object to reliable_text object. */ -void reliable_text_use_with_freedv(reliable_text_t ptr, struct freedv* fdv, - on_text_rx_t text_rx_fn, void* state); +CODEC2_API void reliable_text_use_with_freedv(reliable_text_t ptr, + struct freedv* fdv, + on_text_rx_t text_rx_fn, + void* state); /* Returns associated struct freedv object. */ -struct freedv* reliable_text_get_freedv_obj(reliable_text_t ptr); +CODEC2_API struct freedv* reliable_text_get_freedv_obj(reliable_text_t ptr); /* Unlink FreeDV object from reliable_text object. */ -void reliable_text_unlink_from_freedv(reliable_text_t ptr); +CODEC2_API void reliable_text_unlink_from_freedv(reliable_text_t ptr); #ifdef __cplusplus } diff --git a/stm32/unittest/lib/python/sum_profiles.py b/stm32/unittest/lib/python/sum_profiles.py old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/check_ram_limit b/stm32/unittest/scripts/check_ram_limit old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/kill_run_stm32_tst b/stm32/unittest/scripts/kill_run_stm32_tst old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/plot_ofdm_demod_syms b/stm32/unittest/scripts/plot_ofdm_demod_syms old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/run_all_codec2_tests b/stm32/unittest/scripts/run_all_codec2_tests old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/run_all_ldpc_tests b/stm32/unittest/scripts/run_all_ldpc_tests old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/run_all_ofdm_tests b/stm32/unittest/scripts/run_all_ofdm_tests old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/run_all_stm32_tests b/stm32/unittest/scripts/run_all_stm32_tests old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/run_stm32_prog b/stm32/unittest/scripts/run_stm32_prog old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/run_stm32_tst b/stm32/unittest/scripts/run_stm32_tst old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_api_demod_check b/stm32/unittest/scripts/tst_api_demod_check old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_api_demod_setup b/stm32/unittest/scripts/tst_api_demod_setup old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_api_mod_check b/stm32/unittest/scripts/tst_api_mod_check old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_api_mod_setup b/stm32/unittest/scripts/tst_api_mod_setup old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_codec2_dec_check b/stm32/unittest/scripts/tst_codec2_dec_check old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_codec2_dec_setup b/stm32/unittest/scripts/tst_codec2_dec_setup old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_codec2_enc_check b/stm32/unittest/scripts/tst_codec2_enc_check old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_codec2_enc_setup b/stm32/unittest/scripts/tst_codec2_enc_setup old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_ldpc_dec_check b/stm32/unittest/scripts/tst_ldpc_dec_check old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_ldpc_dec_setup b/stm32/unittest/scripts/tst_ldpc_dec_setup old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_ldpc_enc_check b/stm32/unittest/scripts/tst_ldpc_enc_check old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_ldpc_enc_setup b/stm32/unittest/scripts/tst_ldpc_enc_setup old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_ofdm_demod_check b/stm32/unittest/scripts/tst_ofdm_demod_check old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_ofdm_demod_setup b/stm32/unittest/scripts/tst_ofdm_demod_setup old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_ofdm_mod_check b/stm32/unittest/scripts/tst_ofdm_mod_check old mode 100755 new mode 100644 diff --git a/stm32/unittest/scripts/tst_ofdm_mod_setup b/stm32/unittest/scripts/tst_ofdm_mod_setup old mode 100755 new mode 100644 diff --git a/unittest/check_comp.sh b/unittest/check_comp.sh old mode 100755 new mode 100644 diff --git a/unittest/check_peak.sh b/unittest/check_peak.sh old mode 100755 new mode 100644 diff --git a/unittest/check_real_comp.sh b/unittest/check_real_comp.sh old mode 100755 new mode 100644 diff --git a/unittest/fading_files.sh b/unittest/fading_files.sh old mode 100755 new mode 100644 diff --git a/unittest/ofdm_check b/unittest/ofdm_check old mode 100755 new mode 100644 diff --git a/unittest/ofdm_fade.sh b/unittest/ofdm_fade.sh old mode 100755 new mode 100644 diff --git a/unittest/ofdm_phase_est_bw.sh b/unittest/ofdm_phase_est_bw.sh old mode 100755 new mode 100644 diff --git a/unittest/ofdm_time_sync.sh b/unittest/ofdm_time_sync.sh old mode 100755 new mode 100644 diff --git a/unittest/reliable_text_fade.sh b/unittest/reliable_text_fade.sh old mode 100755 new mode 100644 diff --git a/unittest/sum_debug_alloc b/unittest/sum_debug_alloc old mode 100755 new mode 100644 diff --git a/unittest/test_700c_eq.sh b/unittest/test_700c_eq.sh old mode 100755 new mode 100644