Installing op25 from source on a Raspberry Pi
op25 is basically an SDR based radio scanner that can decode and manage trunked radio
communication. For more information, see
http://osmocom.org/projects/op25/wiki.
This procedure will install the boatbod fork. It must be installed after the
gr-osmosdr step on Part 1 of these procedures.
APCO Project 25 is the digital communications standard used by many police
and emergency services throughout the world. Most notably the US, Canada and
Australia deploy systems based on P25. Compared to existing analog systems, P25
offers improved spectrum use, coverage and flexibility. Provision is made to
ensure the confidentiality of traffic, to allow the use of trunking and the
provision of data in addition to voice services.
Some services are encrypted. This software does not provide decryption.
op25 can also be set up to stream online. Online streaming is not covered
here.
Please note that the default branch will install a version for GNU radio 3.10. Click here for installation on a GNU radio 3.8 system.
Install:
- Prerequisites
- For GNU Radio 3.9 and above
sudo apt-get install libitpp8v5 libitpp-dev libpcap0.8-dev libbladerf2 libfreesrp0 libhidapi-libusb0 libgnuradio-iqbalance3.9.0
sudo apt-get install gnuplot-x11
- Installation
cd ~/
git clone https://github.com/boatbod/op25
cd op25
mkdir build
cd build
cmake ../
make -j 4
sudo make install
sudo ldconfig
- Documentation
If you need help with your installation, you can read the help files in your install directory. Here are a few suggestions.
- Configuring op25 for a trunked public service scanner
- op25 runs in a Terminal window and is started with a command line string.
- This section is taken from Tutorial on Setting up OP25 for P25 Phase
2 Digital Voice Decoding.
I have worked out some of the details for
the SDRplay RSP1A.
The tutorial is detailed below:
OP25 For Dummies – Or how to build a police scanner for $30 (Part 1)
OP25 Raspberry Pi Streaming Part 2
OP25 on a Raspberry Pi (part 3)
- To get started, we need to find the control frequency and NAC for the service in your area.
- Go to https://www.radioreference.com/apps/db/
- Scroll to the section entitled Search Trunked Radio Information.
- You should be able to find your police, Fire, Utilities, etc. by
the state unless you know the other details. I chose the State of
Michigan.
- Click on a service in your area.
- In the list provided, find a service that you wish to monitor.
Look for the control channel frequency in
red with a
c appended to it. You can tune
to it with a program like GQRX. It will be a constant signal and
will sound like noise. Close your SDR program.
- Open a Terminal window.
cd ~/op25/op25/gr-op25_repeater/apps
- Paste a command similar to this into the Terminal.
Change -f frequency to your control channel.
-q is the frequency correction for your SDR.
# For SDRplay:
./rx.py --args 'driver=sdrplay,soapy=0' -N 'IFGR:28,RFGR:2' -S 2500000 -x 1 -f 855.2875e6 -o 1e3 -q -1
# For HackRF
./rx.py --args 'hackrf' -g 65 -N 'RF:14,IF:32,BB:26' -S 1000000 -x 1 -f 855.2875e6 -o 50e3 -q -1
- The terminal will display the control channel frequency and the tuning offset in
parenthesis like this:
Frequency 855.287500(0)
If you get a lot of errors similar to
p25_framer::rx_sym() tuning error +1200,
you may need to make a frequency correction.
Pressing "," lowers the fine tuning frequency by 100 Hz. Pressing
"." increases the fine tuning frequency by 100 Hz. Slowly change
fine tuning (in parenthesis) until the errors stop and decoding
begins.
Take the frequency from the parenthesis and add it to the
end of the command line with a "-d" like this:
-d
600. Press "q" to stop op25. Enter the command into the
terminal again with the correction like this:
# For SDRplay:
./rx.py --args 'driver=sdrplay,soapy=0' -N 'IFGR:28,RFGR:2' -S 2500000 -x 1 -f 855.2875e6 -o 1e3 -q -1 -d 600
# For HackRF:
./rx.py --args 'hackrf' -g 65 -N 'RF:14,IF:32,BB:26' -S 1000000 -x 1 -f 855.2875e6 -o 50e3 -q -1 -d 600
- The display should be free of errors. The top line should look
similar to this:
NAC 0x799 WACN 0x92493 SYSID 0x796 855.287500/810.287500 tsbks 10
- Take a note of the NAC number, which in this case is 0x799.
- Make the configuration files
- While still in the apps directory, open the tab delimited
trunk.tsv. If you have a spreadsheet program, use that. You may use
a text editor of you are careful. In a spreadsheet, it should look
similar to this:
Sysname |
Control Channel List |
Offset |
NAC |
Modulation |
TGID Tags File |
Whitelist |
Blacklist |
Center Frequency |
Washtenaw County |
855.2875,852.8625,853.250,855.0875 |
0 |
0x799 |
cqpsk |
washtenaw.tsv |
|
|
|
Enter the NAC that you found.
Using radioreference.com,
enter the data in the fields the best that you can. TGID Tags File
will be your database of local talkgroups.
Enter the Control Channel List
in a comma separated list as shown above with no whitespace. Place
the primary control channel first and the alternates after that.
These will be listed in
https://www.radioreference.com/apps/db/
Save the file in the
~/op25/op25/gr-op25_repeater/apps directory, keeping
the tab delimited format.
- Create a new tab delimited spreadsheet for the TGID Tags File. Using radioreference.com, enter
data from the DEC (Talkgroup ID) column in column 1, Description
in column 2, and
optionally, a priority in column 3. LOWER numbers have HIGHER
priority. Default is 3 for anything with no tag specified.
2191 |
Washtenaw County Ann Arbor Dispatch [Alternate] |
1 |
2237 |
Huron Valley Ambulance: Dispatch |
3 |
If you click "List All in one table", you can copy and paste the
entire table into the spreadsheet. If you paste as Unicode Text,
programs like Excel will be less likely to "interpret" the data.
Save this file, as you may need it later.
Delete all columns
except the DEC (Talkgroup ID) column in column 1, with Description
in column 2,
sort if you prefer. Add priorities if you want them. Save in the
~/op25/op25/gr-op25_repeater/apps directory as the
file name that you entered into trunk.tsv column "TGID Tags File", keeping the tab delimited format.
If you have a radioreference.com Premium account, you can download
the talkgroups in a CSV file, open in a spreadsheet program, delete
all extra columns except the Decimal (Talkgroup ID) column in column 1,
with Description in column 2 and save as TSV.
- The optional blacklist file
You may want to blacklist the
secure (encrypted) talkgroups as you will not be able to hear their
audio with this program.
The blacklist excludes numerically
listed TGIDs but allows everything else to play. Ranges of
whitelists and blacklists are specified beginning with the starting tgid followed by a tab character and the ending tgid.
- Open your original talkgroup file, that has all of the
original columns, with a spreadsheet program.
- Sort the file by the Mode (4th) column.
- Delete all of the rows that do not have "DE" in the Mode (4th) column.
- Delete all columns
except the first column, DEC or Decimal (Talkgroup ID). If you make
ranges, the spreadsheet will save the file with a tab to start
the second column whether there is a number there or not. You must delete these extra tabs, as those
talkgroups will not be blacklisted.
- Save the file as tab delimited, i.e. blacklist.tsv
- Add your blacklist.tsv file to your trunk file (trunk.tsv) in the Blacklist
column.
- The whitelist file works similarly, except that it limits
monitored TGIDs to just those listed numerically in the file.
- Run the program
- Open a Terminal window,
paste and execute these commands, customized for your setup.
# For SDRplay:
cd ~/op25/op25/gr-op25_repeater/apps
./rx.py --args 'driver=sdrplay,soapy=0' -N 'IFGR:28,RFGR:1' -S 2500000 -x 1 -f 855.2875e6 -o 5e3 -q -1 -d -200 -T michigantrunk.tsv -V -2 -O pulse -U 2> stderr-stream0.2
# For HackRF:
cd ~/op25/op25/gr-op25_repeater/apps
./rx.py --args 'hackrf' -g 65 -N 'RF:14,IF:32,BB:26' -S 1000000 -x 1 -f 855.2875e6 -o 50e3 -q -1 -d 1200 -T michigantrunk.tsv -V -2 -U 2> stderr-stream0.2
Add -O pulse to
the command line if your audio is garbled. You may have to
experiment to get all of the SDR apps to work.
I specified -x 1 to
set the audio gain. Default = 1.0. Specifying
-x 0.8 may be better as some signals are extremely loud.
- The command line syntax can be displayed by typing
./rx.py -h.
- This should get you up and running. You can read the tutorials
mentioned above for more details. You probably will have to adjust
FINE_TUNE and the gains for your SDR, antenna, etc.
- Install liquidsoap (optional)
If you find that there is a wide range in audio levels between the
various signals, I recommend using liquidsoap
There is a sample
liquidsoap configuration file in the ~/op25/op25/gr-op25_repeater/apps
directory named op25.liq. You probably need to change some of the
parameters.
The *.liq files need to have execute permission.
- As of 5/7/2025, there is an incompatibility with the Debian liquidsoap package and the deb-multimedia.org packages.
To try the supplied package,
sudo apt-get install ffmpeg
sudo apt-get install liquidsoap
- If the Debian package gives a Segmentation fault, install the latest
package from github.
Download the latest .deb package from
https://github.com/savonet/liquidsoap/releases
to ~/Downloads
# It you installed the supplied package, uninstall it:
sudo apt-get remove liquidsoap
sudo apt-get install ffmpeg libsdl2-image-2.0-0 libsdl2-ttf-2.0-0 bubblewrap
cd ~/Downloads
# Install the package you downloaded similar to this:
sudo dpkg -i liquidsoap_2.3.2-debian-bookworm-2_arm64.deb
# Test it:
liquidsoap --version
# You should see: Liquidsoap 2.3.2
- If you get the error: no argument labeled "rms_window"!,
edit your configuration file i.e. op25.liq and change
"rms_window" to "window". The line number
that needs to be changed will be in the error
message.
- Instead of starting rx.py as specified above, open 3 Terminal windows:
- Terminal #1:
# For SDRplay:
cd ~/op25/op25/gr-op25_repeater/apps
./rx.py --args 'driver=sdrplay,soapy=0' -N 'IFGR:28,RFGR:1' -S 2000000 -x 1 -f 855.2875e6 -o 5e3 -q -1 -d -200 -T michigantrunk.tsv -V -2 -w 2> stderr-stream0.2
# For HackRF:
cd ~/op25/op25/gr-op25_repeater/apps
./rx.py --args 'hackrf' -g 65 -N 'RF:14,IF:32,BB:26' -S 1000000 -x 1 -f 855.2875e6 -o 50e3 -q -1 -d 1200 -T michigantrunk.tsv -V -2 -w 2> stderr-stream0.2
- Terminal #2:
cd ~/op25/op25/gr-op25_repeater/apps
./op25.liq
- Terminal #3: (optional log window)
cd ~/op25/op25/gr-op25_repeater/apps
tail -f stderr-stream0.2
- HTTP Console
The OP25 GUI dashboard in a web browser. Basically, we add -l 'http:0.0.0.0:8080' to the command and remove the error redirect, so
errors will appear in the terminal.
- Open 2 Terminal windows:
- Terminal #1:
# For SDRplay:
cd ~/op25/op25/gr-op25_repeater/apps
./rx.py --args 'driver=sdrplay,soapy=0' -N 'IFGR:28,RFGR:1' -S 2000000 -x 1 -f 855.2875e6 -o 5e3 -q -1 -d -200 -T michigantrunk.tsv -V -2 -v 1 -w -l 'http:0.0.0.0:8080'
# For HackRF:
cd ~/op25/op25/gr-op25_repeater/apps
./rx.py --args 'hackrf' -g 65 -N 'RF:14,IF:32,BB:26' -S 1000000 -x 1 -f 855.2875e6 -o 50e3 -q -1 -d 1200 -T michigantrunk.tsv -V -2 -v 1 -w -l 'http:0.0.0.0:8080'
- Terminal #2:
cd ~/op25/op25/gr-op25_repeater/apps
./op25.liq
- Open a web browser and enter the URL:
http://127.0.0.1:8080/. You can
also use the IP address of your Raspberry Pi.
To stream the audio
over the Internet, you probably will have to use Icecast.
- Configuring op25 to receive two channel DMR
- You will need a configuration file. An example that uses op25
built-in audio for SDRplay is here.
and for HackRF is here. Right-click on the link and save as... save it in ~/op25/op25/gr-op25_repeater/apps
The IFGR gain setting has no effect unless you add the line "gain_mode":
false, in the "devices" section. This seems to be a hardware AGC
setting, so that won't work unless "gain_mode" is omitted or
"gain_mode": true, is present. Enter your frequency in the
devices section of the config file.
- The receive frequency, audio_gain, plot etc. are in the file. If you use
the fft plot, it may take enough CPU time to cause buffer overruns as
evidenced by a series of "O"s in the message window.
If you
have stereo audio, the two DMR channels will be played in separate speakers,
so you may only hear sound from one speaker.
- Open Terminal windows:
- Terminal #1:
Be sure to specify the .json file for your
SDR
# For SDRplay:
cd ~/op25/op25/gr-op25_repeater/apps
./multi_rx.py -c dmr_cfg.json -v 10 2> stderr-stream-dmr
# For HackRF:
cd ~/op25/op25/gr-op25_repeater/apps
./multi_rx.py -c dmr_cfg_hackrf.json -v 10 2> stderr-stream-dmr
- Terminal #2:
This filter will display only messages that
contain the talkgroup and radio addresses.
cd ~/op25/op25/gr-op25_repeater/apps
tail -f stderr-stream-dmr | grep DSTADDR
- DSTADDR() is the talkgroup in hexadecimal, SRCADDR() is the address of the radio
that is transmitting in hexadecimal. You need to convert these numbers to
decimal before you look them up.
- If you find that there is a wide range in audio levels between the
various signals, I recommend using liquidsoap
Download the DMR
external audio configuration file for RSP1A here, HackRF here. Right-click on the link and save as... save it in
~/op25/op25/gr-op25_repeater/apps
The RSP1A IFGR gain setting has no effect
unless you add the line "gain_mode": false, in the "devices" section. This
seems to be a hardware AGC setting, so that won't work unless "gain_mode" is
omitted or "gain_mode": true, is present.
- Copy your
liquidsoap configuration file in the ~/op25/op25/gr-op25_repeater/apps
directory named op25.liq to op25-2_channel.liq.
In
op25-2_channel.liq, find "./audio.py -x 1.0 -s" in the file and change it to
"./audio.py -2 -x 1.0 -s" so that you can receive 2 channels. (The
-x 1.0 may have changed) Make it executable.
- Instead of starting multi_rx.py as specified above, open 3 Terminal windows:
- Terminal #1:
# For SDRplay:
cd ~/op25/op25/gr-op25_repeater/apps
./multi_rx.py -c dmr_cfg_ext_audio.json -v 10 2> stderr-stream-dmr
# For HackRF:
cd ~/op25/op25/gr-op25_repeater/apps
./multi_rx.py -c dmr_cfg_hackrf_ext_audio.json -v 10 2> stderr-stream-dmr
- Terminal #2:
cd ~/op25/op25/gr-op25_repeater/apps
./op25-2_channel.liq
- Terminal #3:
cd ~/op25/op25/gr-op25_repeater/apps
tail -f stderr-stream-dmr | grep DSTADDR
- HTTP Console does not seem to be implemented for DMR.
- Yahoo System Fusion (YSF)
Yahoo System Fusion is similar to DMR
except that there is only one channel and no talkgroups.
- Motorola Type II Smartnet
- Find the Smartnet service that you want to monitor here: https://www.radioreference.com/apps/db/
Normally, this function requires two SDRs, but SDR hardware with a high
sample rate can be shared between channels, but only if tuning is
disabled (tunable=false)
You will have to configure the sample rate
to be high enough to cover the entire frequency range of the service you
will be monitoring. High sample rates also bring high CPU usage and may
result in buffer overruns from GNU Radio as evidenced by a series of "O"
characters in the message terminal. Press a number key that would bring
up a graph twice such as 3
to restart monitoring.
If there is no sound, even when a talkgroup is
active, check that "nbfm_squelch_threshold" is low enough.
- Browse to directory ~/op25/op25/gr-op25_repeater/apps
- Edit a config file. Here is an example using one RSP1A:
smartnet_test.json or for HackRF:
smartnet_hackrf.json. There is also an example in your install directory:
smartnet_example.json
Here are some of the important items that need to be configured.
- Ensure that the "device" entries in the "channels"
section match
the device "name" in the "devices" section.
- "args", "gains", "gain_mode"
- "frequency", use a frequency in the center of the range used by
the service you want to monitor.
- "name" to match "device" entries in the "channels" section
- "offset": 50e3 This is to avoid the DC offset in most SDRs.
Without it, HackRF has a big spike right on the receive frequency.
- "tunable": false if you only have one device
- "control_channel_list" in the "trunking" section, comma
separated list of the control channels found on radioreference.com
- Run the program
- Open 2 Terminal windows:
- Terminal #1:
(be sure to specify the .json file for your SDR)
# For SDRplay:
cd ~/op25/op25/gr-op25_repeater/apps
./multi_rx.py -v 4 -c smartnet_test.json 2> stderr.2
# For HackRF:
cd ~/op25/op25/gr-op25_repeater/apps
./multi_rx.py -v 4 -c smartnet_hackrf.json 2> stderr.2
- Terminal #2:
cd ~/op25/op25/gr-op25_repeater/apps
tail -f stderr.2
- Use the right and left arrow keys to cycle through the
pages. The second page will show the active talkgroup with the
tags from your "tgid_tags_file" file specified in your
configuration file.
- HTTP Console
The Smartnet GUI dashboard in a web browser. Basically, in the .json
setting file "terminal" section we uncomment (remove the "#") from
"terminal_type": "http:127.0.0.1:8080" and put a "#" at the start of
"#terminal_type": "curses". "terminal_type". "http:0.0.0.0:8080" will
allow access from any IP address on your network.
In the "audio" section, remove the
contents of "instance_name": "", leaving just the quotes as shown.
This will disable the internal audio player and allow you to use an
external audio player such as liquidsoap.
An example .json file for
SDRplay is here.
and for HackRF is here. Right-click on the link and save as... save it in ~/op25/op25/gr-op25_repeater/apps.
Removing the error redirect will cause the errors to appear in the terminal.
- Open 2 Terminal windows:
- Terminal #1:
(be sure to specify the .json file for your SDR)
# For SDRplay:
cd ~/op25/op25/gr-op25_repeater/apps
./multi_rx.py -v 4 -c smartnet_test_http.json
# For HackRF:
cd ~/op25/op25/gr-op25_repeater/apps
./multi_rx.py -v 4 -c smartnet_hackrf_http.json
- Terminal #2:
cd ~/op25/op25/gr-op25_repeater/apps
./op25.liq
- Open a web browser and enter the URL:
http://127.0.0.1:8080/. You can
also use the IP address of your Raspberry Pi if you used
"http:0.0.0.0:8080" in your .json file.
To stream the audio
over the Internet, you probably will have to use Icecast.
Back to the index