#radio #software #notes
**TL;DR: You can [Listen Here](https://openmhz.com/system/coirsdwhu)**
### Overview
These are my notes on setting up trunk-recorder, an open-source software designed to record and manage trunked radio system traffic. Originally created to capture public safety communications, trunk-recorder is highly flexible and supports a range of systems such as P25 and analog trunked networks. By utilizing Software-Defined Radios (SDRs), this tool captures audio, extracts metadata, stores it in an accessible format and uploads it to a [site where you can listen](https://openmhz.com/systems).
### Dependencies
I started with installing this on my Fedora laptop first and then move it to a Pi which I can stash somewhere. I setup my Raspberry Pi’s in a headless manner and I’m going to need to find tuning offsets with GQRX and I’ll have some other hands-on activities with this, so this is the easiest way to start.
I opted to actually build it here instead of the docker instructions because for other reasons, my Docker setup on my laptop is _weird_ and I’m not going to get into that here.
Installing Dependencies:
```shell-session
$ sudo dnf install -y \
ca-certificates \
git \
gnupg2 \
gnuradio \
gnuradio-devel \
gr-osmosdr-devel \
gr-osmosdr \
uhd-devel \
boost-devel \
libcurl-devel \
gmp-devel \
hackrf-devel \
orc-devel \
openssl-devel \
libusb1-devel \
pkgconf-pkg-config \
cmake \
libsndfile-devel \
sox \
fdk-aac \
fdkaac \
spdlog-devel
```
Then
```shell-session
$ mkdir trunk-build
$ git clone https://github.com/robotastic/trunk-recorder.git
$ cd trunk-build
$ cmake ../trunk-recorder
$ make
$ sudo make install
```
That took a while, but it was successful.
Then there's this: https://github.com/robotastic/trunk-recorder/blob/master/docs/CONFIGURE.md
So all my SDR's have the same serial number, so I'll have to renumber them all to be able to address them properly in the config. According to anecdotes from _The Internet_, I should use 8 digit numbers like 00000101, 00000102, 00001090, 00000978, 00000401, 00000118, etc. and not ones that might conflict with the device index. I don't know if these would _conflict_, but there's probably some code out there that's weird that might not respect things so why not, it can't hurt.
I'll need to use `rtl_eeprom` on all 6 of the current SDR's I have. I'll use:
00000101
00000102
00000103
00000104
00000105
00000106
```shell-session
✘ mike@boatanchor ~ rtl_eeprom -d 0 -s 00000101
Found 6 device(s):
0: Generic RTL2832U OEM
1: Generic RTL2832U OEM
2: Generic RTL2832U OEM
3: Generic RTL2832U OEM
4: Generic RTL2832U OEM
5: Generic RTL2832U OEM
Using device 0: Generic RTL2832U OEM
Detached kernel driver
Found Rafael Micro R820T tuner
Current configuration:
__________________________________________
Vendor ID: 0x0bda
Product ID: 0x2838
Manufacturer: Realtek
Product: RTL2838UHIDIR
Serial number: 1
Serial number enabled: yes
IR endpoint enabled: yes
Remote wakeup enabled: no
__________________________________________
New configuration:
__________________________________________
Vendor ID: 0x0bda
Product ID: 0x2838
Manufacturer: Realtek
Product: RTL2838UHIDIR
Serial number: 00000101
Serial number enabled: yes
IR endpoint enabled: yes
Remote wakeup enabled: no
__________________________________________
Write new configuration to device [y/n]? y
Configuration successfully written.
Please replug the device for changes to take effect.
Reattached kernel driver
```
So I'll do that with `-d 1 -s 00000102`, etc and then replug the usb strip.
That worked, but I'm going to spare you the output of all of them, but here's a sample after replugging the powered USB strip:
```shell-session
✘ mike@boatanchor ~ rtl_eeprom -d 5
Found 6 device(s):
0: Generic RTL2832U OEM
1: Generic RTL2832U OEM
2: Generic RTL2832U OEM
3: Generic RTL2832U OEM
4: Generic RTL2832U OEM
5: Generic RTL2832U OEM
Using device 5: Generic RTL2832U OEM
Detached kernel driver
Found Rafael Micro R820T tuner
Current configuration:
__________________________________________
Vendor ID: 0x0bda
Product ID: 0x2838
Manufacturer: Realtek
Product: RTL2838UHIDIR
Serial number: 00000106
Serial number enabled: yes
IR endpoint enabled: yes
Remote wakeup enabled: no
__________________________________________
Reattached kernel driver
```
I'm going to try this on COIRS (Central Ohio Interoperable Radio System) first as I should be able to pick it up pretty easily even in my basement. It has a range of 851.250-865.6125 so I'll need 3 RTL-SDR's to get it working. I'll move on to Ohio MARCS-IP after I'm sure everything is working correctly. The frequencies are currently:
851.250 851.4875 851.7625 853.3625 854.1875 855.4875c 855.7125c
855.9625c 856.6125c
Where the (c) indicates a control channel.
According to the configuration page, I will need to solve for the tuner error of each SDR. Good thing I'm taking notes!
I loaded up GQRX to do this and it didn't have any of the new serial numbers. Wondering if this is cached somewhere? I've done all the ChatGPT'ing and Googling and can't find much on this other than editing the serial number in the config file, which is what I'll have to do.
One of the control channels above should be pretty loud and will let me figure out the tuner error. I'll take the frequency the SDR was tuned to in GQRX and subtract the actual frequency of the channel. So if GQRX says the carrier is on 856.614 for the 856.6125 control channel it's
$
856.614 \text{MHz} - 856.6125\text{MHz} = 0.0015 \text{MHz}
$
Multiply by 1000000 to get Hz:
$
0.0015 \text{MHz} * 1000000 = 1,500 Hz
$
| Radio | Tuning Error |
| -------- | ------------ |
| 00000101 | -1300 Hz |
| 00000102 | Zero |
| 00000103 | Zero |
| 00000104 | Zero |
| 00000105 | Zero |
| 00000106 | Zero |
Ok, so that was the plan until one of the SDR's had zero signal and I couldn't tell which was which so I'm going to do this one at a time and verify the serials.
I did that and all of them worked — I probably just had something not connected correctly. The first unit is a very old RTL-SDR blog unit and it had a minor tuning error. The others are all various later generations of Nooelec NESDR's and were perfect. Yay.
Ok, that worked, but I lack a talk groups file. I found one but the CSV format is very specific, from the output of the program:
```
Required columns are: 'Decimal', 'Mode', 'Description'
[2024-09-13 14:46:14.584062] (error) Optional columns are: 'Alpha Tag', 'Hex', 'Category', 'Tag', 'Priority', 'Preferred NAC'
```
Ok, that was pretty simple. I have a bunch of json files and audio recordings getting dumped to a directory.
Here's the final config
```json
{
"ver": 2,
"sources": [{
"center": 851503125,
"rate": 2048000,
"error": 0,
"gain": 39,
"debugRecorders": 0,
"digitalRecorders": 4,
"driver": "osmosdr",
"device": "rtl=00000104"
}, {
"center": 853775000,
"rate": 2048000,
"error": 0,
"gain": 39,
"digitalRecorders": 4,
"driver": "osmosdr",
"device": "rtl=00000105"
}, {
"center": 856050000,
"rate": 2048000,
"error": 0,
"gain": 39,
"digitalRecorders": 4,
"driver": "osmosdr",
"device": "rtl=00000106"
}],
"systems": [{
"control_channels": [855487500, 855712500, 855962500, 856612500],
"type": "p25",
"shortName": "coirsdwhu",
"modulation": "qpsk",
"talkgroupsFile": "talkgroups.csv",
"apiKey": "REDACTED"
}],
"uploadServer": "https://api.openmhz.com",
"captureDir": "trunk-recordings"
}
```
Note that they all have `”error”: 0` because I didn’t use the RTLSDR with the tuning drift. It’s still in a box for the next project.
Next, I used the Docker instructions on a raspberry pi to get the config from my Fedora laptop working on the Pi rather quickly. I put the configuration and talk-group file in a directory with the following docker-compose.yml file.
```yaml
services:
recorder:
image: robotastic/trunk-recorder:latest
container_name: trunk-recorder
restart: always
privileged: true
volumes:
- /dev/bus/usb:/dev/bus/usb
- /var/run/dbus:/var/run/dbus
- /var/run/avahi-daemon/socket:/var/run/avahi-daemon/socket
- ./:/app
```
I just `docker compose up -d`, checked the logs and the thing worked. It’s uploading to OpenMHz as COIRS [Dublin/Worthington/Hilliard/UA System](https://openmhz.com/system/coirsdwhu). You can go there and listen all you like I'm working through some labeling on the talk groups, but other than that it seems to be working well.
Next I’ll be setting up monitoring for the hardware as part of the [[Danklab Modernization Project]].