Generate Selective Calling Tones     
After a multi day (week?) saga of trying to get op25 to run on a Raspberry Pi, I decided to give it a try on a linux virtual machine, and had much better results. For the radio hardware I used one of the ubiquitous RTL SDR Dongles.
https://www.amazon.com/gp/product/B0129EBDS2/ref=ox_sc_act_title_1?tag=blackcatsyste-20
I used this guide as a reference / starting point: https://www.hagensieker.com/wordpress/2018/07/17/op25-for-dummies/
Here’s what I did to get things running:
I’m using VirtualBox for the VM setup. I did it on macOS, it should work the same way under Windows.
Create a new linux VM. I gave it 8G of RAM (perhaps overkill) and a 30G volume.
Download the Ububtu installation ISO: https://www.ubuntu.com/download/desktop
Go to Settings -> Storage for the new VM, select the ISO as the optical disc image.
Boot the VM, and install. I won’t go into the installation details, in general I found the defaults worked fine.
I installed the Guest Additions so I could cut and paste between the OS and VM.
Next I installed gqrx so I could check out that the RTL Dongle was working. The stock Ububtu I installed did not come with it:
sudo apt install gqrx-sdr
I plugged in the RTL Dongle, went to Devices -> USB in the VM menu, and assigned the dongle to the VM for use. (Don’t forget this step!)
I ran gqrx, and verified the dongle was working.
gqrx
Next, before installing op25, I had to install git:
sudo apt install git
Then grab op25:
git clone https://github.com/boatbod/op25.git
Switch to the op25 directory that was just created:
cd op25
And install it:
./install.sh
Then install gnuplot so you can see the spectrum and constellation plots:
sudo apt-get install gnuplot-x11
Go to the apps directory for op25:
cd op25/gr-op25_repeater/apps
Next you need to go to https://www.radioreference.com/ and locate the details on the trunking system for your area. Several control frequencies may be listed for your system, you need to find the currently active one. In my case, I checked them all until I found one frequency that was continuously transmitting, 852.9375 MHz.
Now, the next part was perhaps the most difficult, you need to determine the correct ppm error for your RTL dongle. All dongles seem to be off, some more than others. Mine turned out to be off by a LOT. The other tutorials I read gave examples with ppm errors of around 2 or 3. I spent a lot of time trying small values like that, and even up to 20 or 30, without success.
I brought up the spectrum plot in op25 (hit the 1 key) and looked at the spikes, representing transmissions, and checked them against my R-7000 receiver. It was confusing at first, trying to match things up. I eventually realized my dongle was off by a huge factor – about 150 kHz at 853 MHz. I ended up using a ppm value of 173, and that seems to be working. Your value will likely be different, but carefully use the spectrum plot to determine what it is, or at least get close. Then you can iterate up and down by 1 ppm. Another recommendation I read, and used, was to set the offset (used to avoid the 0 Hz spike) to zero for initial testing.
Here’s the command to run op25 with a control frequency of 852.9375 MHz, ppm of 172, and an offset of 0 Hz:
./rx.py –args ‘rtl’ -N ‘LNA:47’ -S 2400000 -f 852.9375e6 -o 0 -q 172
I found I still need to use the , and . keys to shift the received frequency offset around until the program started to decode data correctly (the tsbks value will start incrementing). Again I used the spectrum plot to
help center the control frequency.
When properly tuned, the constellation plot looks like this, hit the 2 key to bring it up:
Once that worked, the next step was to find the NAC value, which is displayed in the op25 program, in my case it was 0x661.
In the apps directory, open the trunk.tsv file in the LibreOffice editor built into Ubuntu, it opens as a spreadsheet. I edited it as follows, entering in a system name, setting the control channel and NAC values. I left the modulation alone (CQPSK) and entered a new tags file name, we’ll create that file next.
I then duplicated the tompkins.tsv file, renamed the duplicate carroll.csv to match what I entered in trunk.tsv, and then opened it in LibreOffice.
It’s a bit tedious, but you have to enter in each talkgroup tag number and name. I just went down the list of talkgroups in radio reference, and it took a few minutes. Part of the list:
Once that was done, I ran op25 again. You can append 2> followed by a filename, to route error messages to a file, so they do not clutter the screen:
./rx.py --args 'rtl' -N 'LNA:47' -S 2400000 -o 25000 -q 181 -T trunk.tsv -V -2 -U 2> stderr.2
I am using an offset of 25 kHz (25000 Hz), and notice I now had to change the ppm to -181, the RTL dongle drifted that much in a few hours!
Update, I also got it working with the AirSpy, which turned out to be very easy. I just had to install the AirSpy support with:
sudo apt install airspy
Running it is as easy as:
./rx.py --args "airspy" -q 3 -N 'IF:12,MIX:12,LNA:12' -S 2500000 -V -2 -U -T trunk.tsv
As you can see, the AirSpy is much more accurate, the ppm value is only 3.
I still need to optimize the gain settings, but this is working nicely. Much better reception than the RTL dongle, as you can imagine. Hmm… unfortunately, op25 is freezing after a while with the AirSpy. Need to investigate this…
Another update:
I decided to install Ububtu on an older i3 laptop. I resized the Windows 10 drive, and freed up 200GB (perhaps excessive, but the drive is 750GB, and I don’t really use the laptop much anymore for Windows) for the linux partition.
I followed the above steps and got gqrx running first, then op25. I have not tried with the AirSpy yet, but even with the RTL dongle, things are improved, the audio quality and overall reception are noticeably better.