OP25 For Dummies – Or how to build a police scanner for $30 (Part 1)

OP25 is a program that decodes P25 Phase 1 and Phase 2 digital radio.  Some municipal areas are upgrading to P25 Phase 2 so almost gone are the days that you can track them with a police scanner since P25 is a Trunked Radio system and not just a lone frequency to monitor.   The only things that do Phase 2 are hardware scanners and hardware radios and OP25 for software radios.  Bear in mind Phase 2 could be encrypted and nothing you can do will decode it.

OP25 is HARD.  I’m a geek and I messed with it on and off for a year or more and it whipped me more than once.  Now that I have it working I find that it is REMARKABLY easy and I’m mad at all the geeks out there who never made a simple tutorial.  There are tutorials out there, some good but everybody leaves out the good stuff or the stuff they took for granted.

I’m kind of working on the assumption that you have Linux installed and have your SDR device working.  In a pinch I guess the first thing you could do is to install gqrx which would pull in all the necessary RTL stuff you need.  Follow the directions here if you need to.  Yeah that’s a weird way of doing it but it’ll work and probably the easiest thing to do for a newbie.

Installing OP25 is a SNAP.  Download from the repository using this command. I’m doing this on Ubuntu 18.04

git clone https://github.com/boatbod/op25.git

It will make a folder called op25

cd op25


It will instruct you to install GNUPLOT following the build and install process

sudo apt-get install gnuplot-x11

Wait a bit for it to install.  It should take care of everything.

Now it is installed but there are three obstacles to overcome.

  • How to launch the program with what command to use
  • How to set up the file trunk.tsv
  • How to set up the file yourcity.tsv

That’s basically it.  Now my assumption here is that you are using a generic RTL-SDR device.  I’m using a V3.

These will set you back about $30 or so.  But you only need one of these to track a trunked radio system.

So plug in your RTL-SDR device and let’s get ready to do this thing.

I’m going to demonstrate using my home town of New Bern NC.  Lets find the trunked system to follow.



Go to this page  to list the frequencies.

This page will not always be spot on.  The actual control channel at the moment (they change it sometimes) is 857.2625.

To find the control channel if you don’t know which one it is just open a program like GQRX and look and listen for the control channel.  It will sound like digital noise.  And the signal will be a constant spike.  As you can see I found my Control Channel at 857.2625 as stated above.


Now go back to your system and get in the correct directory. Check your path for accuracy.

cd /home/john/op25/op25/gr-op25_repeater/apps


./rx.py --args 'rtl' -N 'LNA:47' -S 2400000 -f 857.2625e6 -o 25000 -q -2

If you get a bunch of errors remove the last part of the command (-q -2)  It works as above on my V3 SDR but not on my NESDR Smart. You may also have to adjust the -2 number depending on your individual SDR.  Have fun with that.  To further illustrate my SDR v3 works at -2, my NESDR Smart works with the -q -2 removed (0), and my Adalm-Pluto works at -q 5 (positive 5).  You just have to play around until you get your signal centered on the plot.

As per the pic below ………If where it says 857.262500/812.262500 is all zeros then you need to keep adjusting the -q number.  On that screen you can start GNUPLOT by pressing the number 1 key.  Keep messing with the q number until the signal is centered on the plot.

Something like the box above should pop up.  There won’t be any sound but take note of the NAC.  In my case it is 0xfc  We’re going to need that.  Copy your NAC for your frequency.  YOU WILL ONLY GET THE CORRECT NAC IF YOU ARE TUNED TO THE CONTROL CHANNEL YOU WANT TO MONITOR.

Now you should still be in the apps directory.  Double click on the file named trunk.tsv and open it with LibreOffice.  Make sure the file looks like this and has these settings. (I’ve already modified my file, so ignore the difference.)

Now take note of the way I changed the file.  I made the SysName = NewBern, then put my control channel frequency in, put the NAC I copied earlier in, and then told it the tag file was named newbern.tsv  Under modulation there are only two types, CQPSK or C4FM.  If one doesn’t work, try the other.  Save this and exit.  Save it as the “Use Text CSV Format”

