strength - A QT Program To Monitor DVB Adapter Signal Strength

strength is a program I wrote to help me get my antenna system optimized for different stations in different directions under varying conditions. It started out as "Signal" (short for Signal Strength) but an apparent bug in QTCreator (GUI QT development IDE) got confused by the name (QT uses "signals" and "slots" for communication between widgets) and couldn't add Exit to the File menu, so I started over and called it strength.

I am making it available, here, for anyone who wants to use it. That said, I am offering the code as-is. I'm explaining how it works and how to use it, but am not offering support, as such. I have not been real diligent about error-checking or testing it: if it crashes on you, I'd like to hear what you did that I didn't exptect (happens at work all the time!) and I might even fix it, but since I know what I wanted and wrote it for my own use, I can't guarantee someone else might try to use it in a way that will make bugs show up.

I have no idea what libraries and packages my be required to make it build and/or run. It is developed for QT Version 5.?? using packages installed on Fedora 31, where I installed QT libraries and development packages, but it runs fine on my laptop, which is a standard Fedora 31 install and I don't remember having to install anything special. It is my second QT program and writing it has been my self-tutorial, so forgive me if you are a QT expert and find my code ridiculous. The more I use QT, the more I like it and have already used it for two production programs at work (I'm an electronics test engineer). I've been writing Windows programs for most of my career, but after years of dealing with the frustration of constant obsolescence on that platform and an I.T. department that does not take us hardware/software folks into account when they lay down corporate edicts, I have started using Linux on any new systems I set up. The maturity of the Linux platforms (which I have used at home since Redhat 1.0) has made this practical and QTCreator is as good as Visual Studio and better in many ways (the best part is it's non-Micro$oft!).

I have a Hauppauge USB dual tuner that I plug into the laptop which I carry around on the roof and in the attick and monitor two channels simultaneously while making changes. I have a Hauppauge Quad PCIE tuner in my HTPC, as well as a Dvico Fusion Gold dual tuner, giving me six tuners, which I can monitor remotely from the laptop over wifi and ssh. strength also lets me log a set of channels using cron jobs once/hour on each of the two internal cards for performance comparisons under varying weather conditions.

The difference between a "tuner" and an "adapter" is, in my mind, semantics. The adapter is how the driver and OS refer to a device that can tune and decode a digital TV signal, while a tuner is more of a layman's term. I think there is little difference, really, and I may use the terms interchangeably. The program refers to them as "adapters".

I started working with DVB TV tuner adapters using dvb-apps, a collection of utilities for working with DVB tuners. Specifically, I use scandvb to scan for channels, and azap to tune in and monitor ATSC channels. azap is great for early stages of getting things working, but its slowness and busy, hard-to-decipher output make it less than ideal for optimizing a system. Here's a sample of its output:

status 1f | signal d709 | snr 00c0 | ber ffffffff | unc 000000ff | FE_HAS_LOCK
status 1f | signal d709 | snr 00c0 | ber ffffffff | unc 00000000 | FE_HAS_LOCK
status 1f | signal d709 | snr 00c0 | ber ffffffff | unc 00000000 | FE_HAS_LOCK

These lines are printed once/second, WAY too slow for adjusting an antenna. Also, what do these numbers mean? Anything? Why are they not at least decimal numbers? Why hex?

