You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
6.7 KiB
222 lines
6.7 KiB
#!/usr/bin/octave -qf
|
|
|
|
% fsk_horus_stream.m
|
|
% David Rowe 13 Oct 2015
|
|
%
|
|
% Experimental real time near space balloon FSK demodulator, takes
|
|
% 8kHz 16 bit samples from stdin, output txt string on stdout
|
|
%
|
|
% usage:
|
|
%
|
|
% $ chmod 777 fsk_horus_stream.m
|
|
% $ rec -t raw -r 8000 -s -2 -c 1 - -q | ./fsk_horus_stream.m 2 100
|
|
%
|
|
% Or with pulseaudio you can decode two different waveforms at the
|
|
% same time. In two different shells start:
|
|
%
|
|
% $ arecord -D pulse -r 8000 -c 1 -f S16_LE - | ./fsk_horus_stream.m 2 100
|
|
% $ arecord -D pulse -r 8000 -c 1 -f S16_LE - | ./fsk_horus_stream.m 4 50
|
|
%
|
|
% 'pavucontrol' utility can be used to select a sound device for arecord.
|
|
%
|
|
% To test with a stored file (8kHz 16-bit shorts):
|
|
%
|
|
% $ cat ~/Desktop/vk5arg-3.wav | ./fsk_horus_stream.m 2 100
|
|
%
|
|
|
|
% command line arguments
|
|
|
|
arg_list = argv ();
|
|
if nargin == 0
|
|
printf("\nusage: %s [mFSKtones] [SymbolRateHz]\n\n", program_name());
|
|
printf("Horus RTTY 2FSK 100 baud:\n\n");
|
|
printf(" %s 2 100\n\n", program_name());
|
|
printf("Horus Binary 4FSK 50 baud\n\n");
|
|
printf(" %s 4 50\n\n", program_name());
|
|
exit(0);
|
|
end
|
|
|
|
mFSK = str2num(arg_list{1});
|
|
Rs = str2num(arg_list{2});
|
|
telem_upload_enabled = false;
|
|
if nargin == 3
|
|
% Optionally upload Telemetry to Habitat (http://tracker.habhub.org/)
|
|
if strcmp(arg_list{3}, "telem")
|
|
telem_upload_enabled = true;
|
|
end
|
|
end
|
|
printf ("\nmFSK: %d Rs: %d nargin: %d telem: %d\n", mFSK, Rs, nargin, telem_upload_enabled);
|
|
|
|
% include modem library
|
|
|
|
fsk_horus_as_a_lib = 1; % make sure calls to test functions at bottom are disabled
|
|
fsk_horus;
|
|
|
|
gps_log = "~/Desktop/gps_log.txt"
|
|
system_command = "echo -n \"/home/david/Desktop/gps_log.txt\" | nc -u -q1 127.0.0.1 21234";
|
|
|
|
% Update this command with your own callsign.
|
|
telem_upload_command = "python telem_upload.py -c vk5dgr_Octave";
|
|
|
|
more off;
|
|
states = fsk_horus_init(8000, Rs, mFSK);
|
|
rtty = fsk_horus_init_rtty;
|
|
binary = fsk_horus_init_binary;
|
|
N = states.N;
|
|
Rs = states.Rs;
|
|
nsym = states.nsym;
|
|
nin = states.nin;
|
|
nfield = rtty.nfield;
|
|
npad = rtty.npad;
|
|
EbNo = 0;
|
|
SNR = 0;
|
|
|
|
rx = [];
|
|
rx_bits_buf = [];
|
|
rx_bits_sd_buf = [];
|
|
|
|
[s,c] = fread(stdin, N, "short");
|
|
|
|
while c
|
|
|
|
rx = [rx s'];
|
|
|
|
% demodulate samples to bit stream
|
|
|
|
while length(rx) > nin
|
|
states = est_freq(states, rx(1:nin)', states.M);
|
|
[rx_bits states] = fsk_demod(states, rx(1:nin)');
|
|
rx_bits_buf = [rx_bits_buf rx_bits];
|
|
rx_bits_sd_buf = [rx_bits_sd_buf states.rx_bits_sd];
|
|
rx = rx(nin+1:length(rx));
|
|
nin = states.nin;
|
|
EbNo = 0.9*EbNo + 0.1*states.EbNodB;
|
|
SNR = EbNo + 10*log10(states.Rs/3000);
|
|
%printf("nin: %d length(rx): %d length(rx_bits_buf): %d \n", nin, length(rx), length(rx_bits_buf));
|
|
endwhile
|
|
f = states.f(1);
|
|
printf("max: %d f1: %d ppm: %d Eb/No: %3.1f SNR: %3.1f bits: %d\r", max(s), f, states.ppm, EbNo, SNR, length(rx_bits_buf));
|
|
|
|
packet_found = 0;
|
|
|
|
% Look for complete Horus RTTY frame -------------------------------------------------------------------
|
|
|
|
nbits = length(rx_bits_buf);
|
|
uw_loc = find_uw(rtty, 1, rx_bits_buf);
|
|
|
|
if uw_loc != -1
|
|
packet_found = 1;
|
|
|
|
if (uw_loc + rtty.max_packet_len) < nbits
|
|
%printf("\n%d nbits: %d\n",uw_loc + states.rtty.max_packet_len, nbits);
|
|
|
|
[str crc_ok] = extract_ascii(rtty, rx_bits_buf, uw_loc);
|
|
|
|
if crc_ok == 0
|
|
[str_flipped crc_flipped_ok] = sd_bit_flipping(rtty, rx_bits_buf, rx_bits_sd_buf, uw_loc, uw_loc+rtty.max_packet_len);
|
|
if crc_flipped_ok
|
|
str = sprintf("%s fixed", str_flipped);
|
|
crc_ok = 1;
|
|
end
|
|
end
|
|
|
|
if crc_ok
|
|
if telem_upload_enabled
|
|
% Upload to Habitat.
|
|
ascii_upload_cmd = sprintf("%s %s",telem_upload_command,str);
|
|
printf("Uploading ASCII to Habitat...\n");
|
|
system(ascii_upload_cmd,false,"async");
|
|
end
|
|
|
|
strok = sprintf("%s CRC OK", str);
|
|
else
|
|
strok = sprintf("%s CRC BAD", str);
|
|
end
|
|
printf("\n %s \n", strok);
|
|
|
|
% throw out used bits in buffer. We're not sure where the next packet starts
|
|
% so lets remove everything up to just after the UW we just used to force
|
|
% a search for the next UW.
|
|
|
|
rx_bits_buf = rx_bits_buf(uw_loc+length(rtty.uw):length(rx_bits_buf));
|
|
rx_bits_sd_buf = rx_bits_sd_buf(uw_loc+length(rtty.uw):length(rx_bits_sd_buf));
|
|
|
|
if crc_ok
|
|
% extract GPS coords and save to log file for mapping software
|
|
|
|
str_split = strsplit(str,",");
|
|
if length(str_split) > 4
|
|
lat = str_split{1,4}; long = str_split{1,5};
|
|
f = fopen(gps_log,"at");
|
|
fprintf(f,"%s,%s\n", lat, long);
|
|
fclose(f);
|
|
end
|
|
|
|
% TODO: thin out log file to max_points to lighten plotting load
|
|
|
|
% tell foxtrotGPS to plot track
|
|
|
|
system(system_command);
|
|
end
|
|
end
|
|
end
|
|
|
|
% Look for complete Horus BINARY frame -------------------------------------------------------------------
|
|
|
|
nbits = length(rx_bits_buf);
|
|
uw_loc = find_uw(binary, 1, rx_bits_buf);
|
|
|
|
if uw_loc != -1
|
|
packet_found = 1;
|
|
|
|
if (uw_loc + binary.max_packet_len) < nbits
|
|
|
|
pin = uw_loc;
|
|
nbytes = binary.max_packet_len/8;
|
|
for i=1:nbytes
|
|
rx_bytes(i) = rx_bits_buf(pin:pin+7) * (2.^(7:-1:0))';
|
|
pin += 8;
|
|
%printf("%d 0x%02x\n", i, rx_bytes(i));
|
|
end
|
|
|
|
printf("\n ");
|
|
f=fopen("horus_rx_bits_binary.bin","wt");
|
|
fwrite(f, rx_bytes, "uchar");
|
|
fclose(f);
|
|
|
|
% horus_l2 can be compiled a bunch of different ways. You need to
|
|
% compile with:
|
|
% codec2-dev/src$ gcc horus_l2.c -o horus_l2 -Wall -DDEC_RX_BITS -DHORUS_L2_RX
|
|
|
|
system("../src/horus_l2");
|
|
if telem_upload_enabled
|
|
% Upload binary payload data to Habitat.
|
|
binary_upload_addition = "`cat horus_rx_bits_hex.txt`";
|
|
binary_upload_cmd = sprintf("%s %s",telem_upload_command,binary_upload_addition);
|
|
printf("Uploading Binary to Habitat...\n");
|
|
system(binary_upload_cmd,type="async");
|
|
end
|
|
|
|
% throw out used bits in buffer. We're not sure where the next packet starts
|
|
% so lets remove everything up to just after the UW we just used to force
|
|
% a search for the next UW.
|
|
|
|
rx_bits_buf = rx_bits_buf(uw_loc+length(binary.uw):length(rx_bits_buf));
|
|
rx_bits_sd_buf = rx_bits_sd_buf(uw_loc+length(binary.uw):length(rx_bits_sd_buf));
|
|
end
|
|
end
|
|
|
|
% Truncate buffers if no UW found so they don't grow endlessly with no signal.
|
|
% Keep very end of it as it may have part of a UW in it
|
|
|
|
if packet_found == 0
|
|
max_len = rtty.max_packet_len*4;
|
|
if length(rx_bits_buf) > max_len
|
|
rx_bits_buf = rx_bits_buf(length(rx_bits_buf)-rtty.max_packet_len:length(rx_bits_buf));
|
|
rx_bits_sd_buf = rx_bits_sd_buf(length(rx_bits_sd_buf)-rtty.max_packet_len:length(rx_bits_sd_buf));
|
|
end
|
|
end
|
|
|
|
[s,c] = fread(stdin, N, "short");
|
|
|
|
endwhile
|
|
|