Now open the file tompkins.tsv  It looks like this.  Make sure the settings are the same as depicted above.

Delete all the filled in fields in here and go back to the radio reference.com page where all the New Bern frequencies were.


Now go to the tompkins.tsv file that you cleared and type in column A the numbers in the DEC column (i.e. 100, 101, 102, etc.)  Then in column B insert in the tag (i.e. Law Dispatch, Public Works, etc.).

Sorry mine are not in order.  Sue me.

Do a “Save As” and name the file newbern.tsv (remember that field in the other file you named newbern.tsv).  Make sure this file is also saved in the same format as above and also in the apps directory where the tompkins.tsv file was.

Okay open your terminal.  cd to the apps directory  /op25/op25/gr-op25_repeater/apps and do this command:

./rx.py --args 'rtl' -N 'LNA:47' -S 2400000 -f 857.2625e6 -o 25000 -q -2 -T trunk.tsv -V -2 -U 2> stderr.2

Again you may have to remove the -q -2 or adjust it depending on your SDR

When OP25 launches hit the number “1” on your keyboard to open GNUPLOT

And now when there is a transmission on the Control Channel, OP25 will track it to the correct frequency and even display the talk group that is currently active.

Now lets make a little script file so we aren’t forever typing long commands.


cd op25

sudo nano op25.sh

Paste in the following data in the file (MAKE SURE YOUR PATH IS CORRECT AND DON’T FORGET ABOUT THE -q -2 part if you have problems):

#! /bin/sh

cd /home/john/op25/op25/gr-op25_repeater/apps

./rx.py –args ‘rtl’ -N ‘LNA:47’ -S 2400000 -f 857.2625e6 -o 25000 -q -2 -T trunk.tsv -V -2 -U 2> stderr.2

Hit CTL + the X key then Y to save the file.  Now make it executable.

sudo chmod +x op25.sh

Now to launch the file simply be in the directory that script file is in and type:


It will cd to to the right directory and run the command to start OP25.

That’s it.  I hope I made this easier for someone.

Here’s OP25 in action:

And lastly here is a video of me using OP25 to track 2 Control Channels simultaneously.  You’ll hear the transmissions echo in the video.  That is my screencast software recording both from the microphone and speakers and not the way OP25 sounds.

On a final note just for fun I installed OP25 on a Raspberry Pi 3 B+.  It works like a champ.  I installed GQRX first which pulled in most everything OP25 needs and plus I use GQRX a lot anyway.  OP25 takes a while to build on a Pi but it does build.  If you look at the pic below the CPU usage is 40% however to get this picture I was running a VNC server as well so some of that usage is almost certainly the VNC session.

This is a living document (for a while).  If you find something I should add feel free to go to my contact page and email me.