So I downloaded the source, found azap.c and figured out how to "zap" a channel (why they call it zapping, I'll never know). I wrote a GUI app to use my zapping routine and strength began to take shape. There are other "zap"-ers in the dvb-apps package, but I don't use them or know exactly what they are for. I just deal with OTA US TV (the "a" in azap stands for ATSC, the standard for US digital TV), so that's all that strength is currently capable of. I'm guessing it would not be difficult to modify my "zapper" to handle the other types of signals.

Currently, strength can:

Download

In this tar file, there is a directory called strength that contains the QT project. With any luck, you can just load it into QTCreator and build it. I have, however, included the Release and Debug directories where the respective executables reside. If it runs, you can start zapping right away. If not, rebuild for your system. While I say I offer no support, I would still like to hear how it goes (and maybe answer a few questions, maybe give some advice).

The tar file also contains another directory called utilities. In there is a perl script called merge_channels.pl that I wrote to combine channel configuration files. I found that scanning (using scandvb) on different days gives different results. I scan for channels with the antenna in different locations and pointing in different directions and end up with some channels in some files and no files with all channels, so the script reads a list of files and outputs a list of distinct channels. Also, channels change (recent channel "repack", for example), so if there are duplicates (same name), it outputs the one from the file with the latest date. I included a couple of my channels config files as examples, as well as a log file I've been using for logging performance of two brands of tuners over time. More on that on this Analysing The Logged Data page.

Using strength

Scan for channels using scandvb and redirect its output to a channels file. Here is the command I use:
scandvb -a 3 -n -U -x 0 -t 1 /usr/share/dvbv3/atsc/us-ATSC-center-frequencies-8VSB > channels.conf
Run strength and select Load Channels File from the the File menu to load the file. Double-click on a channel to start monitoring signal strength. Signal-to-noise ratio (SNR) is more important than strength, but, depending on the tuner design, both are relevant. If the signal is strong enough, the tuner will lock onto the the carrier and start decoding the digital stream. The graph will turn green and the green Has Lock enunciator will show and the Watch button will be enabled. Double-clicking a different channel will stop monitoring the first channel and tune in the new one.

Select Settings from the File menu and set app preferences. The Settings window lets you set the following:

Settings can be saved or simply applied. The latter does not save changes in the app's .ini file (which is ~/.strength.ini) but applies them for use in the current session, discarding them when the instance exits.

Screenshots

Here's a screenshot of the app with a typical channel tuned and monitoring:

The two drop-down lists to the right of the "Has Lock" enunciator that say "Any Chip" and "Any Adapter" are populated at startup and allow specifying either. If no chip or adapter are specified, strength will simply use the next available adapter. The list of adapters is populated with the command /bin/ls /dev/dvb. The last digit from each adapter is then used in a command to get a unique ID from dmesg that started out as what I was calling the "chip" until I got my Hauppauge Quad and found it was the same "chip" as my Dvico Dual. Turns out that the "chip" I found with dmesg was actually the PCIE interface chip used on the card. Since I wanted to compare performance of these two devices, I needed a different way to identify the adapters on the respective tuner cards. While I still refer to this identifier as the "chip", it actually refers to a unique string generated with this dmesg command:
dmesg | sed -n -r 's/\[[ 0-9.]+\]\s+(\S+)\s+\S+\s+DVB: registering adapter 0 frontend [0-9] \((\S+) .+/\1_\2/p'
This technique results in two entries in my list of chips (cx23885_LG and cx23885_Samsung) and six entries in my list of adapters. In the text widget of the above screenshot, you can see the adapter0 is on the Hauppauge which, I know from experience, is the cx23885_LG chip, used on the Hauppauge Quad.

This dmesg method works, ok, but the driver for the Hauppauge spams the system logs every time it changes channels and the entries that I'm using to identify the devices drop off the bottom of the log after about 4 days and I have to reboot to start logging correctly again. On the graph, below, the hole in the data from Jan 4th to Jan 8th is when that first happened and it was logging "unknown" for the chip.

I have since made it an error if a specified chip can not be found instead of silently logging "unknown" so I'll get an email from my cron daemon and know when it's time to reboot.

I've done some work to find a better way, but so far, everything I try has some limitation. I'm sure there's a better way, but for now, if it can't find the adapter in dmesg's output, it looks for it in /tmp/dmesg.out, which I create at each system boot.

A few lines from my log file showing how I distinquish between the adapters with the dmesg output:

1, 30.3, 569, 60.0, 60.0, 60.0, 210, 210, 210, 100.0, 85, 13, 4, KOMO, cx23885_Samsung, 1.25, 1610907795, Sun Jan 17 10:23:15 2021
2, 25.3, 539, 72.9, 70.0, 71.4, 250, 245, 249, 100.0, 86, 13, 4, KING-HD, cx23885_Samsung, 1.25, 1610907809, Sun Jan 17 10:23:29 2021
1, 30.3, 569, 89.0, 87.0, 87.2, 217, 207, 207, 100.0, 47, 14, 0, KOMO, cx23885_LG, 1.25, 1610911156, Sun Jan 17 11:19:16 2021
2, 25.3, 539, 95.0, 94.0, 94.2, 245, 241, 243, 100.0, 42, 13, 0, KING-HD, cx23885_LG, 1.25, 1610911170, Sun Jan 17 11:19:30 2021
If an adapter is specified and is in use, tuning will fail. If a chip is specified, any adapter that has that chip associated with it will work, but again, tuning will fail if all adapters with that chip are in use.

The next screenshot shows my whole desktop with four instances of strength running, monitoring four channels, one with no lock (click the image to get the full resolution version):

The next image illustrates the watch window displaying the active channel. Notice the title bar of the video (mplayer) window. The command to watch the channel is defined in the settings, available from the File menu. The command I use is mplayer -nosound -vf yadif=1 -cache 8192 -title %d_%c_%n %d. The -title part sets the taskbar text of mplayer's window and the %d, %c and %n translate to device (from /dev directory), chip (see above), and name of the tuned channel. The final %d tells mplayer to play the video from /dev/dvb/adapter0/frontend0 (see "Opening adapter" text in the info text widget). Putting this info in the title bar lets me see which video window goes with which adapter/chip/channel when I am monitoring multiple channels.

Logging Statistics

strength has two logging modes:

I use cron jobs to invoke strength as follows:
14 * * * * DISPLAY=:0 kstart --desktop 2 --skiptaskbar -skippager --windowclass strength strength -c cx23885_LG -s local_channels.conf
This invokes the app with -c to specify the cx23885_LG "chip", -s to start the scan, and local_channels.conf as a channels config file of channels to scan. Because I don't define a Log Filename in the program settings, the data are logged in a file named local_channels.dat. The time is chosen to assure mythbackend will not try to use a tuner that's in use logging signal strength. The kstart stuff puts the app on a different desktop than I normally use so it doesn't pop up in my face once/hour. kstart is a KDE command so other desktops would need something different.

The following fields are logged, separated by commas (CSV format):
Chan_List#,
channel,
Mhz,
max_signal,
min_signal,
mean_signal,
max_snr,
min_snr,
mean_snr,
lock_percent,
num_readings,
seconds_monitored,
adapter,
name,
chip_name,
program_version,
timestamp,
time_date

The max, min and mean are not applicable in single-channel, non-scan mode, so zeros are logged for max and min and the mean is actually the single reading.

Analysing The Logged Data is a whole other topic.

Salutation

That's it. I hope others get some use out of it.