Merged origin/master into nmux
This commit is contained in:
commit
3246e20864
6 changed files with 736 additions and 311 deletions
4
Makefile
4
Makefile
|
@ -29,7 +29,7 @@
|
||||||
LIBSOURCES = fft_fftw.c libcsdr_wrapper.c
|
LIBSOURCES = fft_fftw.c libcsdr_wrapper.c
|
||||||
#SOURCES = csdr.c $(LIBSOURCES)
|
#SOURCES = csdr.c $(LIBSOURCES)
|
||||||
cpufeature = $(if $(findstring $(1),$(shell cat /proc/cpuinfo)),$(2))
|
cpufeature = $(if $(findstring $(1),$(shell cat /proc/cpuinfo)),$(2))
|
||||||
PARAMS_SSE = $(call cpufeature,sse,-msse) $(call cpufeature,sse2,-msse2) $(call cpufeature,sse3,-msse3) $(call cpufeature,sse4,-msse4) $(call cpufeature,sse4_1,-msse4.1) $(call cpufeature,sse4_2,-msse4.2) -mfpmath=sse
|
PARAMS_SSE = $(call cpufeature,sse,-msse) $(call cpufeature,sse2,-msse2) $(call cpufeature,sse3,-msse3) $(call cpufeature,sse4a,-msse4a) $(call cpufeature,sse4_1,-msse4.1) $(call cpufeature,sse4_2,-msse4.2 -msse4) -mfpmath=sse
|
||||||
PARAMS_NEON = -mfloat-abi=hard -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mvectorize-with-neon-quad -funsafe-math-optimizations -Wformat=0 -DNEON_OPTS
|
PARAMS_NEON = -mfloat-abi=hard -march=armv7-a -mtune=cortex-a8 -mfpu=neon -mvectorize-with-neon-quad -funsafe-math-optimizations -Wformat=0 -DNEON_OPTS
|
||||||
#tnx Jan Szumiec for the Raspberry Pi support
|
#tnx Jan Szumiec for the Raspberry Pi support
|
||||||
PARAMS_RASPI = -mfloat-abi=hard -mcpu=arm1176jzf-s -mfpu=vfp -funsafe-math-optimizations -Wformat=0
|
PARAMS_RASPI = -mfloat-abi=hard -mcpu=arm1176jzf-s -mfpu=vfp -funsafe-math-optimizations -Wformat=0
|
||||||
|
@ -92,7 +92,7 @@ emcc-get-deps:
|
||||||
emmake make; \
|
emmake make; \
|
||||||
emmake make install
|
emmake make install
|
||||||
emcc:
|
emcc:
|
||||||
emcc -O3 -Isdr.js/$(FFTW_PACKAGE)/api -Lsdr.js/$(FFTW_PACKAGE)/emscripten-lib -o sdr.js/sdrjs-compiled.js fft_fftw.c libcsdr_wrapper.c -DLIBCSDR_GPL -DUSE_IMA_ADPCM -DUSE_FFTW -lfftw3f -s EXPORTED_FUNCTIONS="`python sdr.js/exported_functions.py`"
|
emcc -O3 -Isdr.js/$(FFTW_PACKAGE)/api -Lsdr.js/$(FFTW_PACKAGE)/emscripten-lib -o sdr.js/sdrjs-compiled.js fft_fftw.c libcsdr_wrapper.c -s TOTAL_MEMORY=67108864 -DLIBCSDR_GPL -DUSE_IMA_ADPCM -DUSE_FFTW -lfftw3f -s EXPORTED_FUNCTIONS="`python sdr.js/exported_functions.py`"
|
||||||
cat sdr.js/sdrjs-header.js sdr.js/sdrjs-compiled.js sdr.js/sdrjs-footer.js > sdr.js/sdr.js
|
cat sdr.js/sdrjs-header.js sdr.js/sdrjs-compiled.js sdr.js/sdrjs-footer.js > sdr.js/sdr.js
|
||||||
emcc-beautify:
|
emcc-beautify:
|
||||||
bash -c 'type js-beautify >/dev/null 2>&1; if [ $$? -eq 0 ]; then js-beautify sdr.js/sdr.js >sdr.js/sdr.js.beautiful; mv sdr.js/sdr.js.beautiful sdr.js/sdr.js; fi'
|
bash -c 'type js-beautify >/dev/null 2>&1; if [ $$? -eq 0 ]; then js-beautify sdr.js/sdr.js >sdr.js/sdr.js.beautiful; mv sdr.js/sdr.js.beautiful sdr.js/sdr.js; fi'
|
||||||
|
|
118
README.md
118
README.md
|
@ -12,14 +12,22 @@ Most of the code is available under the permissive BSD license, with some option
|
||||||
|
|
||||||
How to compile
|
How to compile
|
||||||
--------------
|
--------------
|
||||||
The project was only tested on Linux. It has the following dependencies: `libfftw3-dev`
|
|
||||||
|
|
||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
|
The project was only tested on Linux. It has the following dependencies: `libfftw3-dev`
|
||||||
|
|
||||||
If you compile on ARM, please edit the Makefile and tailor `PARAMS_NEON` for your CPU.
|
If you compile on ARM, please edit the Makefile and tailor `PARAMS_NEON` for your CPU.
|
||||||
|
|
||||||
To run the examples, you will also need <a href="http://sdr.osmocom.org/trac/wiki/rtl-sdr">rtl_sdr</a> from Osmocom, and the following packages (at least on Debian): `mplayer octave gnuplot gnuplot-x11`
|
To run the examples, you will also need <a href="http://sdr.osmocom.org/trac/wiki/rtl-sdr">rtl_sdr</a> from Osmocom, and the following packages (at least on Debian): `mplayer octave gnuplot gnuplot-x11`
|
||||||
|
|
||||||
|
If you compile *fftw3* from sources for use with *libcsdr*, you need to configure it with 32-bit float support enabled:
|
||||||
|
|
||||||
|
./configure --enable-float
|
||||||
|
|
||||||
|
(This is for *fftw3*, not *libcsdr*. You do not need to run the configure script before compiling *libcsdr*.)
|
||||||
|
|
||||||
Credits
|
Credits
|
||||||
-------
|
-------
|
||||||
The library was written by Andras Retzler, HA7ILM <<randras@sdr.hu>>.
|
The library was written by Andras Retzler, HA7ILM <<randras@sdr.hu>>.
|
||||||
|
@ -31,7 +39,7 @@ Usage by example
|
||||||
|
|
||||||
### Demodulate WFM
|
### Demodulate WFM
|
||||||
|
|
||||||
rtl_sdr -s 240000 -f 89500000 -g 20 - | csdr convert_u8_f | csdr fmdemod_quadri_cf | csdr fractional_decimator_ff 5 | csdr deemphasis_wfm_ff 48000 50e-6 | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
rtl_sdr -s 240000 -f 89500000 -g 20 - | csdr convert_u8_f | csdr fmdemod_quadri_cf | csdr fractional_decimator_ff 5 | csdr deemphasis_wfm_ff 48000 50e-6 | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||||
|
|
||||||
- Baseband I/Q signal is coming from an RTL-SDR USB dongle, with a center frequency of `-f 104300000` Hz, a sampling rate of `-s 240000` samples per second.
|
- Baseband I/Q signal is coming from an RTL-SDR USB dongle, with a center frequency of `-f 104300000` Hz, a sampling rate of `-s 240000` samples per second.
|
||||||
- The `rtl_sdr` tool outputs an unsigned 8-bit I/Q signal (one byte of I sample and one byte of Q coming after each other), but `libcsdr` DSP routines internally use floating point data type, so we convert the data stream of `unsigned char` to `float` by `csdr convert_u8_f`.
|
- The `rtl_sdr` tool outputs an unsigned 8-bit I/Q signal (one byte of I sample and one byte of Q coming after each other), but `libcsdr` DSP routines internally use floating point data type, so we convert the data stream of `unsigned char` to `float` by `csdr convert_u8_f`.
|
||||||
|
@ -43,7 +51,7 @@ Usage by example
|
||||||
|
|
||||||
### Demodulate WFM: advanced
|
### Demodulate WFM: advanced
|
||||||
|
|
||||||
rtl_sdr -s 2400000 -f 89300000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc -0.085 | csdr fir_decimate_cc 10 0.05 HAMMING | csdr fmdemod_quadri_cf | csdr fractional_decimator_ff 5 | csdr deemphasis_wfm_ff 48000 50e-6 | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
rtl_sdr -s 2400000 -f 89300000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc -0.085 | csdr fir_decimate_cc 10 0.05 HAMMING | csdr fmdemod_quadri_cf | csdr fractional_decimator_ff 5 | csdr deemphasis_wfm_ff 48000 50e-6 | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||||
|
|
||||||
- We want to listen to one radio station, but input signal contains multiple stations, and its bandwidth is too large for sending it directly to the FM demodulator.
|
- We want to listen to one radio station, but input signal contains multiple stations, and its bandwidth is too large for sending it directly to the FM demodulator.
|
||||||
- We shift the signal to the center frequency of the station we want to receive: `-0.085*2400000 = -204000`, so basically we will listen to the radio station centered at 89504000 Hz.
|
- We shift the signal to the center frequency of the station we want to receive: `-0.085*2400000 = -204000`, so basically we will listen to the radio station centered at 89504000 Hz.
|
||||||
|
@ -64,7 +72,7 @@ The first parameter is the frequency in MHz, and the second optional parameter i
|
||||||
|
|
||||||
### Demodulate NFM
|
### Demodulate NFM
|
||||||
|
|
||||||
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-145350000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr fmdemod_quadri_cf | csdr limit_ff | csdr deemphasis_nfm_ff 48000 | csdr fastagc_ff | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-145350000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr fmdemod_quadri_cf | csdr limit_ff | csdr deemphasis_nfm_ff 48000 | csdr fastagc_ff | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||||
|
|
||||||
- Note that the decimation factor is higher (we want to select a ~25 kHz channel).
|
- Note that the decimation factor is higher (we want to select a ~25 kHz channel).
|
||||||
- Also there is a python hack to calculate the relative shift offset. The real receiver frequency is `145350000` Hz.
|
- Also there is a python hack to calculate the relative shift offset. The real receiver frequency is `145350000` Hz.
|
||||||
|
@ -72,7 +80,7 @@ The first parameter is the frequency in MHz, and the second optional parameter i
|
||||||
|
|
||||||
### Demodulate AM
|
### Demodulate AM
|
||||||
|
|
||||||
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-144400000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr amdemod_cf | csdr fastdcblock_ff | csdr agc_ff | csdr limit_ff | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-144400000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr amdemod_cf | csdr fastdcblock_ff | csdr agc_ff | csdr limit_ff | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||||
|
|
||||||
- `amdemod_cf` is used as demodulator.
|
- `amdemod_cf` is used as demodulator.
|
||||||
- `agc_ff` should be used for AM and SSB.
|
- `agc_ff` should be used for AM and SSB.
|
||||||
|
@ -87,7 +95,7 @@ The first parameter is the frequency in MHz, and the second optional parameter i
|
||||||
|
|
||||||
### Demodulate SSB
|
### Demodulate SSB
|
||||||
|
|
||||||
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-144400000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr bandpass_fir_fft_cc 0 0.1 0.05 | csdr realpart_cf | csdr agc_ff | csdr limit_ff | csdr convert_f_i16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
rtl_sdr -s 2400000 -f 145000000 -g 20 - | csdr convert_u8_f | csdr shift_addition_cc `python -c "print float(145000000-144400000)/2400000"` | csdr fir_decimate_cc 50 0.005 HAMMING | csdr bandpass_fir_fft_cc 0 0.1 0.05 | csdr realpart_cf | csdr agc_ff | csdr limit_ff | csdr convert_f_s16 | mplayer -cache 1024 -quiet -rawaudio samplesize=2:channels=1:rate=48000 -demuxer rawaudio -
|
||||||
|
|
||||||
- It is a modified Weaver-demodulator. The complex FIR filter removes the lower sideband and lets only the upper pass (USB). If you want to demodulate LSB, change `bandpass_fir_fft_cc 0 0.05` to `bandpass_fir_fft_cc -0.05 0`.
|
- It is a modified Weaver-demodulator. The complex FIR filter removes the lower sideband and lets only the upper pass (USB). If you want to demodulate LSB, change `bandpass_fir_fft_cc 0 0.05` to `bandpass_fir_fft_cc -0.05 0`.
|
||||||
|
|
||||||
|
@ -109,7 +117,7 @@ Data types are noted as it follows:
|
||||||
- `f` is `float` (single percision)
|
- `f` is `float` (single percision)
|
||||||
- `c` is `complexf` (two single precision floating point values in a struct)
|
- `c` is `complexf` (two single precision floating point values in a struct)
|
||||||
- `u8` is `unsigned char` of 1 byte/8 bits (e. g. the output of `rtl_sdr` is of `u8`)
|
- `u8` is `unsigned char` of 1 byte/8 bits (e. g. the output of `rtl_sdr` is of `u8`)
|
||||||
- `i16` is `signed short` of 2 bytes/16 bits (e. g. sound card input is usually `i16`)
|
- `s16` is `signed short` of 2 bytes/16 bits (e. g. sound card input is usually `s16`)
|
||||||
|
|
||||||
Functions usually end as:
|
Functions usually end as:
|
||||||
|
|
||||||
|
@ -124,12 +132,14 @@ The following commands are available:
|
||||||
- `csdr convert_f_u8`
|
- `csdr convert_f_u8`
|
||||||
- `csdr convert_s8_f`
|
- `csdr convert_s8_f`
|
||||||
- `csdr convert_f_s8`
|
- `csdr convert_f_s8`
|
||||||
- `csdr convert_i16_f`
|
- `csdr convert_s16_f`
|
||||||
- `csdr convert_f_i16`
|
- `csdr convert_f_s16`
|
||||||
|
|
||||||
How to interpret: `csdr convert_<src>_<dst>`
|
How to interpret: `csdr convert_<src>_<dst>`
|
||||||
You can use these commands on complex streams, too, as they are only interleaved values (I,Q,I,Q,I,Q... coming after each other).
|
You can use these commands on complex streams, too, as they are only interleaved values (I,Q,I,Q,I,Q... coming after each other).
|
||||||
|
|
||||||
|
> Note: The the functions with `i16` in their names have been renamed, but still work (e.g. `csdr convert_f_i16`).
|
||||||
|
|
||||||
#### csdr commands
|
#### csdr commands
|
||||||
|
|
||||||
`csdr` should be considered as a reference implementation on using `libcsdr`. For additional details on how to use the library, check `csdr.c` and `libcsdr.c`.
|
`csdr` should be considered as a reference implementation on using `libcsdr`. For additional details on how to use the library, check `csdr.c` and `libcsdr.c`.
|
||||||
|
@ -157,6 +167,10 @@ It multiplies all samples by `gain`.
|
||||||
|
|
||||||
It copies the input to the output.
|
It copies the input to the output.
|
||||||
|
|
||||||
|
through
|
||||||
|
|
||||||
|
It copies the input to the output, while also displaying the speed of the data going through it.
|
||||||
|
|
||||||
none
|
none
|
||||||
|
|
||||||
The `csdr` process just exits with 0.
|
The `csdr` process just exits with 0.
|
||||||
|
@ -363,11 +377,45 @@ The actual number of padding samples can be determined by running `cat csdr.c |
|
||||||
|
|
||||||
It exchanges the first and second part of the FFT vector, to prepare it for the waterfall/spectrum display. It should operate on the data output from `logpower_cf`.
|
It exchanges the first and second part of the FFT vector, to prepare it for the waterfall/spectrum display. It should operate on the data output from `logpower_cf`.
|
||||||
|
|
||||||
|
dsb_fc [q_value]
|
||||||
|
|
||||||
|
It converts a real signal to a double sideband complex signal centered around DC.
|
||||||
|
It does so by generating a complex signal:
|
||||||
|
* the real part of which is the input real signal,
|
||||||
|
* the imaginary part of which is `q_value` (0 by default).
|
||||||
|
With `q_value = 0` it is an AM-DSB/SC modulator. If you want to get an AM-DSB signal, you will have to add a carrier to it.
|
||||||
|
|
||||||
|
add_dcoffset_cc
|
||||||
|
|
||||||
|
It adds a DC offset to the complex signal: `i_output = 0.5 + i_input / 2, q_output = q_input / 2`
|
||||||
|
|
||||||
|
convert_f_samplerf <wait_for_this_sample>
|
||||||
|
|
||||||
|
It converts a real signal to the `-mRF` input format of [https://github.com/F5OEO/rpitx](rpitx), so it allows you to generate frequency modulation. The input signal will be the modulating signal. The `<wait_for_this_sample>` parameter is the value for `rpitx` indicating the time to wait between samples. For a sampling rate of 48 ksps, this is 20833.
|
||||||
|
|
||||||
|
fmmod_fc
|
||||||
|
|
||||||
|
It generates a complex FM modulated output from a real input signal.
|
||||||
|
|
||||||
|
fixed_amplitude_cc <new_amplitude>
|
||||||
|
|
||||||
|
It changes the amplitude of every complex input sample to a fixed value. It does not change the phase information of the samples.
|
||||||
|
|
||||||
|
mono2stereo_s16
|
||||||
|
|
||||||
|
It doubles every input sample.
|
||||||
|
|
||||||
setbuf <buffer_size>
|
setbuf <buffer_size>
|
||||||
|
|
||||||
If the environment variable `CSDR_DYNAMIC_BUFSIZE_ON` is set to 1, then you can use this command to set the input buffer size for the next `csdr` process in the chain.
|
See the [buffer sizes](#buffer_sizes) section.
|
||||||
|
|
||||||
|
squelch_and_smeter_cc --fifo <squelch_fifo> --outfifo <smeter_fifo> <use_every_nth> <report_every_nth>
|
||||||
|
|
||||||
|
This is a controllable squelch, which reads the squelch level input from `<squelch_fifo>` and writes the power level output to `<smeter_fifo>`. Both input and output are in the format of `%g\n`. While calculating the power level, it takes only every `<use_every_nth>` sample into consideration. It writes the S-meter value for every `<report_every_nth>` buffer to `<smeter_fifo>`. If the squelch level is set to 0, it it forces the squelch to be open. If the squelch is closed, it fills the output with zero.
|
||||||
|
|
||||||
|
fifo <buffer_size> <number_of_buffers>
|
||||||
|
|
||||||
|
It is similar to `clone`, but internally it uses a circular buffer. It reads as much as possible from the input. It discards input samples if the input buffer is full.
|
||||||
|
|
||||||
#### Control via pipes
|
#### Control via pipes
|
||||||
|
|
||||||
|
@ -391,6 +439,56 @@ By writing to the given FIFO file with the syntax below, you can control the shi
|
||||||
|
|
||||||
E.g. you can send `-0.05 0.02\n`
|
E.g. you can send `-0.05 0.02\n`
|
||||||
|
|
||||||
|
#### Buffer sizes
|
||||||
|
|
||||||
|
*csdr* has three modes of determining the buffer sizes, which can be chosen by the appropriate environment variables:
|
||||||
|
* *default:* 16k or 1k buffer is chosen based on function,
|
||||||
|
* *dynamic buffer size determination:* input buffer size is recommended by the previous process, output buffer size is determined by the process,
|
||||||
|
* *fixed buffer sizes*.
|
||||||
|
|
||||||
|
*csdr* can choose from two different buffer sizes by **default**.
|
||||||
|
* For operations handling the full-bandwidth I/Q data from the receiver, a buffer size of 16384 samples is used (see `env_csdr_fixed_big_bufsize` in the code).
|
||||||
|
* For operations handling only a selected channel, a buffer size of 1024 samples is used (see `env_csdr_fixed_bufsize` in the code).
|
||||||
|
|
||||||
|
*csdr* now has an experimental feature called **dynamic buffer size determination**, which is switched on by issuing `export CSDR_DYNAMIC_BUFSIZE_ON=1` in the shell before running `csdr`. If it is enabled:
|
||||||
|
* All `csdr` processes in a DSP chain acquire their recommended input buffer size from the previous `csdr` process. This information is in the first 8 bytes of the input stream.
|
||||||
|
* Each process can decide whether to use this or choose another input buffer size (if that's more practical).
|
||||||
|
* Every process sends out its output buffer size to the next process. Then it startss processing data.
|
||||||
|
* The DSP chain should start with a `csdr setbuf <buffer_size>` process, which only copies data from the input to the output, but also sends out the given buffer size information to the next process.
|
||||||
|
* The 8 bytes of information included in the beginning of the stream is:
|
||||||
|
* a preamble of the bytes 'c','s','d','r' (4 bytes),
|
||||||
|
* the buffer size stored as `int` (4 bytes).
|
||||||
|
* This size always counts as samples, as we expect that the user takes care of connecting the functions with right data types to each other.
|
||||||
|
|
||||||
|
> I added this feature while researching how to decrease the latency of a DSP chain consisting of several multirate algorithms.<br />
|
||||||
|
> For example, a `csdr fir_decimate_cc 10` would use an input buffer of 10240, and an output buffer of 1024. The next process in the chain, `csdr bandpass_fir_fft_cc` would automatically adjust to it, using a buffer of 1024 for both input and output.<br />
|
||||||
|
> In contrast to original expectations, using dynamic buffer sizes didn't decrease the latency much.
|
||||||
|
|
||||||
|
If dynamic buffer size determination is disabled, you can still set a **fixed buffer size** with `export CSDR_FIXED_BUFSIZE=<buffer_size>`.
|
||||||
|
|
||||||
|
For debug purposes, buffer sizes of all processes can be printed using `export CSDR_PRINT_BUFSIZES=1`.
|
||||||
|
|
||||||
|
If you add your own functions to `csdr`, you have to initialize the buffers before doing the processing. Buffer size will be stored in the global variable `the_bufsize`.
|
||||||
|
|
||||||
|
Example of initialization if the process generates N output samples for N input samples:
|
||||||
|
|
||||||
|
if(!sendbufsize(initialize_buffers())) return -2;
|
||||||
|
|
||||||
|
Example of initalization if the process generates N/D output samples for N input samples:
|
||||||
|
|
||||||
|
if(!initialize_buffers()) return -2;
|
||||||
|
sendbufsize(the_bufsize/D);
|
||||||
|
|
||||||
|
Example of initialization if the process allocates memory for itself, and it doesn't want to use the global buffers:
|
||||||
|
|
||||||
|
getbufsize(); //dummy
|
||||||
|
sendbufsize(my_own_bufsize);
|
||||||
|
|
||||||
|
Example of initialization if the process always works with a fixed output size, regardless of the input:
|
||||||
|
|
||||||
|
if(!initialize_buffers()) return -2;
|
||||||
|
sendbufsize(fft_size);
|
||||||
|
|
||||||
#### Testbench
|
#### Testbench
|
||||||
|
|
||||||
`csdr` was tested with GNU Radio Companion flowgraphs. These flowgraphs are available under the directory `grc_tests`, and they require the <a href="https://github.com/simonyiszk/gr-ha5kfu">gr-ha5kfu</a> set of blocks for GNU Radio.
|
`csdr` was tested with GNU Radio Companion flowgraphs. These flowgraphs are available under the directory `grc_tests`, and they require the <a href="https://github.com/simonyiszk/gr-ha5kfu">gr-ha5kfu</a> set of blocks for GNU Radio.
|
||||||
|
|
276
csdr.c
276
csdr.c
|
@ -49,6 +49,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
#include <errno.h>
|
||||||
#include "fastddc.h"
|
#include "fastddc.h"
|
||||||
|
|
||||||
char usage[]=
|
char usage[]=
|
||||||
|
@ -60,8 +61,10 @@ char usage[]=
|
||||||
" convert_f_u8\n"
|
" convert_f_u8\n"
|
||||||
" convert_s8_f\n"
|
" convert_s8_f\n"
|
||||||
" convert_f_s8\n"
|
" convert_f_s8\n"
|
||||||
" convert_f_i16\n"
|
" convert_f_s16\n"
|
||||||
" convert_i16_f\n"
|
" convert_s16_f\n"
|
||||||
|
" convert_f_s24 [--bigendian]\n"
|
||||||
|
" convert_s24_f [--bigendian]\n"
|
||||||
" realpart_cf\n"
|
" realpart_cf\n"
|
||||||
" clipdetect_ff\n"
|
" clipdetect_ff\n"
|
||||||
" limit_ff [max_amplitude]\n"
|
" limit_ff [max_amplitude]\n"
|
||||||
|
@ -73,7 +76,9 @@ char usage[]=
|
||||||
" floatdump_f\n"
|
" floatdump_f\n"
|
||||||
" flowcontrol <data_rate> <reads_per_second> [prebuffer_sec] [thrust]\n"
|
" flowcontrol <data_rate> <reads_per_second> [prebuffer_sec] [thrust]\n"
|
||||||
" shift_math_cc <rate>\n"
|
" shift_math_cc <rate>\n"
|
||||||
|
" shift_math_cc --fifo <fifo_path>\n"
|
||||||
" shift_addition_cc <rate>\n"
|
" shift_addition_cc <rate>\n"
|
||||||
|
" shift_addition_cc --fifo <fifo_path>\n"
|
||||||
" shift_addition_cc_test\n"
|
" shift_addition_cc_test\n"
|
||||||
" shift_table_cc <rate> [table_size]\n"
|
" shift_table_cc <rate> [table_size]\n"
|
||||||
" decimating_shift_addition_cc <rate> [decimation]\n"
|
" decimating_shift_addition_cc <rate> [decimation]\n"
|
||||||
|
@ -97,10 +102,21 @@ char usage[]=
|
||||||
" logpower_cf [add_db]\n"
|
" logpower_cf [add_db]\n"
|
||||||
" fft_benchmark <fft_size> <fft_cycles> [--benchmark]\n"
|
" fft_benchmark <fft_size> <fft_cycles> [--benchmark]\n"
|
||||||
" bandpass_fir_fft_cc <low_cut> <high_cut> <transition_bw> [window]\n"
|
" bandpass_fir_fft_cc <low_cut> <high_cut> <transition_bw> [window]\n"
|
||||||
" encode_ima_adpcm_i16_u8\n"
|
" bandpass_fir_fft_cc --fifo <fifo_path> <transition_bw> [window]\n"
|
||||||
" decode_ima_adpcm_u8_i16\n"
|
" encode_ima_adpcm_s16_u8\n"
|
||||||
|
" decode_ima_adpcm_u8_s16\n"
|
||||||
" compress_fft_adpcm_f_u8 <fft_size>\n"
|
" compress_fft_adpcm_f_u8 <fft_size>\n"
|
||||||
|
" flowcontrol <data_rate> <reads_per_second>\n"
|
||||||
|
" through\n"
|
||||||
|
" dsb_fc [q_value]\n"
|
||||||
|
" convert_f_samperf <wait_for_this_sample> \n"
|
||||||
|
" fmmod_fc\n"
|
||||||
|
" fixed_amplitude_cc <new_amplitude>\n"
|
||||||
|
" monos2stereo_s16\n"
|
||||||
|
" setbuf <buffer_size>\n"
|
||||||
" fft_exchange_sides_ff <fft_size>\n"
|
" fft_exchange_sides_ff <fft_size>\n"
|
||||||
|
" squelch_and_smeter_cc --fifo <squelch_fifo> --outfifo <smeter_fifo> <use_every_nth> <report_every_nth>\n"
|
||||||
|
" fifo <buffer_size> <number_of_buffers>\n"
|
||||||
" \n"
|
" \n"
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -306,7 +322,7 @@ int parse_env()
|
||||||
envtmp=getenv("CSDR_FIXED_BUFSIZE");
|
envtmp=getenv("CSDR_FIXED_BUFSIZE");
|
||||||
if(envtmp)
|
if(envtmp)
|
||||||
{
|
{
|
||||||
env_csdr_fixed_bufsize = atoi(envtmp);
|
env_csdr_fixed_big_bufsize = env_csdr_fixed_bufsize = atoi(envtmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
envtmp=getenv("CSDR_PRINT_BUFSIZES");
|
envtmp=getenv("CSDR_PRINT_BUFSIZES");
|
||||||
|
@ -341,6 +357,94 @@ int main(int argc, char *argv[])
|
||||||
if(!sendbufsize(initialize_buffers())) return -2;
|
if(!sendbufsize(initialize_buffers())) return -2;
|
||||||
clone_(the_bufsize);
|
clone_(the_bufsize);
|
||||||
}
|
}
|
||||||
|
#define SET_NONBLOCK(fd) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK)
|
||||||
|
|
||||||
|
if(!strcmp(argv[1],"fifo"))
|
||||||
|
{
|
||||||
|
if(!sendbufsize(initialize_buffers())) return -2;
|
||||||
|
|
||||||
|
int fifo_buffer_size;
|
||||||
|
if(argc<=2) return badsyntax("need required parameter (buffer_size)");
|
||||||
|
sscanf(argv[2],"%d",&fifo_buffer_size);
|
||||||
|
int fifo_num_buffers;
|
||||||
|
if(argc<=3) return badsyntax("need required parameter (number of buffers)");
|
||||||
|
sscanf(argv[3],"%d",&fifo_num_buffers);
|
||||||
|
|
||||||
|
char** fifo_buffers = (char**)malloc(sizeof(char*)*fifo_num_buffers);
|
||||||
|
for(int i=0;i<fifo_num_buffers;i++) fifo_buffers[i]=(char*)malloc(sizeof(char)*fifo_buffer_size);
|
||||||
|
|
||||||
|
SET_NONBLOCK(STDIN_FILENO);
|
||||||
|
SET_NONBLOCK(STDOUT_FILENO);
|
||||||
|
|
||||||
|
fd_set read_fds;
|
||||||
|
FD_ZERO(&read_fds);
|
||||||
|
FD_SET(STDIN_FILENO, &read_fds);
|
||||||
|
fd_set write_fds;
|
||||||
|
FD_ZERO(&write_fds);
|
||||||
|
FD_SET(STDOUT_FILENO, &write_fds);
|
||||||
|
|
||||||
|
int highfd = ((STDOUT_FILENO > STDIN_FILENO) ? STDOUT_FILENO : STDIN_FILENO) + 1;
|
||||||
|
|
||||||
|
int fifo_actual_buffer_wr = fifo_num_buffers - 1;
|
||||||
|
int fifo_actual_buffer_rd = 0;
|
||||||
|
int fifo_actual_buffer_wr_pos = 0;
|
||||||
|
int fifo_actual_buffer_rd_pos = 0;
|
||||||
|
int fifo_error = 0;
|
||||||
|
int fifo_overrun_shown = 0;
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
select(highfd, &read_fds, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
//try to read until buffer is full
|
||||||
|
if(FD_ISSET(STDIN_FILENO, &read_fds)) for(;;)
|
||||||
|
{
|
||||||
|
int read_bytes=read(STDIN_FILENO, fifo_buffers[fifo_actual_buffer_rd]+fifo_actual_buffer_rd_pos, fifo_buffer_size-fifo_actual_buffer_rd_pos);
|
||||||
|
//fprintf(stderr, "r %d %d | %d %d\n", read_bytes, fifo_buffer_size-fifo_actual_buffer_rd_pos, fifo_actual_buffer_rd, fifo_actual_buffer_rd_pos);
|
||||||
|
if(!read_bytes || ((read_bytes<0)&&(fifo_error=read_bytes)) ) break;
|
||||||
|
fifo_actual_buffer_rd_pos+=read_bytes;
|
||||||
|
if(!((fifo_actual_buffer_rd==fifo_actual_buffer_wr-1)||(fifo_actual_buffer_wr==0&&fifo_actual_buffer_rd==fifo_num_buffers-1)))
|
||||||
|
{
|
||||||
|
if(fifo_actual_buffer_rd_pos==fifo_buffer_size)
|
||||||
|
{
|
||||||
|
fifo_overrun_shown = 0;
|
||||||
|
fifo_actual_buffer_rd++;
|
||||||
|
fifo_actual_buffer_rd_pos = 0;
|
||||||
|
if(fifo_actual_buffer_rd>=fifo_num_buffers) fifo_actual_buffer_rd=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(fifo_actual_buffer_rd_pos==fifo_buffer_size)
|
||||||
|
{
|
||||||
|
fifo_actual_buffer_rd_pos = 0; //rewrite same buffer
|
||||||
|
if(!fifo_overrun_shown) { fifo_overrun_shown=1; fprintf(stderr, "fifo: circular buffer full, dropping samples\n"); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//try to write until buffer is empty
|
||||||
|
if(FD_ISSET(STDOUT_FILENO, &write_fds)) for(;;)
|
||||||
|
{
|
||||||
|
if(fifo_actual_buffer_wr == fifo_actual_buffer_rd) break;
|
||||||
|
int written_bytes=write(STDOUT_FILENO, fifo_buffers[fifo_actual_buffer_wr]+fifo_actual_buffer_wr_pos, fifo_buffer_size-fifo_actual_buffer_wr_pos);
|
||||||
|
//fprintf(stderr, "w %d %d | %d %d\n", written_bytes, fifo_buffer_size-fifo_actual_buffer_wr_pos, fifo_actual_buffer_wr, fifo_actual_buffer_wr_pos);
|
||||||
|
if(!written_bytes || ((written_bytes<0)&&(fifo_error=written_bytes)) ) break;
|
||||||
|
fifo_actual_buffer_wr_pos+=written_bytes;
|
||||||
|
if(fifo_actual_buffer_wr_pos==fifo_buffer_size)
|
||||||
|
{
|
||||||
|
fifo_actual_buffer_wr++;
|
||||||
|
fifo_actual_buffer_wr_pos = 0;
|
||||||
|
if(fifo_actual_buffer_wr>=fifo_num_buffers) fifo_actual_buffer_wr=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if(fifo_error&&errno!=11) { fprintf(stderr,"fifo: fifo_error (%d)", errno); return -1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(!strcmp(argv[1],"convert_u8_f"))
|
if(!strcmp(argv[1],"convert_u8_f"))
|
||||||
{
|
{
|
||||||
|
@ -368,27 +472,29 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
if(!strcmp(argv[1],"convert_s8_f"))
|
if(!strcmp(argv[1],"convert_s8_f"))
|
||||||
{
|
{
|
||||||
|
if(!sendbufsize(initialize_buffers())) return -2;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
FEOF_CHECK;
|
FEOF_CHECK;
|
||||||
fread(buffer_s8, sizeof(signed char), BUFSIZE, stdin);
|
fread((signed char*)buffer_u8, sizeof(signed char), the_bufsize, stdin);
|
||||||
convert_s8_f(buffer_s8, output_buffer, BUFSIZE);
|
convert_s8_f((signed char*)buffer_u8, output_buffer, the_bufsize);
|
||||||
FWRITE_R;
|
FWRITE_R;
|
||||||
TRY_YIELD;
|
TRY_YIELD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!strcmp(argv[1],"convert_f_s8")) //not tested
|
if(!strcmp(argv[1],"convert_f_s8")) //not tested
|
||||||
{
|
{
|
||||||
|
if(!sendbufsize(initialize_buffers())) return -2;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
FEOF_CHECK;
|
FEOF_CHECK;
|
||||||
FREAD_R;
|
FREAD_R;
|
||||||
convert_f_s8(input_buffer, buffer_s8, BUFSIZE);
|
convert_f_s8(input_buffer, (signed char*)buffer_u8, the_bufsize);
|
||||||
fwrite(buffer_s8, sizeof(signed char), BUFSIZE, stdout);
|
fwrite((signed char*)buffer_u8, sizeof(signed char), the_bufsize, stdout);
|
||||||
TRY_YIELD;
|
TRY_YIELD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!strcmp(argv[1],"convert_f_i16"))
|
if((!strcmp(argv[1],"convert_f_i16")) || (!strcmp(argv[1],"convert_f_s16")))
|
||||||
{
|
{
|
||||||
if(!sendbufsize(initialize_buffers())) return -2;
|
if(!sendbufsize(initialize_buffers())) return -2;
|
||||||
for(;;)
|
for(;;)
|
||||||
|
@ -400,7 +506,7 @@ int main(int argc, char *argv[])
|
||||||
TRY_YIELD;
|
TRY_YIELD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!strcmp(argv[1],"convert_i16_f")) //not tested
|
if((!strcmp(argv[1],"convert_i16_f")) || (!strcmp(argv[1],"convert_s16_f")))
|
||||||
{
|
{
|
||||||
if(!sendbufsize(initialize_buffers())) return -2;
|
if(!sendbufsize(initialize_buffers())) return -2;
|
||||||
for(;;)
|
for(;;)
|
||||||
|
@ -412,6 +518,34 @@ int main(int argc, char *argv[])
|
||||||
TRY_YIELD;
|
TRY_YIELD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(!strcmp(argv[1],"convert_f_s24"))
|
||||||
|
{
|
||||||
|
int bigendian = (argc>2) && (!strcmp(argv[2],"--bigendian"));
|
||||||
|
unsigned char* s24buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*3);
|
||||||
|
if(!sendbufsize(initialize_buffers())) return -2;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
FEOF_CHECK;
|
||||||
|
FREAD_R;
|
||||||
|
convert_f_s24(input_buffer, s24buffer, the_bufsize, bigendian);
|
||||||
|
fwrite(s24buffer, sizeof(unsigned char)*3, the_bufsize, stdout);
|
||||||
|
TRY_YIELD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!strcmp(argv[1],"convert_s24_f"))
|
||||||
|
{
|
||||||
|
int bigendian = (argc>2) && (!strcmp(argv[2],"--bigendian"));
|
||||||
|
unsigned char* s24buffer = (unsigned char*)malloc(sizeof(unsigned char)*the_bufsize*3);
|
||||||
|
if(!sendbufsize(initialize_buffers())) return -2;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
FEOF_CHECK;
|
||||||
|
fread(s24buffer, sizeof(unsigned char)*3, the_bufsize, stdin);
|
||||||
|
convert_s24_f(s24buffer, output_buffer, the_bufsize, bigendian);
|
||||||
|
FWRITE_R;
|
||||||
|
TRY_YIELD;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(!strcmp(argv[1],"realpart_cf"))
|
if(!strcmp(argv[1],"realpart_cf"))
|
||||||
{
|
{
|
||||||
if(!sendbufsize(initialize_buffers())) return -2;
|
if(!sendbufsize(initialize_buffers())) return -2;
|
||||||
|
@ -906,11 +1040,15 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
else fprintf(stderr,"fir_decimate_cc: window = %s\n",firdes_get_string_from_window(window));
|
else fprintf(stderr,"fir_decimate_cc: window = %s\n",firdes_get_string_from_window(window));
|
||||||
|
|
||||||
|
int taps_length=firdes_filter_len(transition_bw);
|
||||||
|
fprintf(stderr,"fir_decimate_cc: taps_length = %d\n",taps_length);
|
||||||
|
|
||||||
|
while (env_csdr_fixed_big_bufsize < taps_length*2) env_csdr_fixed_big_bufsize*=2; //temporary fix for buffer size if [transition_bw] is low
|
||||||
|
//fprintf(stderr, "env_csdr_fixed_big_bufsize = %d\n", env_csdr_fixed_big_bufsize);
|
||||||
|
|
||||||
if(!initialize_buffers()) return -2;
|
if(!initialize_buffers()) return -2;
|
||||||
sendbufsize(the_bufsize/factor);
|
sendbufsize(the_bufsize/factor);
|
||||||
|
|
||||||
int taps_length=firdes_filter_len(transition_bw);
|
|
||||||
fprintf(stderr,"fir_decimate_cc: taps_length = %d\n",taps_length);
|
|
||||||
|
|
||||||
int padded_taps_length = taps_length;
|
int padded_taps_length = taps_length;
|
||||||
float *taps;
|
float *taps;
|
||||||
|
@ -1255,6 +1393,8 @@ int main(int argc, char *argv[])
|
||||||
FFT_PLAN_T* plan=make_fft_c2c(fft_size, windowed, output, 1, benchmark);
|
FFT_PLAN_T* plan=make_fft_c2c(fft_size, windowed, output, 1, benchmark);
|
||||||
if(benchmark) fprintf(stderr," done\n");
|
if(benchmark) fprintf(stderr," done\n");
|
||||||
if(octave) printf("setenv(\"GNUTERM\",\"X11 noraise\");y=zeros(1,%d);semilogy(y,\"ydatasource\",\"y\");\n",fft_size);
|
if(octave) printf("setenv(\"GNUTERM\",\"X11 noraise\");y=zeros(1,%d);semilogy(y,\"ydatasource\",\"y\");\n",fft_size);
|
||||||
|
float *windowt;
|
||||||
|
windowt = precalculate_window(fft_size, window);
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
FEOF_CHECK;
|
FEOF_CHECK;
|
||||||
|
@ -1273,7 +1413,8 @@ int main(int argc, char *argv[])
|
||||||
for(int i=0;i<fft_size-every_n_samples;i++) input[i]=input[i+every_n_samples];
|
for(int i=0;i<fft_size-every_n_samples;i++) input[i]=input[i+every_n_samples];
|
||||||
fread(input+fft_size-every_n_samples, sizeof(complexf), every_n_samples, stdin);
|
fread(input+fft_size-every_n_samples, sizeof(complexf), every_n_samples, stdin);
|
||||||
}
|
}
|
||||||
apply_window_c(input,windowed,fft_size,window);
|
//apply_window_c(input,windowed,fft_size,window);
|
||||||
|
apply_precalculated_window_c(input,windowed,fft_size,windowt);
|
||||||
fft_execute(plan);
|
fft_execute(plan);
|
||||||
if(octave)
|
if(octave)
|
||||||
{
|
{
|
||||||
|
@ -1309,6 +1450,40 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!strcmp(argv[1],"logaveragepower_cf"))
|
||||||
|
{
|
||||||
|
bigbufs=1;
|
||||||
|
if(argc<=4) return badsyntax("need required parameters (add_db, table_size, avgnumber)");
|
||||||
|
float add_db=0;
|
||||||
|
int avgnumber=0;
|
||||||
|
int fft_size=0;
|
||||||
|
|
||||||
|
sscanf(argv[2],"%g",&add_db);
|
||||||
|
sscanf(argv[3],"%d",&fft_size);
|
||||||
|
sscanf(argv[4],"%d",&avgnumber);
|
||||||
|
|
||||||
|
float *input = malloc(sizeof(float)*2 * fft_size);
|
||||||
|
float *output = malloc(sizeof(float) * fft_size);
|
||||||
|
|
||||||
|
add_db -= 10.0*log10(avgnumber);
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
int i,n;
|
||||||
|
for(i = 0; i < fft_size; i++) {
|
||||||
|
output[i] = 0;
|
||||||
|
}
|
||||||
|
FEOF_CHECK;
|
||||||
|
for(n = 0; n < avgnumber; n++) {
|
||||||
|
fread (input, sizeof(float)*2, fft_size, stdin);
|
||||||
|
accumulate_power_cf((complexf*)input, output, fft_size);
|
||||||
|
}
|
||||||
|
log_ff(output, output, fft_size, add_db);
|
||||||
|
fwrite (output, sizeof(float), fft_size, stdout);
|
||||||
|
TRY_YIELD;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if(!strcmp(argv[1],"fft_exchange_sides_ff"))
|
if(!strcmp(argv[1],"fft_exchange_sides_ff"))
|
||||||
{
|
{
|
||||||
if(argc<=2) return badsyntax("need required parameters (fft_size)");
|
if(argc<=2) return badsyntax("need required parameters (fft_size)");
|
||||||
|
@ -1409,7 +1584,6 @@ int main(int argc, char *argv[])
|
||||||
float high_cut;
|
float high_cut;
|
||||||
float transition_bw;
|
float transition_bw;
|
||||||
window_t window = WINDOW_DEFAULT;
|
window_t window = WINDOW_DEFAULT;
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
if(fd=init_fifo(argc,argv))
|
if(fd=init_fifo(argc,argv))
|
||||||
{
|
{
|
||||||
|
@ -1485,7 +1659,7 @@ int main(int argc, char *argv[])
|
||||||
#ifdef USE_IMA_ADPCM
|
#ifdef USE_IMA_ADPCM
|
||||||
#define IMA_ADPCM_BUFSIZE BUFSIZE
|
#define IMA_ADPCM_BUFSIZE BUFSIZE
|
||||||
|
|
||||||
if(!strcmp(argv[1],"encode_ima_adpcm_i16_u8"))
|
if( (!strcmp(argv[1],"encode_ima_adpcm_i16_u8"))||(!strcmp(argv[1],"encode_ima_adpcm_s16_u8")) )
|
||||||
{
|
{
|
||||||
if(!sendbufsize(initialize_buffers()/2)) return -2;
|
if(!sendbufsize(initialize_buffers()/2)) return -2;
|
||||||
ima_adpcm_state_t d;
|
ima_adpcm_state_t d;
|
||||||
|
@ -1500,7 +1674,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!strcmp(argv[1],"decode_ima_adpcm_u8_i16"))
|
if( (!strcmp(argv[1],"decode_ima_adpcm_u8_i16"))||(!strcmp(argv[1],"decode_ima_adpcm_u8_s16")) )
|
||||||
{
|
{
|
||||||
ima_adpcm_state_t d;
|
ima_adpcm_state_t d;
|
||||||
d.index=d.previousValue=0;
|
d.index=d.previousValue=0;
|
||||||
|
@ -1515,7 +1689,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/*
|
|
||||||
if(!strcmp(argv[1],"flowcontrol"))
|
if(!strcmp(argv[1],"flowcontrol"))
|
||||||
{
|
{
|
||||||
if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)");
|
if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)");
|
||||||
|
@ -1537,9 +1711,9 @@ int main(int argc, char *argv[])
|
||||||
usleep(flowcontrol_sleep);
|
usleep(flowcontrol_sleep);
|
||||||
TRY_YIELD;
|
TRY_YIELD;
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
if(!strcmp(argv[1],"flowcontrol"))
|
if(!strcmp(argv[1],"flowcontrol"))
|
||||||
{
|
{
|
||||||
if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)");
|
if(argc<=3) return badsyntax("need required parameters (data_rate, reads_per_seconds)");
|
||||||
|
@ -1638,6 +1812,7 @@ int main(int argc, char *argv[])
|
||||||
TRY_YIELD;
|
TRY_YIELD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if(!strcmp(argv[1],"through"))
|
if(!strcmp(argv[1],"through"))
|
||||||
{
|
{
|
||||||
|
@ -1767,7 +1942,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!strcmp(argv[1],"mono2stereo_i16"))
|
if((!strcmp(argv[1],"mono2stereo_i16"))||(!strcmp(argv[1],"mono2stereo_s16")))
|
||||||
{
|
{
|
||||||
if(!sendbufsize(initialize_buffers())) return -2;
|
if(!sendbufsize(initialize_buffers())) return -2;
|
||||||
float last_phase = 0;
|
float last_phase = 0;
|
||||||
|
@ -1785,6 +1960,59 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!strcmp(argv[1],"squelch_and_smeter_cc"))
|
||||||
|
{
|
||||||
|
if(!sendbufsize(initialize_buffers())) return -2;
|
||||||
|
float power;
|
||||||
|
float squelch_level;
|
||||||
|
int decimation;
|
||||||
|
int report_every_nth;
|
||||||
|
int fd;
|
||||||
|
char power_value_buf[101];
|
||||||
|
int power_value_buf_size;
|
||||||
|
int report_cntr=0;
|
||||||
|
complexf* zerobuf = (complexf*)malloc(sizeof(complexf)*the_bufsize);
|
||||||
|
for(int i=0;i<the_bufsize*2;i++) *(((float*)zerobuf)+i)=0;
|
||||||
|
if(fd=init_fifo(argc,argv)) while(!read_fifo_ctl(fd,"%g\n",&squelch_level)) usleep(10000);
|
||||||
|
else return badsyntax("need required parameter (--fifo <fifo>)");
|
||||||
|
fprintf(stderr, "squelch_and_power_cc: initial squelch level is %g\n", squelch_level);
|
||||||
|
if((argc<=5)||((argc>5)&&(strcmp(argv[4],"--outfifo")))) return badsyntax("need required parameter (--outfifo <fifo>)");
|
||||||
|
int fd2 = open(argv[5], O_WRONLY);
|
||||||
|
if(fd2==-1) return badsyntax("error while opening --outfifo");
|
||||||
|
int flags = fcntl(fd2, F_GETFL, 0);
|
||||||
|
fcntl(fd2, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
if(argc<=6) return badsyntax("need required parameter (use_every_nth)");
|
||||||
|
sscanf(argv[6],"%d",&decimation);
|
||||||
|
if(decimation<=0) return badsyntax("use_every_nth <= 0 is invalid");
|
||||||
|
if(argc<=7) return badsyntax("need required parameter (report_every_nth)");
|
||||||
|
sscanf(argv[7],"%d",&report_every_nth);
|
||||||
|
if(report_every_nth<=0) return badsyntax("report_every_nth <= 0 is invalid");
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
FEOF_CHECK;
|
||||||
|
FREAD_C; //read input data
|
||||||
|
power = get_power_c((complexf*)input_buffer, the_bufsize, decimation);
|
||||||
|
if(report_cntr++>report_every_nth)
|
||||||
|
{
|
||||||
|
report_cntr=0;
|
||||||
|
power_value_buf_size=snprintf(power_value_buf,100,"%g\n",power);
|
||||||
|
write(fd2,power_value_buf,power_value_buf_size*sizeof(char));
|
||||||
|
}
|
||||||
|
if(squelch_level==0||power>=squelch_level)
|
||||||
|
{
|
||||||
|
//fprintf(stderr,"P");
|
||||||
|
fwrite(input_buffer, sizeof(complexf), the_bufsize, stdout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//fprintf(stderr,"S");
|
||||||
|
fwrite(zerobuf, sizeof(complexf), the_bufsize, stdout);
|
||||||
|
}
|
||||||
|
if(read_fifo_ctl(fd,"%g\n",&squelch_level)) fprintf(stderr, "squelch_and_power_cc: new squelch level is %g\n", squelch_level);
|
||||||
|
TRY_YIELD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( !strcmp(argv[1],"fastddc_fwd_cc") ) //<decimation> [transition_bw [window]]
|
if( !strcmp(argv[1],"fastddc_fwd_cc") ) //<decimation> [transition_bw [window]]
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -1942,9 +2170,5 @@ int main(int argc, char *argv[])
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr,"csdr: function name given in argument 1 (%s) does not exist. Possible causes:\n- You mistyped the commandline.\n- You need to update csdr to a newer version (if available).", argv[1]);
|
fprintf(stderr,"csdr: function name given in argument 1 (%s) does not exist. Possible causes:\n- You mistyped the commandline.\n- You need to update csdr to a newer version (if available).", argv[1]); return -1;
|
||||||
return -1;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
108
libcsdr.c
108
libcsdr.c
|
@ -941,7 +941,7 @@ complexf fmdemod_quadri_cf(complexf* input, float* output, int input_size, float
|
||||||
}
|
}
|
||||||
for (int i=0; i<input_size; i++) //@fmdemod_quadri_cf: output division
|
for (int i=0; i<input_size; i++) //@fmdemod_quadri_cf: output division
|
||||||
{
|
{
|
||||||
output[i]=fmdemod_quadri_K*output[i]/temp[i];
|
output[i]=(temp[i])?fmdemod_quadri_K*output[i]/temp[i]:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return input[input_size-1];
|
return input[input_size-1];
|
||||||
|
@ -1018,6 +1018,26 @@ void gain_ff(float* input, float* output, int input_size, float gain)
|
||||||
for(int i=0;i<input_size;i++) output[i]=gain*input[i]; //@gain_ff
|
for(int i=0;i<input_size;i++) output[i]=gain*input[i]; //@gain_ff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float get_power_f(float* input, int input_size, int decimation)
|
||||||
|
{
|
||||||
|
float acc = 0;
|
||||||
|
for(int i=0;i<input_size;i+=decimation)
|
||||||
|
{
|
||||||
|
acc += (input[i]*input[i])/input_size;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
float get_power_c(complexf* input, int input_size, int decimation)
|
||||||
|
{
|
||||||
|
float acc = 0;
|
||||||
|
for(int i=0;i<input_size;i+=decimation)
|
||||||
|
{
|
||||||
|
acc += (iof(input,i)*iof(input,i)+qof(input,i)*qof(input,i))/input_size;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
__ __ _ _ _
|
__ __ _ _ _
|
||||||
| \/ | | | | | | |
|
| \/ | | | | | | |
|
||||||
|
@ -1110,6 +1130,29 @@ void apply_window_c(complexf* input, complexf* output, int size, window_t window
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float *precalculate_window(int size, window_t window)
|
||||||
|
{
|
||||||
|
float (*window_function)(float)=firdes_get_window_kernel(window);
|
||||||
|
float *windowt;
|
||||||
|
windowt = malloc(sizeof(float) * size);
|
||||||
|
for(int i=0;i<size;i++) //@precalculate_window
|
||||||
|
{
|
||||||
|
float rate=(float)i/(size-1);
|
||||||
|
windowt[i] = window_function(2.0*rate+1.0);
|
||||||
|
}
|
||||||
|
return windowt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_precalculated_window_c(complexf* input, complexf* output, int size, float *windowt)
|
||||||
|
{
|
||||||
|
for(int i=0;i<size;i++) //@apply_precalculated_window_c
|
||||||
|
{
|
||||||
|
iof(output,i)=iof(input,i)*windowt[i];
|
||||||
|
qof(output,i)=qof(input,i)*windowt[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void apply_window_f(float* input, float* output, int size, window_t window)
|
void apply_window_f(float* input, float* output, int size, window_t window)
|
||||||
{
|
{
|
||||||
float (*window_function)(float)=firdes_get_window_kernel(window);
|
float (*window_function)(float)=firdes_get_window_kernel(window);
|
||||||
|
@ -1129,6 +1172,19 @@ void logpower_cf(complexf* input, float* output, int size, float add_db)
|
||||||
for(int i=0;i<size;i++) output[i]=10*output[i]+add_db; //@logpower_cf: pass 3
|
for(int i=0;i<size;i++) output[i]=10*output[i]+add_db; //@logpower_cf: pass 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void accumulate_power_cf(complexf* input, float* output, int size)
|
||||||
|
{
|
||||||
|
for(int i=0;i<size;i++) output[i] += iof(input,i)*iof(input,i) + qof(input,i)*qof(input,i); //@logpower_cf: pass 1
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_ff(float* input, float* output, int size, float add_db) {
|
||||||
|
for(int i=0;i<size;i++) output[i]=log10(input[i]); //@logpower_cf: pass 2
|
||||||
|
|
||||||
|
for(int i=0;i<size;i++) output[i]=10*output[i]+add_db; //@logpower_cf: pass 3
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
_____ _ _
|
_____ _ _
|
||||||
| __ \ | | (_)
|
| __ \ | | (_)
|
||||||
|
@ -1149,9 +1205,9 @@ void convert_s8_f(signed char* input, float* output, int input_size)
|
||||||
for(int i=0;i<input_size;i++) output[i]=((float)input[i])/SCHAR_MAX; //@convert_s8_f
|
for(int i=0;i<input_size;i++) output[i]=((float)input[i])/SCHAR_MAX; //@convert_s8_f
|
||||||
}
|
}
|
||||||
|
|
||||||
void convert_i16_f(short* input, float* output, int input_size)
|
void convert_s16_f(short* input, float* output, int input_size)
|
||||||
{
|
{
|
||||||
for(int i=0;i<input_size;i++) output[i]=(float)input[i]/SHRT_MAX; //@convert_i16_f
|
for(int i=0;i<input_size;i++) output[i]=(float)input[i]/SHRT_MAX; //@convert_s16_f
|
||||||
}
|
}
|
||||||
|
|
||||||
void convert_f_u8(float* input, unsigned char* output, int input_size)
|
void convert_f_u8(float* input, unsigned char* output, int input_size)
|
||||||
|
@ -1166,16 +1222,56 @@ void convert_f_s8(float* input, signed char* output, int input_size)
|
||||||
for(int i=0;i<input_size;i++) output[i]=input[i]*SCHAR_MAX; //@convert_f_s8
|
for(int i=0;i<input_size;i++) output[i]=input[i]*SCHAR_MAX; //@convert_f_s8
|
||||||
}
|
}
|
||||||
|
|
||||||
void convert_f_i16(float* input, short* output, int input_size)
|
void convert_f_s16(float* input, short* output, int input_size)
|
||||||
{
|
{
|
||||||
/*for(int i=0;i<input_size;i++)
|
/*for(int i=0;i<input_size;i++)
|
||||||
{
|
{
|
||||||
if(input[i]>1.0) input[i]=1.0;
|
if(input[i]>1.0) input[i]=1.0;
|
||||||
if(input[i]<-1.0) input[i]=-1.0;
|
if(input[i]<-1.0) input[i]=-1.0;
|
||||||
}*/
|
}*/
|
||||||
for(int i=0;i<input_size;i++) output[i]=input[i]*SHRT_MAX; //@convert_f_i16
|
for(int i=0;i<input_size;i++) output[i]=input[i]*SHRT_MAX; //@convert_f_s16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void convert_i16_f(short* input, float* output, int input_size) { convert_s16_f(input, output, input_size); }
|
||||||
|
void convert_f_i16(float* input, short* output, int input_size) { convert_f_s16(input, output, input_size); }
|
||||||
|
|
||||||
|
void convert_f_s24(float* input, unsigned char* output, int input_size, int bigendian)
|
||||||
|
{
|
||||||
|
int k=0;
|
||||||
|
if(bigendian) for(int i=0;i<input_size;i++)
|
||||||
|
{
|
||||||
|
int temp=input[i]*(INT_MAX>>8);
|
||||||
|
unsigned char* ptemp=(unsigned char*)&temp;
|
||||||
|
output[k++]=*ptemp;
|
||||||
|
output[k++]=*(ptemp+1);
|
||||||
|
output[k++]=*(ptemp+2);
|
||||||
|
}
|
||||||
|
else for(int i=0;i<input_size;i++)
|
||||||
|
{
|
||||||
|
int temp=input[i]*(INT_MAX>>8);
|
||||||
|
unsigned char* ptemp=(unsigned char*)&temp;
|
||||||
|
output[k++]=*(ptemp+2);
|
||||||
|
output[k++]=*(ptemp+1);
|
||||||
|
output[k++]=*ptemp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void convert_s24_f(unsigned char* input, float* output, int input_size, int bigendian)
|
||||||
|
{
|
||||||
|
int k=0;
|
||||||
|
if(bigendian) for(int i=0;i<input_size*3;i+=3)
|
||||||
|
{
|
||||||
|
int temp=(input[i+2]<<24)|(input[i+1]<<16)|(input[i]<<8);
|
||||||
|
output[k++]=temp/(float)(INT_MAX-256);
|
||||||
|
}
|
||||||
|
else for(int i=0;i<input_size*3;i+=3)
|
||||||
|
{
|
||||||
|
int temp=(input[i+2]<<8)|(input[i+1]<<16)|(input[i]<<24);
|
||||||
|
output[k++]=temp/(float)(INT_MAX-256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int trivial_vectorize()
|
int trivial_vectorize()
|
||||||
{
|
{
|
||||||
//this function is trivial to vectorize and should pass on both NEON and SSE
|
//this function is trivial to vectorize and should pass on both NEON and SSE
|
||||||
|
@ -1186,5 +1282,3 @@ int trivial_vectorize()
|
||||||
}
|
}
|
||||||
return c[0];
|
return c[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
11
libcsdr.h
11
libcsdr.h
|
@ -137,9 +137,13 @@ typedef struct rational_resampler_ff_s
|
||||||
rational_resampler_ff_t rational_resampler_ff(float *input, float *output, int input_size, int interpolation, int decimation, float *taps, int taps_length, int last_taps_delay);
|
rational_resampler_ff_t rational_resampler_ff(float *input, float *output, int input_size, int interpolation, int decimation, float *taps, int taps_length, int last_taps_delay);
|
||||||
void rational_resampler_get_lowpass_f(float* output, int output_size, int interpolation, int decimation, window_t window);
|
void rational_resampler_get_lowpass_f(float* output, int output_size, int interpolation, int decimation, window_t window);
|
||||||
|
|
||||||
|
float *precalculate_window(int size, window_t window);
|
||||||
void apply_window_c(complexf* input, complexf* output, int size, window_t window);
|
void apply_window_c(complexf* input, complexf* output, int size, window_t window);
|
||||||
|
void apply_precalculated_window_c(complexf* input, complexf* output, int size, float *windowt);
|
||||||
void apply_window_f(float* input, float* output, int size, window_t window);
|
void apply_window_f(float* input, float* output, int size, window_t window);
|
||||||
void logpower_cf(complexf* input, float* output, int size, float add_db);
|
void logpower_cf(complexf* input, float* output, int size, float add_db);
|
||||||
|
void accumulate_power_cf(complexf* input, float* output, int size);
|
||||||
|
void log_ff(float* input, float* output, int size, float add_db);
|
||||||
|
|
||||||
typedef struct fractional_decimator_ff_s
|
typedef struct fractional_decimator_ff_s
|
||||||
{
|
{
|
||||||
|
@ -182,6 +186,8 @@ int log2n(int x);
|
||||||
int next_pow2(int x);
|
int next_pow2(int x);
|
||||||
void apply_fir_fft_cc(FFT_PLAN_T* plan, FFT_PLAN_T* plan_inverse, complexf* taps_fft, complexf* last_overlap, int overlap_size);
|
void apply_fir_fft_cc(FFT_PLAN_T* plan, FFT_PLAN_T* plan_inverse, complexf* taps_fft, complexf* last_overlap, int overlap_size);
|
||||||
void gain_ff(float* input, float* output, int input_size, float gain);
|
void gain_ff(float* input, float* output, int input_size, float gain);
|
||||||
|
float get_power_f(float* input, int input_size, int decimation);
|
||||||
|
float get_power_c(complexf* input, int input_size, int decimation);
|
||||||
|
|
||||||
void add_dcoffset_cc(complexf* input, complexf* output, int input_size);
|
void add_dcoffset_cc(complexf* input, complexf* output, int input_size);
|
||||||
float fmmod_fc(float* input, complexf* output, int input_size, float last_phase);
|
float fmmod_fc(float* input, complexf* output, int input_size, float last_phase);
|
||||||
|
@ -191,7 +197,12 @@ void convert_u8_f(unsigned char* input, float* output, int input_size);
|
||||||
void convert_f_u8(float* input, unsigned char* output, int input_size);
|
void convert_f_u8(float* input, unsigned char* output, int input_size);
|
||||||
void convert_s8_f(signed char* input, float* output, int input_size);
|
void convert_s8_f(signed char* input, float* output, int input_size);
|
||||||
void convert_f_s8(float* input, signed char* output, int input_size);
|
void convert_f_s8(float* input, signed char* output, int input_size);
|
||||||
|
void convert_f_s16(float* input, short* output, int input_size);
|
||||||
|
void convert_s16_f(short* input, float* output, int input_size);
|
||||||
void convert_f_i16(float* input, short* output, int input_size);
|
void convert_f_i16(float* input, short* output, int input_size);
|
||||||
void convert_i16_f(short* input, float* output, int input_size);
|
void convert_i16_f(short* input, float* output, int input_size);
|
||||||
|
void convert_f_s24(float* input, unsigned char* output, int input_size, int bigendian);
|
||||||
|
void convert_s24_f(unsigned char* input, float* output, int input_size, int bigendian);
|
||||||
|
|
||||||
|
|
||||||
int is_nan(float f);
|
int is_nan(float f);
|
||||||
|
|
|
@ -219,10 +219,9 @@ float agc_ff(float* input, float* output, int input_size, float reference, float
|
||||||
}
|
}
|
||||||
gain=gain+dgain;
|
gain=gain+dgain;
|
||||||
//fprintf(stderr,"g=%f dg=%f\n",gain,dgain);
|
//fprintf(stderr,"g=%f dg=%f\n",gain,dgain);
|
||||||
|
}
|
||||||
if(gain>max_gain) gain=max_gain; //We also have to limit our gain, it can't be infinity.
|
if(gain>max_gain) gain=max_gain; //We also have to limit our gain, it can't be infinity.
|
||||||
if(gain<0) gain=0;
|
if(gain<0) gain=0;
|
||||||
}
|
|
||||||
//output[i]=gain*input[i]; //Here we do the actual scaling of the samples.
|
//output[i]=gain*input[i]; //Here we do the actual scaling of the samples.
|
||||||
//Here we do the actual scaling of the samples, but we run an IIR filter on the gain values:
|
//Here we do the actual scaling of the samples, but we run an IIR filter on the gain values:
|
||||||
output[i]=(gain=gain+last_gain-gain_filter_alpha*last_gain)*input[i]; //dc-pass-filter: freqz([1 -1],[1 -0.99]) y[i]=x[i]+y[i-1]-alpha*x[i-1]
|
output[i]=(gain=gain+last_gain-gain_filter_alpha*last_gain)*input[i]; //dc-pass-filter: freqz([1 -1],[1 -0.99]) y[i]=x[i]+y[i-1]-alpha*x[i-1]
|
||||||
|
@ -234,4 +233,3 @@ float agc_ff(float* input, float* output, int input_size, float reference, float
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue