Skip to content

Commit

Permalink
build and publish docker containers (#444)
Browse files Browse the repository at this point in the history
* build and publish docker containers
* changes to supported `cmake` platforms:
  * depreciate `rpiv1`, `armv7-generic`, and `armv8-generic` and build platforms
  * change default build platform to `native`
  * rename `default` to `generic`
* enable a series of compile warnings and cleanup code
* remove `SSE` specific code - let the compiler "do the right thing"
* remove some no longer supported windows `ifdef`'s
* fix CTCSS bug that could miss a tone when multiple tones have the same power (happens with less accurate floating point operations, ie i386)
  • Loading branch information
charlie-foxtrot authored Jan 21, 2024
1 parent 6aaf698 commit dad1a8b
Show file tree
Hide file tree
Showing 25 changed files with 317 additions and 287 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"twxs.cmake",
"streetsidesoftware.code-spell-checker",
"ms-azuretools.vscode-docker",
"GitHub.vscode-github-actions"
"GitHub.vscode-github-actions"
]
}
},
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name: Test build
on:
push:
branches: [main, unstable]
tags: ['v*']
pull_request:
schedule:
- cron: '39 13 * * *' # run daily
Expand All @@ -18,8 +19,8 @@ jobs:
- name: Runner Info
run: printenv | sort

- name: Checkout repository
uses: actions/checkout@main
- name: Checkout
uses: actions/checkout@v4

- name: Install packaged dependencies
run: .github/install_dependencies
Expand Down
51 changes: 51 additions & 0 deletions .github/workflows/build_containers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Build and Publish Containers

on:
push:
branches: [main, unstable]
tags: ['v*']
pull_request:
workflow_dispatch:
schedule:
- cron: '29 13 * * *' # run daily

jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Runner Info
run: printenv | sort

- name: Checkout
uses: actions/checkout@v4

- name: Container metadata
id: metadata
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}

# Add support for more platforms with QEMU - https://github.com/docker/setup-qemu-action
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v5
with:
platforms: linux/amd64, linux/386, linux/arm64, linux/arm/v6, linux/arm/v7
cache-from: type=gha
cache-to: type=gha,mode=max
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}

4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ if(NOT CMAKE_BUILD_TYPE)
message(STATUS "Build type not specified: defaulting to Release")
endif(NOT CMAKE_BUILD_TYPE)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
# TODO: flags to add: -Wfloat-equal -Wconversion -Wstrict-overflow=5 -Waggregate-return -Wpedantic -Wcast-align
# TODO: these could be added except for gtest: -Wswitch-enum -Wundef -Wswitch-default
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wshadow -Wdate-time -Wpointer-arith -Wwrite-strings -Wcast-qual -Wunreachable-code -Werror")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -DDEBUG")

if(DEBUG_SQUELCH)
Expand Down
100 changes: 100 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# build container
FROM debian:bookworm-slim AS build

# set working dir
WORKDIR /app

# install build dependencies
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y --no-install-recommends \
build-essential \
cmake \
libmp3lame-dev \
libshout3-dev \
libconfig++-dev \
libfftw3-dev \
libsoapysdr-dev \
libpulse-dev \
\
git \
ca-certificates \
libusb-1.0-0-dev \
debhelper \
pkg-config \
&& \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# compile / install rtl-sdr-blog version of rtl-sdr for v4 support
RUN git clone https://github.com/rtlsdrblog/rtl-sdr-blog && \
cd rtl-sdr-blog/ && \
dpkg-buildpackage -b --no-sign && \
cd .. && \
dpkg -i librtlsdr0_*.deb && \
dpkg -i librtlsdr-dev_*.deb && \
dpkg -i rtl-sdr_*.deb


# TODO: build anything from source?

# copy in the rtl_airband source
COPY CMakeLists.txt src /app/

