diff --git a/IPoverVHF/build_codec2.sh b/IPoverVHF/build_codec2.sh deleted file mode 100644 index ad356a8c36..0000000000 --- a/IPoverVHF/build_codec2.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -x -# automate local build of codec2 -git clone https://github.com/drowe67/codec2.git -cd codec2 && mkdir -p build_linux && cd build_linux -cmake ../ && make diff --git a/IPoverVHF/build_csdr.sh b/IPoverVHF/build_csdr.sh deleted file mode 100644 index 700100b33a..0000000000 --- a/IPoverVHF/build_csdr.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -x -# Automate building of csdr library, which is used by rtl_fsk application -PIRIP_DIR=$(pwd) -git clone https://github.com/ha7ilm/csdr.git -cd csdr && make diff --git a/IPoverVHF/build_rpitx.sh b/IPoverVHF/build_rpitx.sh deleted file mode 100644 index f3bba56f6a..0000000000 --- a/IPoverVHF/build_rpitx.sh +++ /dev/null @@ -1,9 +0,0 @@ -# automate building of RpiTx library -git clone https://github.com/F5OEO/librpitx -cd librpitx/src -make -cd ../../ -echo "To the end of /boot/config.txt add" -echo " gpu_freq=250" -echo " force_turbo=1" -echo "and reboot your Pi" diff --git a/IPoverVHF/build_rtlsdr.sh b/IPoverVHF/build_rtlsdr.sh deleted file mode 100644 index 9d48eee799..0000000000 --- a/IPoverVHF/build_rtlsdr.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -x -# Automate building of rtlsdr library and applications -PIRIP_DIR=$(pwd) -git clone https://github.com/drowe67/librtlsdr.git -cd librtlsdr -git checkout development -mkdir -p build_rtlsdr -cd build_rtlsdr -cmake ../ -DINSTALL_UDEV_RULES=ON -DCODEC2_BUILD_DIR=${PIRIP_DIR}/codec2/build_linux -DCSDR_BUILD_DIR=${PIRIP_DIR}/csdr -make rtl_sdr rtl_fsk diff --git a/IPoverVHF/script/dash.py b/IPoverVHF/script/dash.py deleted file mode 100644 index c49c6d7308..0000000000 --- a/IPoverVHF/script/dash.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python3 -# -# rtl_fsk modem dashboard -# -# usage: -# netcat -luk 8001 | ./dash.py - -import json -import sys -import numpy as np -import matplotlib.pyplot as plt -import io - -roll_s = 5 -SNRestdB = [] -norm_timing = []; - -# unbuffered stdin -sys.stdin = io.open(sys.stdin.fileno()) - -for line in sys.stdin: - - data = json.loads(line) - - # update rolling SNRest - SNRest_lin = data['SNRest_lin'] - tmp = 10*np.log10(SNRest_lin+1) - SNRestdB.append(tmp) - if len(SNRestdB) > roll_s: - SNRestdB.pop(0) - - # update rolling norm timing - latest_norm_timing = data['norm_rx_timing'] - norm_timing.extend(latest_norm_timing) - one_sec = len(latest_norm_timing) - if len(norm_timing) > roll_s*one_sec: - norm_timing = norm_timing[one_sec:] - - plt.clf() - plt.subplot(311) - SfdB = data['SfdB'] - fsk_lower_kHz = np.array(data['fsk_lower_Hz'])/1000 - fsk_upper_kHz = np.array(data['fsk_upper_Hz'])/1000 - f_est_kHz = np.array(data['f_est_Hz'])/1000 - Fs_kHz = data['Fs_Hz']/1000 - f_axis_kHz = -Fs_kHz/2 + np.arange(len(SfdB))*Fs_kHz/len(SfdB) - plt.plot(f_axis_kHz, SfdB) - height = 10; - mn = np.min(SfdB); - for f in f_est_kHz: - plt.plot(f, mn,"r+") - plt.plot([fsk_lower_kHz, fsk_lower_kHz], [mn, mn+height],"g") - plt.plot([fsk_upper_kHz, fsk_upper_kHz], [mn, mn+height],"g") - plt.grid() - plt.ylabel('Spectrum') - - plt.subplot(312) - - plt.plot(SNRestdB) - plt.ylabel('SNR') - mx = 10*np.ceil(np.max(SNRestdB)/10); - plt.ylim([0, mx]) - plt.grid() - plt.subplot(313) - plt.plot(norm_timing) - plt.ylabel('Timing') - plt.ylim([-0.5, 0.5]) - - plt.draw() - plt.pause(0.01) # renders plot diff --git a/IPoverVHF/script/frame_repeater b/IPoverVHF/script/frame_repeater deleted file mode 100644 index 63b4ede4e2..0000000000 --- a/IPoverVHF/script/frame_repeater +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/bash -# frame repeater service - -# TODO -# [X] way to send stderr to log file -# [ ] way to set freq at start up -# [ ] way to set Rs and M at start up -# [ ] way to start as frame repeater or beacon - -TERM_ADDR=0x2 -RS=10000 -DATA_BITS_PER_FRAME=256 -CODE=H_${DATA_BITS_PER_FRAME}_512_4 -TR_SWITCH_GPIO=21 -PIRIP_PATH=/home/pi/pirip -NAME=frame_repeater -PIDFILE=/var/run/${NAME}.pid -LOGFILE=/var/log/${NAME}.log -PATH=${PIRIP_PATH}/tx:${PIRIP_PATH}/librtlsdr/build_rtlsdr/src:${PATH} -GAIN="${GAIN:-49}" - -function tx_burst_rpitx { - num_bursts=$1 - rpitx_fsk /dev/zero --code H_256_512_4 -r ${RS} -s ${RS} --testframes 3 --bursts ${num_bursts} --delay 2000 -g 21 -m 2 - #rpitx_fsk -c -} - -function start_rx { - rtl_fsk -g ${GAIN} -f 144490000 - -a 200000 -r ${RS} --code H_256_512_4 --mask ${RS} -L $1 > /dev/null & - echo $!>${PIDFILE} -} - -function stop_service { - echo "service stopping - bye!" 1>&2 - parent=$(cat ${PIDFILE}) - kill ${parent} - rm ${PIDFILE} -} - -case "$1" in - start) - ( rtl_fsk -g 49 -f 144490000 - -a 200000 -r ${RS} --code ${CODE} --mask ${RS} --filter ${TERM_ADDR} -q -b | \ - frame_repeater ${DATA_BITS_PER_FRAME} ${TERM_ADDR} | \ - rpitx_fsk - --code ${CODE} -r ${RS} -s ${RS} -g ${TR_SWITCH_GPIO} --packed -- ) >>${LOGFILE} 2>&1 & - echo $!>${PIDFILE} - ;; - start_verbose) - # run in the foreground and log to stderr instead of a logfile - rtl_fsk -g 49 -f 144490000 - -a 200000 -r ${RS} --code ${CODE} --mask ${RS} --filter ${TERM_ADDR} -q -b -v | \ - frame_repeater ${DATA_BITS_PER_FRAME} ${TERM_ADDR} | \ - rpitx_fsk - --code ${CODE} -r ${RS} -s ${RS} -g ${TR_SWITCH_GPIO} --packed -- - ;; - start_loopback) - # Send packets from Pi to RTLSDR on this machine (no filtering of packets or frame repeater) - set -x - verbose=1 - start_rx - sleep 1 - if ! ps -p $(cat ${PIDFILE}); then - echo "rtl_fsk failed to start!" - rm ${PIDFILE} - exit 1 - fi - tx_burst_rpitx $2 - stop_service - ;; - stop) - stop_service - ;; - restart) - $0 stop - $0 start - ;; - status) - if [ -e ${PIDFILE} ]; then - echo ${NAME} is running, pid=`cat ${PIDFILE}` - else - echo$ {NAME} is NOT running - exit 1 - fi - ;; - *) - echo "Usage: sudo $0 {start|stop|status|restart}" - echo "" - echo "start - Start frame repeater service, logfile is ${LOGFILE}" - echo "start_verbose - Start frame repeater in foreground, no logfile" - echo "start_loopback numBursts - Local loopback test, tx/rx numBursts" -esac - -exit 0 diff --git a/IPoverVHF/script/ping b/IPoverVHF/script/ping deleted file mode 100644 index b6740cad3a..0000000000 --- a/IPoverVHF/script/ping +++ /dev/null @@ -1,130 +0,0 @@ -#!/bin/bash -# ping service script - sends bursts to the frame repeater and logs reply - -# TODO -# [X] receive it's own packets -# [X] log one one logfile -# [X] clean start up and shut down -# [X] send a sequence of packets -# [X] test with Pi running frame_repeater OTC - -TERM_ADDR=0x1 -RS=10000 -DATA_BITS_PER_FRAME=256 -CODE=H_${DATA_BITS_PER_FRAME}_512_4 -PIRIP_PATH=${PWD}/.. -NAME=ping -PIDFILE1=/var/run/${NAME}1.pid -PIDFILE2=/var/run/${NAME}2.pid -LOGFILE=/var/log/${NAME}.log -PATH=${PIRIP_PATH}/tx:${PIRIP_PATH}/librtlsdr/build_rtlsdr/src:${PATH} -PATH=${PIRIP_PATH}/codec2/build_linux/misc:${PIRIP_PATH}/codec2/build_linux/src:${PATH} -PAUSE="${PAUSE:-10}" -GAIN="${GAIN:-49}" -HACKRF_TX_GAIN="${HACKRF_TX_GAIN:-40}" - -function tx_burst_hackrf { - num_bursts=$1 - pause_between_bursts=$2 - tmp=$(mktemp) - if [ -z ${verbose+x} ]; then - # quiet version - freedv_data_raw_tx --source 0x1 -c --testframes 3 --burst 1 --Fs 100000 --Rs ${RS} --tone1 ${RS} --shift ${RS} -a 30000 FSK_LDPC /dev/zero - 2>/dev/null | tlininterp - - 40 -d -f > ${tmp} - for (( i=1; i<=$num_bursts; i++ )) - do - printf "%d Tx burst %d from HackRF...\n" `date +%s` ${i} 1>&2 - hackrf_transfer -t ${tmp} -s 4E6 -f 143.5E6 -x ${HACKRF_TX_GAIN} 2>/dev/null 1>/dev/null - sleep $pause_between_bursts - done - else - # verbose version - freedv_data_raw_tx --source 0x1 -c --testframes 3 --burst 1 --Fs 100000 --Rs ${RS} --tone1 ${RS} --shift ${RS} -a 30000 FSK_LDPC /dev/zero - | tlininterp - - 40 -d -f > ${tmp} - for (( i=1; i<=$num_bursts; i++ )) - do - printf "%d Tx burst %d from HackRF...\n" `date +%s` ${i} 1>&2 - hackrf_transfer -t ${tmp} -s 4E6 -f 143.5E6 -x ${HACKRF_TX_GAIN} - sleep $pause_between_bursts - done - fi -} - -function start_rx { - rtl_fsk -g ${GAIN} -f 144490000 - -a 200000 -r 10000 --code H_256_512_4 --mask 10000 -L $1 > /dev/null & - echo $!>${PIDFILE2} -} - -function stop_service { - echo "service stopping - bye!" 1>&2 - if [ -e ${PIDFILE2} ]; then - pid2=$(cat ${PIDFILE2}) - rm ${PIDFILE2} - kill ${pid2} - fi - if [ -e ${PIDFILE1} ]; then - pid1=$(cat ${PIDFILE1}) - rm ${PIDFILE1} - kill ${pid1} - fi -} - - -function check_running { - if [ -e ${PIDFILE1} ]; then - echo "service already running... pid: ${PIDFILE1}" - exit 1 - fi - if [ -e ${PIDFILE2} ]; then - echo "service already running... pid: ${PIDFILE2}" - exit 1 - fi -} - -case "$1" in - start) - check_running - ( start_rx "--filter ${TERM_ADDR}" && sleep 1 && tx_burst_hackrf $2 ${PAUSE} && stop_service) 2>>${LOGFILE} & - echo $!>${PIDFILE1} - ;; - start_verbose) - check_running - # Show all tool outputs and log output to stderr rather than logfile - verbose=1 - start_rx "--filter ${TERM_ADDR}" && sleep 1 && tx_burst_hackrf 1 1 && stop_service - ;; - start_loopback) - check_running - # Send packets from HackRF to RTLSDR on this machine (no filtering of packets) - verbose=1 - start_rx && sleep 1 && tx_burst_hackrf 1 1 && stop_service - ;; - start_carrier) - # Send carrier from HackRF at same Tx power as FSK signal, much easier to measure on a spec-an - fsk_get_test_bits - 60000 | fsk_mod -t -c -a 30000 2 40000 1000 1000 2000 - - | \ - tlininterp - - 100 -d -f | \ - hackrf_transfer -t - -s 4E6 -f 143.5E6 -x ${HACKRF_TX_GAIN} - ;; - stop) - stop_service - ;; - restart) - $0 stop - $0 start - ;; - status) - if [ -e ${PIDFILE1} ]; then - echo ${NAME} is running, pid=`cat ${PIDFILE}` - else - echo$ {NAME} is NOT running - exit 1 - fi - ;; - *) - echo "Usage: sudo $0 {start|stop|status|restart}" - echo "" - echo "start numPings - send numPing bursts to frame repeater, one every ${PAUSE} seconds, logfile is ${LOGFILE}" - echo "start_verbose - send single burst to frame repeater in foreground, no logfile" - echo "start_loopback - local loopback test, Tx/Rx a single burst of 3 frames" - echo "start_carrier - Send carrier from HackRF at same tx power as FSK signal" -esac - -exit 0 diff --git a/IPoverVHF/test/include.sh b/IPoverVHF/test/include.sh deleted file mode 100644 index a5ae6fa8ca..0000000000 --- a/IPoverVHF/test/include.sh +++ /dev/null @@ -1,10 +0,0 @@ -dash_host=penetrator -freq=144500000 -Fs=240000 -Rb=10000 -rx_freq=$(($freq-2*$Rb)) -numTxPackets=1000 -bitsPerPacket=100 -numTxBits=$(( ${numTxPackets}*${Rb}/${bitsPerPacket} )) -passRxPackets=$(( $numTxPackets-10 )) -rx_secs=15 diff --git a/IPoverVHF/test/loopback_rtl_fsk.sh b/IPoverVHF/test/loopback_rtl_fsk.sh deleted file mode 100644 index 7d61708219..0000000000 --- a/IPoverVHF/test/loopback_rtl_fsk.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -x -# -# Send test frames from Pi, receive and check on rtlsdr, using integrated rtl_fsk - -source test/include.sh -results=mktemp - -# kick off rx in background - -rtl-sdr-blog/build_rtlsdr/src/rtl_fsk -g 1 -s $Fs -f $rx_freq - -n $(($Fs*$rx_secs)) -u $dash_host | codec2/build_linux/src/fsk_put_test_bits -q -p $passRxPackets - 2>&1 | tee ${RESULTS} & -rx_pid=$! -# make sure rx is running -sleep 2 - -# send packets on Pi - -ssh pi@raspberrypi "cd pirip/tx; ../../codec2/build_linux/src/fsk_get_test_bits - $numTxBits | sudo ./fsk_rpitx -" - -# check results -wait ${rx_pid} diff --git a/IPoverVHF/test/loopback_rtl_sdr.sh b/IPoverVHF/test/loopback_rtl_sdr.sh deleted file mode 100644 index 6c082b7f42..0000000000 --- a/IPoverVHF/test/loopback_rtl_sdr.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -x -# -# Send test frames from Pi, receive and check on rtlsdr, using vanilla rtl_sdr - -Fs=240000 -Rb=10000 -numTxPackets=100 -bitsPerPacket=100 -numTxBits=$(( ${numTxPackets}*${Rb}/${bitsPerPacket} )) -passRxPackets=$(( $numTxPackets-10 )) - -results=mktemp - -# kick off rx in background - -tsecs=5; rtl-sdr-blog/build_rtlsdr/src/rtl_sdr -g 1 -s $Fs -f 144500000 - -n $(($Fs*$tsecs)) | codec2/build_linux/src/fsk_demod -d -p 24 2 $Fs $Rb - - | codec2/build_linux/src/fsk_put_test_bits -q -p $passRxPackets - 2>&1 | tee ${RESULTS} & -rx_pid=$! -sleep 2 - -# send packets on Pi - -ssh pi@raspberrypi "cd pirip/tx; ../../codec2/build_linux/src/fsk_get_test_bits - $numTxBits | sudo ./fsk_rpitx -" - -# check results -wait ${rx_pid} diff --git a/IPoverVHF/tx/Makefile b/IPoverVHF/tx/Makefile deleted file mode 100644 index a8da50f0f0..0000000000 --- a/IPoverVHF/tx/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# Makefile for rpitx_fsk, a fsk modulator for the Pi - -all: rpitx_fsk frame_repeater - -CODEC2_DIR=$(HOME)/pirip/codec2/build_linux/src -LIBRTLSDR_DIR=$(HOME)/pirip/librpitx/src/ -CXXFLAGS = -std=c++11 -Wall -g -O2 -Wno-unused-variable -I$(HOME)/pirip/codec2/src -CFLAGS = -Wall -g -O2 -Wno-unused-variable -I$(HOME)/pirip/codec2/src -LDFLAGS = $(LIBRTLSDR_DIR)/librpitx.a $(CODEC2_DIR)/libcodec2.so -Wl,-rpath=$(CODEC2_DIR) -lm -lrt -lpthread -CCP = c++ -CC = cc - -rpitx_fsk : rpitx_fsk.cpp $(LIBRTLSDR_DIR)/librpitx.a - $(CCP) $(CXXFLAGS) -o rpitx_fsk rpitx_fsk.cpp $(LDFLAGS) - -frame_repeater : frame_repeater.c - $(CC) $(CFLAGS) -o $@ $^ - - diff --git a/IPoverVHF/tx/frame_repeater.c b/IPoverVHF/tx/frame_repeater.c deleted file mode 100644 index ae5a4d1c32..0000000000 --- a/IPoverVHF/tx/frame_repeater.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - frame_repeater.c - David Rowe Nov 2020 - - Sits between rtl_fsk and rpitx_fsk, to implement a pirip frame - repeater, useful for unattended testing. Allows us to "ping" a - terminal. - - rtl_fsk | frame_repeater | rpitx_fsk - - + State machine gets "clocked" every time rtl_fsk sends a status byte. - + Bursts are accumulated until complete, then sent to rpitx_fsk for re-transmission - + we wait for the estimated time of the Tx burst, ignoring any frames received during the Tx burst, - as our sensitive RX will be picking up what we are sending - - TODO: - [X] Show it can echo one frame - [X] Show it can echo multiple frames - [X] leave running for a few hours with no lockups -*/ - -#include -#include -#include -#include -#include -#include - -#include "freedv_api_internal.h" - -#define IDLE 0 -#define RECEIVING_BURST 1 -#define MAX_FRAMES 100 - -int main(int argc, char *argv[]) { - int state = IDLE; - int next_state, bytes_in, bytes_out, nframes, ret, nclocks; - uint8_t burst_control, source_byte; - time_t last_time = 0; - - if (argc < 3) { - fprintf(stderr, "usage: %s dataBitsPerFrame sourceByte\n", argv[0]); - exit(1); - } - - int data_bits_per_frame = atoi(argv[1]); - assert((data_bits_per_frame % 8) == 0); - int data_bytes_per_frame = data_bits_per_frame/8; - fprintf(stderr, "frame_repeater: %d %d\n", data_bits_per_frame, data_bytes_per_frame); - uint8_t data[data_bytes_per_frame]; - uint8_t data_buffer[data_bytes_per_frame*MAX_FRAMES]; - - source_byte = strtol(argv[2], NULL, 0); - - /* At regular intervals rtl_fsk sends a status byte then - data_bytes_per_frame. If there is no received data then - data_buffer will be all zeros. */ - - uint8_t rx_status, prev_rx_status = 0; int time_ms; nclocks = 0; int wait_until_ms; - while(fread(&rx_status, sizeof(uint8_t), 1, stdin)) { - ret = fread(data, sizeof(uint8_t), data_bytes_per_frame, stdin); - assert(ret == data_bytes_per_frame); - nclocks++; - - /* update rate from rtl_fsk can be quite fast, so only fprintf status updates when the rx_status - changes */ - - next_state = state; - switch(state) { - case IDLE: - if (rx_status == (FREEDV_RX_SYNC | FREEDV_RX_BITS)) { - fprintf(stderr, "frame_repeater: Starting to receive a burst\n"); - memcpy(data_buffer, data, data_bytes_per_frame); - bytes_in = data_bytes_per_frame; - nframes = 1; - next_state = RECEIVING_BURST; - } - break; - case RECEIVING_BURST: - if (rx_status & FREEDV_RX_BITS) { - fprintf(stderr, "frame_repeater: Receiving a frame in a burst\n"); - // buffer latest packet - memcpy(&data_buffer[bytes_in], data, data_bytes_per_frame); - bytes_in += data_bytes_per_frame; - nframes++; - assert(bytes_in <= data_bytes_per_frame*MAX_FRAMES); - } - if (!(rx_status & FREEDV_RX_SYNC)) { - /* We've lost RX_SYNC so receive burst finished. So now we can Tx the frames we have buffered */ - fprintf(stderr, "frame_repeater: Sending received %d frame burst of %d bytes\n", nframes, bytes_in); - bytes_out = 0; burst_control = 1; - while(bytes_out != bytes_in) { - fwrite(&burst_control, sizeof(uint8_t), 1, stdout); - /* change source address so our local receiver can filter these packets out */ - data_buffer[bytes_out] = source_byte; - fwrite(&data_buffer[bytes_out], sizeof(uint8_t), data_bytes_per_frame, stdout); - bytes_out += data_bytes_per_frame; - burst_control = 0; - } - burst_control = 2; memset(data, 0, data_bytes_per_frame); - fwrite(&burst_control, sizeof(uint8_t), 1, stdout); - fwrite(data, sizeof(uint8_t), data_bytes_per_frame, stdout); - fflush(stdout); - next_state = IDLE; - } - break; - default: - assert(0); - } - /* just log output when state changes to avoid too much noise. Also log every 10s as a heartbeat, if that stops it means - rtl_fsk or this program has choked */ - if ((state != next_state) || (rx_status & FREEDV_RX_BITS) || (time(NULL) > (last_time + 10))) { - fprintf(stderr, "frame_repeater: [%d] state %d next_state: %d rx_status: 0x%02x\n", nclocks, state, next_state, rx_status); - last_time = time(NULL); - } - state = next_state; - } - - return 0; -} diff --git a/IPoverVHF/tx/rpitx_fsk.cpp b/IPoverVHF/tx/rpitx_fsk.cpp deleted file mode 100644 index 809b98a51a..0000000000 --- a/IPoverVHF/tx/rpitx_fsk.cpp +++ /dev/null @@ -1,561 +0,0 @@ -/* - rpitx_fsk.cpp - David Rowe July 2020 - - FSK modulates an input bit stream using rpitx. - - TODO: - [X] option for packed/unpacked byte input data - [ ] Fix operation at Rs<200, at present we can't detect any packets at Rs=100 - [ ] test with other LDPC codes - + high rate codes are of interest, big gains for small overhead -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../librpitx/src/librpitx.h" -#include "ldpc_codes.h" -#include "freedv_api.h" - -#define MAX_CHAR 256 -#define FIFO_SIZE 100 - -// Functions to build FSK_LDPC frame. Not normally exposed by FreeDV API -extern "C" { -int freedv_tx_fsk_ldpc_bits_per_frame(struct freedv *f); -void freedv_tx_fsk_ldpc_framer(struct freedv *f, uint8_t frame[], uint8_t payload_data[]); -void ofdm_generate_payload_data_bits(uint8_t payload_data_bits[], int n); -unsigned short freedv_gen_crc16(unsigned char* data_p, int length); -void freedv_pack(unsigned char *bytes, unsigned char *bits, int nbits); -void freedv_unpack(unsigned char *bits, unsigned char *bytes, int nbits); -} - -bool running=true; -static int terminate_calls = 0; -ngfmdmasync *fmmod = NULL; -float initial_frequency = 0.0; - -// Signals like Ctrl-C or segfaults get handled here -static void terminate(int num) { - terminate_calls++; - running=false; - fprintf(stderr,"Caught signal %d - Terminating\n", num); - if (terminate_calls >= 5) { - fprintf(stderr, "Too many signals - finishing....\n"); - fmmod->clkgpio::print_clock_tree(); - // make sure TX is off if we have to abort - if (fmmod) delete fmmod; - exit(1); - } -} - - -/* Use the Linux /sys/class/gpio system to access the RPis GPIOs */ -void sys_gpio(const char filename[], const char s[]) { - FILE *fgpio = fopen(filename, "wt"); - //fprintf(stderr,"%s %s\n",filename, s); - if (fgpio == NULL) { - fprintf(stderr, "\nProblem opening %s\n", filename); - exit(1); - } - fprintf(fgpio,"%s",s); - fclose(fgpio); -} - -// calculate and insert CRC in the last 16 bits of (unpacked) data_bits[] -void calculate_and_insert_crc(uint8_t data_bits[], int data_bits_per_frame) { - assert((data_bits_per_frame % 8) == 0); - int data_bytes_per_frame = data_bits_per_frame / 8; - uint8_t data_bytes[data_bytes_per_frame]; - freedv_pack(data_bytes, data_bits, data_bits_per_frame-16); - uint16_t crc16 = freedv_gen_crc16(data_bytes, data_bytes_per_frame-2); - uint8_t crc16_bytes[] = { (uint8_t)(crc16 >> 8), (uint8_t)(crc16 & 0xff) }; - freedv_unpack(data_bits+data_bits_per_frame-16, crc16_bytes, 16); -} - - -/* Sanity check PLLC. During development this was getting modified outside of rpitx. - Fix is to add "force_turbo=1" to the end of /boot/config.txt */ - -#define PLLC_CTRL (0x1120 / 4) // from libpitx/src/gpio.h - -float initial_pllc_freq() { - volatile uint32_t *gpioreg = fmmod->clkgpio::gpioreg; - return 19.2 * 1E6 * ((float)(gpioreg[PLLC_CTRL] & 0x3ff) + ((float)gpioreg[PLLC_FRAC]) / ((float)(1 << 20))); -} - -void check_pllc() { - volatile uint32_t *gpioreg = fmmod->clkgpio::gpioreg; - float current_freq = 19.2 * 1E6 * ((float)(gpioreg[PLLC_CTRL] & 0x3ff) + ((float)gpioreg[PLLC_FRAC]) / ((float)(1 << 20))); - - float delta = fabs(current_freq - initial_frequency)/initial_frequency; - if (delta > 0.01) { - fprintf(stderr, "PLLC PDIV=%d NDIV=%d FRAC=%d ", (gpioreg[PLLC_CTRL] >> 12)&0x7, gpioreg[PLLC_CTRL] & 0x3ff, gpioreg[PLLC_FRAC]); - fprintf(stderr, " %f MHz\n", 19.2 * ((float)(gpioreg[PLLC_CTRL] & 0x3ff) + ((float)gpioreg[PLLC_FRAC]) / ((float)(1 << 20)))); - fprintf(stderr, "\nPLLC getting modified outside of rpitx! Add \"force_turbo=1\" to the end of /boot/config.txt\n"); - delete fmmod; - exit(1); - } -} - - -// My attempt at a function to send samples to the DMA circular -// buffer. Not sure if this is any better than ngfmdamsync functions! -// Interesting area for further work. -int SetFrequencySampleNonBlocking(ngfmdmasync *fmmod, float Frequency) -{ - int Index = fmmod->GetUserMemIndex(); - if (Index == -1) { - return -1; - } else { - fmmod->sampletab[Index]=(0x5A<<24)|fmmod->GetMasterFrac(Frequency); - fmmod->PushSample(Index); - return 0; - } -} - -// FSK Modulate and Tx a frame of bits -void modulate_frame(ngfmdmasync *fmmod, float shiftHz, int m, uint8_t tx_frame[], int bits_per_frame) { - assert(fmmod != NULL); - for(int bit_i=0; bit_i>=1; ) { - uint8_t bit = tx_frame[bit_i] & 0x1; - sym = (sym<<1)|bit; - bit_i++; - } - float VCOfreqHz = shiftHz*sym; - while (SetFrequencySampleNonBlocking(fmmod,VCOfreqHz)) usleep(100); - } - -} - - -int main(int argc, char **argv) -{ - for (int i = 0; i < 64; i++) { - struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = terminate; - sigaction(i, &sa, NULL); - } - - FILE *fin; - int carrier_test = 0; - int one_zero_test = 0; - float frequency = 144.5e6; - int SymbolRate = 10000; - int m = 2; - int log2m; - float shiftHz = -1; - struct freedv *freedv = NULL; - struct freedv_advanced adv; - int fsk_ldpc = 0; - int data_bits_per_frame; // number of payload data bits - int bits_per_frame; // total number of bits including UW, payload data, parity bits for FSK + LDPC mode - int testframes = 0; - int Nframes = 0; - int Nbursts = 1; - int sequence_numbers = 0; - char ant_switch_gpio[128] = ""; - char ant_switch_gpio_path[MAX_CHAR] = ""; - int rpitx_fsk_fifo = 0; - int packed = 0; - uint8_t source_byte = 0; - int inter_burst_delay_ms = 0; - - char usage[] = "usage: %s [-m fskM 2|4] [-f carrierFreqHz] [-r symbRateHz] [-s shiftHz] [-t] [-c] " - "[--testframes Nframes] InputOneBitPerCharFile\n" - " -c Carrier test mode\n" - " -g GPIO that controls antenna Tx/Rx switch (1 for Tx, 0 for Rx)\n" - " -t ...0101010... FSK test mode\n" - " --code CodeName Use LDPC code CodeName\n" - " --listcodes List available LDPC codes\n" - " --testframes N Send N testframes per burst\n" - " --bursts B Send B bursts of N testframes (default 1)\n" - " --delay ms testframe inter-burst delay in ms (default 2 frames)\n" - " --seq send packet sequence numbers (breaks testframe BER counting) in byte[1]\n" - " --fifo fifoName send stats messages to fifoName\n" - " --packed packed byte input\n" - " --source Byte insert a (non-zero) source address att byte[0]\n" - "\n" - " Example 1, send 10000 bits of (100 bit) tests frames from external test frame generator\n" - " at 1000 bits/s using 2FSK:\n\n" - " $ ../codec2/build_linux/src/fsk_get_test_bits - 10000 | sudo ./rpitx_fsk - -r 1000 -s 1000\n\n" - " Example 2, send two LDPC encoded test frames at 1000 bits/s using 2FSK:\n\n" - " $ sudo ./rpitx_fsk /dev/zero --code H_256_512_4 -r 1000 -s 1000 --testframes 2\n"; - - int opt = 0; - int opt_idx = 0; - while( opt != -1 ){ - static struct option long_opts[] = { - {"code", required_argument, 0, 'a'}, - {"listcodes", no_argument, 0, 'b'}, - {"testframes",required_argument, 0, 'u'}, - {"bursts", required_argument, 0, 'e'}, - {"seq", no_argument, 0, 'q'}, - {"fifo", required_argument, 0, 'i'}, - {"packed", no_argument, 0, 'l'}, - {"source", required_argument, 0, 'd'}, - {"delay", required_argument, 0, 'j'}, - {0, 0, 0, 0} - }; - - opt = getopt_long(argc,argv,"a:bcd:e:f:g:i:m:qr:s:tu:",long_opts,&opt_idx); - - switch (opt) { - case 'a': - fsk_ldpc = 1; - adv.codename = optarg; - break; - case 'b': - ldpc_codes_list(); - exit(0); - break; - case 'c': - carrier_test = 1; - break; - case 'd': - source_byte = strtol(optarg, NULL, 0); - fprintf(stderr,"source byte: 0x%02x\n", source_byte); - break; - case 'e': - Nbursts = atoi(optarg); - break; - case 'm': - m = atoi(optarg); - break; - case 'l': - packed = 1; - break; - case 'f': - frequency = atof(optarg); - break; - case 'i': - rpitx_fsk_fifo = open(optarg, O_WRONLY); - if (rpitx_fsk_fifo == -1) { - fprintf(stderr, "Error opening fifo %s\n", argv[2]); - exit(1); - } - fprintf(stderr, "rpitx_fsk: FIFO opened OK ...\n"); - break; - case 'q': - sequence_numbers = 1; - break; - case 'r': - SymbolRate = atof(optarg); - break; - case 's': - shiftHz = atof(optarg); - break; - case 't': - one_zero_test = 1; - break; - case 'u': - if (fsk_ldpc == 0) { - fprintf(stderr, "internal testframe mode only supported in --code coded mode!\n"); - exit(1); - } - testframes = 1; - Nframes = atoi(optarg); - fprintf(stderr, "rpitx_fsk: Sending %d testframe(s)...\n", Nframes); - break; - case 'g': - strcpy(ant_switch_gpio, optarg); - sys_gpio("/sys/class/gpio/unexport", ant_switch_gpio); - sys_gpio("/sys/class/gpio/export", ant_switch_gpio); - usleep(100*1000); /* short delay so OS can create the next device */ - char tmp[MAX_CHAR]; - sprintf(tmp,"/sys/class/gpio/gpio%s/direction", ant_switch_gpio); - sys_gpio(tmp, "out"); - sprintf(ant_switch_gpio_path,"/sys/class/gpio/gpio%s/value", ant_switch_gpio); - sys_gpio(ant_switch_gpio_path, "0"); - break; - case 'j': - inter_burst_delay_ms = atoi(optarg); - break; - case 'h': - case '?': - fprintf(stderr, usage, argv[0]); - exit(1); - } - } - - if (argc < 2) { - fprintf(stderr, usage, argv[0]); - exit(1); - } - - fin = stdin; - if (!(carrier_test || one_zero_test)) { - if (strcmp(argv[optind],"-") != 0) { - fin = fopen(argv[optind],"rb"); - if (fin == NULL) { - fprintf(stderr, "Error opening input file: %s\n", argv[optind]); - exit(1); - } - } - } - - int npreamble_symbols = 50*(m>>1); - int npreamble_bits = npreamble_symbols*(m>>1); - uint8_t preamble_bits[npreamble_bits]; - - if (fsk_ldpc) { - // setup LDPC encoder and framer - adv.Rs = SymbolRate; - adv.Fs = 8*SymbolRate; // just required to satisfy freedv_open FSK_LDPC, as we don't run FSK demod here - adv.M = m; - freedv = freedv_open_advanced(FREEDV_MODE_FSK_LDPC, &adv); - assert(freedv != NULL); - data_bits_per_frame = freedv_get_bits_per_modem_frame(freedv); - bits_per_frame = freedv_tx_fsk_ldpc_bits_per_frame(freedv); - fprintf(stderr, "rpitx_fsk: FSK LDPC mode code: %s data_bits_per_frame: %d\n", adv.codename, data_bits_per_frame); - - /* set up preamble */ - /* TODO: this should be a freeDV API function */ - // cycle through all 2 and 4FSK symbols, not sure if this is better than random - int sym = 0; - for(int i=0; i>1) & 0x1; - preamble_bits[i+1] = sym & 0x1; - sym += 1; - } - - } else { - // uncoded mode - data_bits_per_frame = log2(m); - bits_per_frame = data_bits_per_frame; - } - - /* Start RpiTX ---------------------------------------------------------------------------------*/ - - // Set shiftHz at 2*Rs if no command line argument - if (shiftHz == -1) - shiftHz = 2*SymbolRate; - dbg_setlevel(1); - fmmod = new ngfmdmasync(frequency,SymbolRate,14,FIFO_SIZE); - initial_frequency = initial_pllc_freq(); - fmmod->clkgpio::disableclk(4); - - fprintf(stderr, "rpitx_fsk: Frequency: %4.1f MHz Rs: %4.1f kHz Shift: %4.1f kHz M: %d \n", frequency/1E6, SymbolRate/1E3, shiftHz/1E3, m); - fprintf(stderr, "rpitx_fsk: data_bits_per_frame: %d bits_per_frame: %d\n", data_bits_per_frame, bits_per_frame); - - if ((carrier_test == 0) && (one_zero_test == 0)) { - // FSK Tx -------------------------------------------------------------------- - - uint8_t data_bits[data_bits_per_frame]; - uint8_t tx_frame[bits_per_frame]; - - if (testframes) { - /* FSK_LDPC Tx in test frame mode -------------------------------------------*/ - - assert(fsk_ldpc); - ofdm_generate_payload_data_bits(data_bits, data_bits_per_frame); - - for(int b=0; bclkgpio::enableclk(4); - //fmmod = new ngfmdmasync(frequency,SymbolRate,14,FIFO_SIZE); - - // send pre-amble at start of burst - modulate_frame(fmmod, shiftHz, m, preamble_bits, npreamble_bits); - - for (int f=0; f> (7-i)) & 0x1; - } - - // optional injection of sequence numbers to help locate bad frames - if (sequence_numbers) { - int seq = (f+1) & 0xff; - for (int i=0; i<8; i++) - data_bits[8+i] = (seq >> (7-i)) & 0x1; - } - - calculate_and_insert_crc(data_bits, data_bits_per_frame); - freedv_tx_fsk_ldpc_framer(freedv, tx_frame, data_bits); - modulate_frame(fmmod, shiftHz, m, tx_frame, bits_per_frame); - - // allow early exit on Crtl-C - if (!running) goto finished; - } - - // wait for enough time for FIFO to empty - int bufferSamples = FIFO_SIZE - fmmod->GetBufferAvailable(); - float tdelay = (float)bufferSamples/SymbolRate; - usleep((int)(tdelay*1E6)); - - fprintf(stderr, "rpitx_fsk: End of burst %d\n", b); - - // transmitter carrier off between bursts - fmmod->clkgpio::disableclk(4); - //delete fmmod; - // antenna switch to Rx - if (*ant_switch_gpio_path) sys_gpio(ant_switch_gpio_path, "0"); - - if (inter_burst_delay_ms == 0) { - // Two frames delay so we have some interpacket silence - tdelay = (2.0/SymbolRate)*bits_per_frame/(m>>1); - } else { - tdelay = inter_burst_delay_ms/1E3; - } - usleep((int)(tdelay*1E6)); - check_pllc(); - } - - } - else { - /* regular FSK or FSK_LDPC Tx operation with bits/bytes from stdin ----------------------*/ - int nframes = 0; - while(1) { - uint8_t burst_control; - int nRead; - - if (fsk_ldpc) { - // in fsk_ldpc mode we prepend input data with a burst control byte - nRead = fread(&burst_control, sizeof(uint8_t), 1, fin); - if (nRead == 0) goto finished; - } - - if (packed) { - int data_bytes_per_frame = data_bits_per_frame/8; - uint8_t data_bytes[data_bytes_per_frame]; - nRead = fread(data_bytes, sizeof(uint8_t), data_bytes_per_frame, fin); - freedv_unpack(data_bits, data_bytes, data_bits_per_frame); - nRead *= 8; - } - else { - nRead = fread(data_bits, sizeof(uint8_t), data_bits_per_frame, fin); - } - - fprintf(stderr, "rpitx_fsk: burst_control: %d nRead: %d\n", burst_control, nRead); - - if (nRead != data_bits_per_frame) goto finished; - - if (fsk_ldpc) { - - // start of burst - if (burst_control == 1) { - fprintf(stderr, "rpitx_fsk: Tx on\n"); - // antenna switch to Tx - if (*ant_switch_gpio_path) sys_gpio(ant_switch_gpio_path, "1"); - // transmitter carrier on - fmmod->clkgpio::enableclk(4); - //fmmod = new ngfmdmasync(frequency,SymbolRate,14,FIFO_SIZE); - // send preamble - fprintf(stderr, "rpitx_fsk: sending preamble\n"); - modulate_frame(fmmod, shiftHz, m, preamble_bits, npreamble_bits); - nframes = 0; - } - - if ((burst_control == 0) || (burst_control == 1)) { - fprintf(stderr, "rpitx_fsk: sending frame: %d\n", nframes); nframes++; - // send a data frame, note last two bytes in frame replaced with CRC - calculate_and_insert_crc(data_bits, data_bits_per_frame); - freedv_tx_fsk_ldpc_framer(freedv, tx_frame, data_bits); - modulate_frame(fmmod, shiftHz, m, tx_frame, bits_per_frame); - } - - // end of burst - this has a dummy data frame so don't send - if (burst_control == 2) { - // wait for enough time for FIFO to empty - int bufferSamples = FIFO_SIZE - fmmod->GetBufferAvailable(); - float tdelay = (float)bufferSamples/SymbolRate; - usleep((int)(tdelay*1E6)); - // transmitter carrier off between bursts - fmmod->clkgpio::disableclk(4); - //delete fmmod; - // antenna switch to Rx - if (*ant_switch_gpio_path) sys_gpio(ant_switch_gpio_path, "0"); - fprintf(stderr, "rpitx_fsk: Tx off\n"); - if (rpitx_fsk_fifo) { - char buf[256]; - sprintf(buf, "Tx off"); - if (write(rpitx_fsk_fifo, buf, strlen(buf)+1) ==-1) { - fprintf(stderr, "rpitx_fsk: error writing to FIFO\n"); - } - } - } - } - else { - // uncoded mode - just send data_bits without any further framing - memcpy(tx_frame, data_bits, data_bits_per_frame); - modulate_frame(fmmod, shiftHz, m, tx_frame, bits_per_frame); - } - - // allow us to bail on Ctrl-C - if (!running) goto finished; - check_pllc(); - } - } - } - - if (carrier_test) { - fprintf(stderr, "Carrier test mode 1 sec on/off , Ctrl-C to exit\n"); - int count = 0; - int cycles = 0; - float VCOfreqHz = 0; - fmmod->clkgpio::enableclk(4); - while(running) { - //fmmod->SetFrequencySamples(&VCOfreqHz,1); - while (SetFrequencySampleNonBlocking(fmmod, VCOfreqHz)) usleep(100); - count++; - if (count == SymbolRate) - fmmod->clkgpio::disableclk(4); - if (count == 2*SymbolRate) { - fmmod->clkgpio::enableclk(4); - count = 0; - fprintf(stderr,"\rcycles: %d", ++cycles); - } - } - } - - if (one_zero_test) { - fprintf(stderr, "...010101... test mode, Ctrl-C to exit\n"); - float VCOfreqHz = 0; - fmmod->clkgpio::enableclk(4); - while(running) { - if (VCOfreqHz == shiftHz) - VCOfreqHz = 0; - else - VCOfreqHz = shiftHz; - while (SetFrequencySampleNonBlocking(fmmod, VCOfreqHz)) usleep(100); - } - } - - finished: - check_pllc(); - fprintf(stderr, "finishing....\n"); - - if (fmmod) delete fmmod; - if (fsk_ldpc) freedv_close(freedv); - - if (*ant_switch_gpio) { - sys_gpio(ant_switch_gpio_path, "0"); - sys_gpio("/sys/class/gpio/unexport", ant_switch_gpio); - } - return 0; -} - - - -