33 thoughts on “OP25 For Dummies – Or how to build a police scanner for $30 (Part 1)

  1. Pingback: Tutorial on Setting up OP25 for P25 Phase 2 Digital Voice Decoding - rtl-sdr.com

  2. Gene

    Thank you. Runs great on a Tinkerboard. Monitoring Louisville Metrosafe. Used the standard RTL install procedures then I used sudo apt-get install gqrx-sdr and then sudo apt-get install libvolk1-bin and ran volk_profile. Then I followed all of your steps. And just for info the -n option in OP25 somewhere near the beginning of the will block the encrypted squeals that can cause loved ones to vote you off the island.
    I’m not sure why but this system has a better sound than others that I use and like.
    Thanks again, have finally found a use for this SBC that I had written off months ago. As an additional note my V3 is running off a powered USB adapter, not the Tinkerboard usb power.

    1. Tyler Ryno

      Ok, So far this is working out amazingly. but could i use this for Conventinal Scanning if my First Responders are using Analog and P25 convintional

  3. Pingback: OP25 on a Raspberry Pi (part 3) | John’s Tech Blog

  4. Brian

    Thanks for great tutorials. Not only got op25 phase 2 running on my laptop under Ubuntu, but also got it working on my Raspberry Pi 3 perfectly!

    I have a question, I am using the -n switch to silence the encrypted stuff (works fine), but is there a way to block them completely? I find sometimes the encrypted “silenced” talkgroups, over ride the non-encrypted ones and I miss some of the information. I listen to the fire departments in my area, but the police who are encrypted are on the same control channel and I will sometimes miss the dispatch of a fire call because a “silenced” talkgroup is active. Is there a way around this by chance?

    Thanks again for taking the time to put this information together in a easy to understand format!!

    1. John Hagensieker Post author

      In your .tsv file you can set Priority but you’d have to know which talk groups the encrypted stuff is generally on. Set a low priority for it.

      1. Brian

        ah, OK. I’ll give that a go then. I am getting a pretty good idea of which talk groups are the busiest and those will be my priority first.

        Thanks for the reply!

    2. Matt R.

      The “blacklist” field in trunk.tsv tells op25 to skip a talkgroup completely and keep listening for other talkgroups; I have been putting the encrypted talkgroups on the local system in that field and it seems to work OK. See my reply further below for the details.

      (Even with a talkgroup in the blacklist, if somebody transmits on that talkgroup, you will still see the talkgroup near the top of the screen, where op25 lists the last 5 frequencies it heard things on – you just won’t hear the audio for that talkgroup.)

      I hope this helps!

  5. PiScanner

    I see all the comments about getting this going on RasPi 3 B+, but not the details on it. So could you please post the RasPi 3 B+ portion of the tutorial. A couple SDR dongles and a PI 3+ would still be cheaper than a $600 P25-PII scanner, or a $3K P25 PII radio and hoping you can keep it unaffiliated and unstunned.

  6. David Dobson

    First time link user (ubuntu18-04) how and where can I check my build to ensure all is their and what not and something to compare to

  7. Gared

    I am linux stupid, but this tutorial helped me out a lot thank you. I am having trouble with setting up the whitelist I can’t seem to find it ( if you have it and I skipped it i’m sorry my brain is still fried from the commands )

    Do you have to setup a new line with the nac and the whitelist every time? Or just in the whitelist box you can have many many entries?

  8. Ashleigh

    Thanks for the tutorial. It saved me days of work. I had this working great for a few weeks but then i got a software update thru ubuntu yesterday and now its broken. I run op25.sh and it stops at setting gain LNA to 47

    Any ideas how to fix it?

    1. Ken F Simpson

      @ashleigh The issue I kept having is it needed a 0 in the offset column, that and double check to make sure its not saved as trunk.tsv.csv it should be trunk.tsv ,

  9. Matt R.

    Thanks for the write-up! I got an RTL-SDR a few years ago, when P25 decoding was not as far along as it is now. I started playing with it again recently and now I have a scanner – thanks!

    Some notes on how I set it up:

    I found I could copy the text of the tables on Radio-Reference and paste it into LibreOffice. LibreOffice treats the paste like importing a text file, and breaks it up into columns and rows pretty much how you would expect. You can then cut it down to just the talkgroup ID (first column) and whatever you want to use for the description (second column), for the .tsv file that describes the system you want to listen to.

    I used the “Description” field from Radio-Reference as the description in my .tsv file. The “Tag” field there is pretty generic; the “Alpha Tag” is a little better, but still kind of cryptic – especially on a system like the one near me, which has 800+ talkgroups. (On the other hand, “Alpha Tag” probably matches what the “official” system users actually see on the front of their radios.)

    When you are first listening, you might want to have a text file or a piece of paper handy. You will probably hear some encrypted talkgroups; note their talkgroup IDs. Then, add those channels into the “blacklist” field in trunk.tsv – you can put more than one talkgroup in that cell, separating them with commas. If you wanted to ignore talkgroups 1001, 2002, and 3003, that cell would look like this:


    Save trunk.tsv and restart the scanner program and op25 will then skip those talkgroups. (There is an -n option to rx.py to ignore encrypted channels, but if you use that, op25 will still stop on an encrypted talkgroup for as long as someone is transmitting on that talkgroup. Putting the talkgroup in the blacklist makes op25 skip it immediately and keep checking for other transmissions.)


  10. Scott Gayden

    Thank you so much for putting this information out there. I’m almost completely new to Linux and was able to follow along very easily. I was able to successfully get OP-25 running on Ubuntu 18.04 LTS with a RTL-SDR v3 dongle. Thank you again for this excellent writeup.

  11. marklt1

    Is there an way to get OP25 to work with multiple RTL-SDR dongles? The reason I ask that is that I monitor the Ohio MARCS P25 system where the frequencies can span 6 Mhz. I would like to constantly monitor the control channel with a single dongle and let the others take care of bouncing around.
    The way it works today is that it will jump from the control channel to a listening channel to listen to a specific talk group. I generally hear one side of the conversation since the control channel cannot tell me then next channel for the reply in time.
    Another user will reply to a call for that talk group but will appear on a different channel. I will miss that since the control channel isn’t constantly monitored. Three dongles would suffice in this situation.
    I’ve been looking for many months but haven’t had much luck. The only think close would be trunk recorder, which is a path really don’t want to take due to its intense use of resources.

  12. Cam

    John, greetings from the Triangle. Your tutorials – especially this one on OP25 – were a great comfort during the recent storms. I recently bought an ADALM-PLUTO, and I’m finding a strange behavior – I can be zeroed right on the control channel, but the actual communication channels always seem to be too offset for me to recover audio. Have you seen such similar behavior on the Pluto?

    1. John Hagensieker Post author

      I have to set my Pluto at q 5 and then if it gets hot in the room have to set it to q 6. It’s kind of drifty but playing around with it a bit you should find the magic range.

  13. Nick

    Thanks for this tutorial. I can now listen to my county’s Phase II TDMA with a nesdr smart on MATE 1.20.1. I had to lose the “2> stderr.2” from the launch script in order to get it to work for me.

    I was also able to copy and paste the data from Radio Reference like Matt R. above.

    1. John Hagensieker Post author

      Outstanding write up. Thanks for sharing it here. It will only serve to help others get OP25 up and running with a Pi. I recently added a couple other blogs where I was playing around with DSDPlus and came to the conclusion that while DSDPlus is better eye candy, the superior decoder by a longshot is OP25. The fact you can run it on a Raspberry Pi is icing on the cake.

  14. Kirk Wolff

    Hello, I am using ubuntu 18.04 and i have been having trouble getting the line:

    git clone https://github.com/boatbod/op25.git

    to facilitate. I have tried sudo apt-get install, etc, but no good. Previously i was using Ubuntu 16.04 and it ran flawlessly. Any Ideas ??

    Oh, just love your blog. Simple is better and as a Robotics Engineer, I have found many mistakes by backing off original thoughts and Keeping It Simple !!


    1. John Hagensieker Post author

      Did you install git? sudo apt-get install git

      You can also go to that GitHub page and download the zip file and unzip it where you want it.

  15. Fred Albertson

    Hi John, You are a masterful teacher. Thanks for assisting a WIN 10 guy with a functional installation on Ubuntu. With your assistance, I’ve got OP25 working in Virtualbox with the exception of the audio – the next project…

  16. Alexander Bowman

    I’ve got this working on my raspberry pi 3.

    Something cool that might benefit others is, if you’re lazy like me, set an alias for op25.sh

    In Terminal:

    sudo nano .bashrc

    ##OP25 alias

    alias op25=’bash /home/pi/op25/op25.sh’

    Close terminal and open it back up. You can now run your command by typing op25 as soon as the terminal opens, without changing directories.

    1. Alexander Bowman

      CTRL+X, Y, Enter

      after typing:
      alias op25=’bash /home/pi/op25/op25.sh’

      for some reason the CTRL+X, Y, Enter was missed when I tried to post comment.

      1. John Hagensieker Post author

        Next time I launch OP25 on one of my Linux computers I’ll give that a try and then add it to the tutorial. Thanks!


Leave a Reply

Your email address will not be published. Required fields are marked *