# configure and build
# TODO: detect platforms
RUN uname -m && \
echo | gcc -### -v -E - | tee /app/compiler_native_info.txt && \
cmake -B build_dir -DPLATFORM=generic -DCMAKE_BUILD_TYPE=Release -DNFM=TRUE -DBUILD_UNITTESTS=TRUE && \
VERBOSE=1 cmake --build build_dir -j4

# make sure unit tests pass
RUN ./build_dir/unittests


# application container
FROM debian:bookworm-slim

# set working dir
WORKDIR /app

# install runtime dependencies
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y --no-install-recommends \
tini \
libc6 \
libmp3lame0 \
libshout3 \
libconfig++9v5 \
libfftw3-single3 \
libsoapysdr0.8 \
libpulse0 \
libusb-1.0-0-dev \
&& \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# install (from build container) rtl-sdr-blog version of rtl-sdr for v4 support
COPY --from=build /app/librtlsdr0_*.deb /app/librtlsdr-dev_*.deb /app/rtl-sdr_*.deb ./
RUN dpkg -i librtlsdr0_*.deb && \
dpkg -i librtlsdr-dev_*.deb && \
dpkg -i rtl-sdr_*.deb && \
rm -rf *.deb && \
echo '' | tee --append /etc/modprobe.d/rtl_sdr.conf && \
echo 'blacklist dvb_usb_rtl28xxun' | tee --append /etc/modprobe.d/rtl_sdr.conf && \
echo 'blacklist rtl2832' | tee --append /etc/modprobe.d/rtl_sdr.conf && \
echo 'blacklist rtl2830' | tee --append /etc/modprobe.d/rtl_sdr.conf

# Copy rtl_airband from the build container
COPY LICENSE /opt/rtl_airband/
COPY --from=build /app/build_dir/unittests /opt/rtl_airband/
COPY --from=build /app/build_dir/rtl_airband /opt/rtl_airband/
RUN chmod a+x /opt/rtl_airband/unittests /opt/rtl_airband/rtl_airband

# make sure unit tests pass
RUN /opt/rtl_airband/unittests

# Use tini as init and run rtl_airband
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["/opt/rtl_airband/rtl_airband", "-F", "-e"]
32 changes: 12 additions & 20 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ set(CMAKE_REQUIRED_LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS_SAVE})

option(NFM "Enable support for narrow FM channels" OFF)

set(PLATFORM "default" CACHE STRING "Optimize the build for the given hardware platform")
set(PLATFORM "native" CACHE STRING "Optimize the build for the given hardware platform")

option(RTLSDR "Enable RTL-SDR support" ON)
set(WITH_RTLSDR FALSE)
Expand Down Expand Up @@ -192,38 +192,30 @@ endif()
option(BCM_VC "Enable Broadcom Videocore 3 support" OFF)
set(WITH_BCM_VC FALSE)

if(PLATFORM STREQUAL "rpiv1")
set(BCM_VC ON)
add_compile_options(-march=armv6zk -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mfpu=vfp)
enable_language(ASM)
list(APPEND rtl_airband_extra_sources rtl_airband_vfp.s)
# error out on depricated PLATFORM values
if(PLATFORM STREQUAL "rpiv1" OR PLATFORM STREQUAL "armv7-generic" OR PLATFORM STREQUAL "armv8-generic")
message(FATAL_ERROR "platform '${PLATFORM}' has been deprecated, see https://github.com/charlie-foxtrot/RTLSDR-Airband/discussions/447")
# rpiv2 - Raspberry Pi 2 or Raspberry Pi 3 using Broadcom VideoCore IV GPU for FFT
# NOTE: use 'native' to not use the GPU for FFT
elseif(PLATFORM STREQUAL "rpiv2")
set(BCM_VC ON)
add_compile_options(-march=armv7-a -mfpu=neon-vfpv4 -mfloat-abi=hard)
enable_language(ASM)
list(APPEND rtl_airband_extra_sources rtl_airband_neon.s)
elseif(PLATFORM STREQUAL "armv7-generic")
add_compile_options(-march=armv7-a -mfpu=neon-vfpv4 -mfloat-abi=hard)
elseif(PLATFORM STREQUAL "armv8-generic")
add_compile_options(-march=armv8-a+crc -mtune=cortex-a53)
# native - let the complier optimize to run on local hardware (default)
elseif(PLATFORM STREQUAL "native")
CHECK_CXX_COMPILER_FLAG(-march=native CXX_HAS_MARCH_NATIVE)
if(CXX_HAS_MARCH_NATIVE)
add_compile_options(-march=native)
else()
message(FATAL_ERROR "Cannot build with PLATFORM=native: the compiler does not support -march=native option")
endif()
CHECK_CXX_COMPILER_FLAG(-mtune=native CXX_HAS_MTUNE_NATIVE)
if(CXX_HAS_MTUNE_NATIVE)
add_compile_options(-mtune=native)
else()
message(FATAL_ERROR "Cannot build with PLATFORM=native: the compiler does not support -mtune=native option")
endif()
elseif(PLATFORM STREQUAL "default")
# NOOP
# generic - dont add any hardware related flags, used to build a "portable" binary
elseif(PLATFORM STREQUAL "generic")
# NO-OP
# error out on unrecongnnized PLATFORM value
else()
message(FATAL_ERROR "Unknown platform '${PLATFORM}'. Valid options are:
rpiv1, rpiv2, armv7-generic, armv8-generic, native, default")
message(FATAL_ERROR "Unknown platform '${PLATFORM}'. Valid options are: rpiv2, native, and generic")
endif()

# Try using VC GPU if enabled. Fallback to fftw3f if disabled or if VC lib not found
Expand Down
20 changes: 10 additions & 10 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ static int parse_outputs(libconfig::Setting &outs, channel_t *channel, int i, in
} else {
idata->tls_mode = SHOUT_TLS_DISABLED;
}
#endif // LIBSHOUT_HAS_TLS
#endif /* LIBSHOUT_HAS_TLS */
channel->need_mp3 = 1;
} else if(!strncmp(outs[o]["type"], "file", 4)) {
channel->outputs[oo].data = XCALLOC(1, sizeof(struct file_data));
Expand Down Expand Up @@ -255,7 +255,7 @@ static int parse_outputs(libconfig::Setting &outs, channel_t *channel, int i, in
snprintf(buf, sizeof(buf), "%.3f MHz", (float)channel->freqlist[0].frequency / 1000000.0f);
pdata->stream_name = strdup(buf);
}
#endif
#endif /* WITH_PULSEAUDIO */
} else {
if(parsing_mixers) {
cerr << "Configuration error: mixers.["<<i<<"] outputs.["<<o<<"]: ";
Expand Down Expand Up @@ -342,7 +342,7 @@ static int parse_channels(libconfig::Setting &chans, device_t *dev, int i) {
channel->pj = 0;
channel->prev_waveout = 0.5;
channel->alpha = dev->alpha;
#endif
#endif /* NFM */

// Make sure lowpass / highpass aren't flipped.
// If lowpass is enabled (greater than zero) it must be larger than highpass
Expand All @@ -357,7 +357,7 @@ static int parse_channels(libconfig::Setting &chans, device_t *dev, int i) {
if(strncmp(chans[j]["modulation"], "nfm", 3) == 0) {
channel_modulation = MOD_NFM;
} else
#endif
#endif /* NFM */
if(strncmp(chans[j]["modulation"], "am", 2) != 0) {
cerr<<"Configuration error: devices.["<<i<<"] channels.["<<j<<"]: unknown modulation\n";
error();
Expand Down Expand Up @@ -430,7 +430,7 @@ static int parse_channels(libconfig::Setting &chans, device_t *dev, int i) {
if(strncmp(chans[j]["modulations"][f], "nfm", 3) == 0) {
channel->freqlist[f].modulation = MOD_NFM;
} else
#endif
#endif /* NFM */
if(strncmp(chans[j]["modulations"][f], "am", 2) == 0) {
channel->freqlist[f].modulation = MOD_AM;
} else {
Expand Down Expand Up @@ -668,7 +668,7 @@ static int parse_channels(libconfig::Setting &chans, device_t *dev, int i) {
if(chans[j].exists("tau")) {
channel->alpha = ((int)chans[j]["tau"] == 0 ? 0.0f : exp(-1.0f/(WAVE_RATE * 1e-6 * (int)chans[j]["tau"])));
}
#endif
#endif /* NFM */
libconfig::Setting &outputs = chans[j]["outputs"];
channel->output_count = outputs.getLength();
if(channel->output_count < 1) {
Expand Down Expand Up @@ -697,7 +697,7 @@ static int parse_channels(libconfig::Setting &chans, device_t *dev, int i) {
break;
}
}
#endif
#endif /* NFM */

if(channel->needs_raw_iq) {
// Downmixing is done only for NFM and raw IQ outputs. It's not critical to have some residual
Expand Down Expand Up @@ -743,7 +743,7 @@ static int parse_channels(libconfig::Setting &chans, device_t *dev, int i) {
snprintf(tmp_filepath, sizeof(tmp_filepath), "./squelch_debug-%d-%d.dat", j, f);
channel->freqlist[f].squelch.set_debug_file(tmp_filepath);
}
#endif
#endif /* DEBUG_SQUELCH */

jj++;
}
Expand All @@ -768,7 +768,7 @@ int parse_devices(libconfig::Setting &devs) {
#else
cerr<<"Configuration error: devices.["<<i<<"]: mandatory parameter missing: type\n";
error();
#endif
#endif /* WITH_RTLSDR */
}
assert(dev->input != NULL);
if(devs[i].exists("sample_rate")) {
Expand Down Expand Up @@ -800,7 +800,7 @@ int parse_devices(libconfig::Setting &devs) {
} else {
dev->alpha = alpha;
}
#endif
#endif /* NFM */

// Parse hardware-dependent configuration parameters
if(input_parse_config(dev->input, devs[i]) < 0) {
Expand Down
2 changes: 1 addition & 1 deletion src/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@

#define SHOUT_SET_METADATA @SHOUT_SET_METADATA@

#endif // !_CONFIG_H
#endif /* _CONFIG_H */
18 changes: 13 additions & 5 deletions src/ctcss.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,17 +146,25 @@ void CTCSS::process_audio_sample(const float &sample) {

enough_samples_ = true;

// if this is sample fills out the window then check if the strongest tone is
// the CTCSS tone we are looking for
// if this is sample fills out the window then check if one of the "strongest"
// tones is the CTCSS tone we are looking for. NOTE: there can be multiple "strongest"
// tones based on floating point math
vector<ToneDetectorSet::PowerIndex> tone_powers;
float avg_power = powers_.sorted_powers(tone_powers);
if (tone_powers[0].freq == ctcss_freq_ && tone_powers[0].power > avg_power) {
float ctcss_tone_power = 0.0;
for( const auto i:tone_powers) {
if (i.freq == ctcss_freq_) {
ctcss_tone_power = i.power;
break;
}
}
if (ctcss_tone_power == tone_powers[0].power && ctcss_tone_power > avg_power) {
debug_print("CTCSS tone of %f Hz detected\n", ctcss_freq_);
has_tone_ = true;
found_count_++;
} else {
debug_print("CTCSS tone of %f Hz not detected - highest power was %f Hz at %f\n",
ctcss_freq_, tone_powers[0].freq, tone_powers[0].power);
debug_print("CTCSS tone of %f Hz not detected - highest power was %f Hz at %f vs %f\n",
ctcss_freq_, tone_powers[0].freq, tone_powers[0].power, ctcss_tone_power);
has_tone_ = false;
not_found_count_++;
}
Expand Down
3 changes: 0 additions & 3 deletions src/input-common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifdef __MINGW32__
#define _GNU_SOURCE 1 // asprintf
#endif

#include <iostream>
#include <assert.h>
Expand Down
Loading

0 comments on commit dad1a8b

Please sign in to comment.