aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Berndt <lukekb@gmail.com>2023-02-06 21:26:12 -0500
committerLuke Berndt <lukekb@gmail.com>2023-02-06 21:26:12 -0500
commit088ae9fc9b3992d1cca2bc069ed43b5c77639633 (patch)
tree671d6536bad9d8088239a54aa870f31d4534af08
parent73967269dea3276456ac9cccf730f6c6f6b0a221 (diff)
parenta11e502cf39fd7e1144180bcfb40223f92b3fc91 (diff)
Merge branch 'master' into pr/758
-rw-r--r--Dockerfile1
-rw-r--r--docs/CONFIGURE.md111
-rw-r--r--docs/INSTALL-LINUX.md26
-rw-r--r--docs/INSTALL-MAC.md4
-rw-r--r--lib/op25_repeater/lib/frame_assembler_impl.h2
-rw-r--r--plugins/broadcastify_uploader/broadcastify_uploader.cc12
-rw-r--r--trunk-recorder/call_concluder/call_concluder.cc3
-rw-r--r--trunk-recorder/gr_blocks/decoders/signal_decoder_sink_impl.cc8
-rw-r--r--trunk-recorder/main.cc600
-rw-r--r--trunk-recorder/plugin_manager/plugin_manager.cc8
-rw-r--r--trunk-recorder/source.cc1
-rw-r--r--trunk-recorder/systems/system.h2
-rw-r--r--trunk-recorder/systems/system_impl.cc2
-rw-r--r--trunk-recorder/systems/system_impl.h2
-rw-r--r--trunk-recorder/unit_tag.cc5
-rw-r--r--trunk-recorder/unit_tag.h6
-rw-r--r--trunk-recorder/unit_tags.cc27
-rw-r--r--trunk-recorder/unit_tags.h4
18 files changed, 456 insertions, 368 deletions
diff --git a/Dockerfile b/Dockerfile
index 1364bb24..c49ea727 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -9,6 +9,7 @@ RUN apt-get update && \
build-essential \
ca-certificates \
cmake \
+ curl \
docker.io \
fdkaac \
git \
diff --git a/docs/CONFIGURE.md b/docs/CONFIGURE.md
index d8fcd0b0..9d0d104a 100644
--- a/docs/CONFIGURE.md
+++ b/docs/CONFIGURE.md
@@ -26,31 +26,31 @@ The amount of tuning error is -14500Hz, so that would go under **error:** for th
**NOTE:** In some instances, an alternative is to use `ppm` correction rather than the `error` configuration option.
-Alternatively, you can use this tool here: http://garvas.org/trunk-recorder/ to obtain RTL-SDR dongle/array configurations.
+Alternatively, you can use this tool here: http://garvas.org/trunk-recorder/ to obtain RTL-SDR dongle/array configurations.
### Gain
-After you have figured out the amount of tuning error, you now need to find the optimal amount of receiver gain to use.
+After you have figured out the amount of tuning error, you now need to find the optimal amount of receiver gain to use.
-Gain is a measure of how much amplification is required for the received signal, and on some SDRs, there are multiple places along the receive path where a signal can be amplified.
+Gain is a measure of how much amplification is required for the received signal, and on some SDRs, there are multiple places along the receive path where a signal can be amplified.
-If there is not enough gain, the signal will not be strong enough to decode, and Trunk-Recorder will fail to lock to the control channel. If there is too much gain, it can distort the signal, there is also the chance you might be causing harm to your SDR reception device. Setting the gain too high will result in amplification of the background RF and create noise.
+If there is not enough gain, the signal will not be strong enough to decode, and Trunk-Recorder will fail to lock to the control channel. If there is too much gain, it can distort the signal, there is also the chance you might be causing harm to your SDR reception device. Setting the gain too high will result in amplification of the background RF and create noise.
-Generally, you can mess around with the gain slider in GQRX until the signal looks well defined and there isn't too much noise. If it is impossible to get a well-defined signal, it could be a sign that you have one or more issues: a better antenna that is tuned to the needed frequency range, moving the antenna to a new location, or using a different SDR device. There could also be some strong interference nearby, which can introduce a lot of background noise making it tough to distinguish the signal. Various computer hardware, poorly grounded hardware, and cheaply made USB hubs can be notorious for producing RF noise across the entire spectrum.
+Generally, you can mess around with the gain slider in GQRX until the signal looks well defined and there isn't too much noise. If it is impossible to get a well-defined signal, it could be a sign that you have one or more issues: a better antenna that is tuned to the needed frequency range, moving the antenna to a new location, or using a different SDR device. There could also be some strong interference nearby, which can introduce a lot of background noise making it tough to distinguish the signal. Various computer hardware, poorly grounded hardware, and cheaply made USB hubs can be notorious for producing RF noise across the entire spectrum.
Once you find the correct gain settings, use them for this source in the `config.json` file.
### Center Frequency
-When you set the center frequency for a source, **you are picking the frequency that will be in the _middle_ of the block of spectrum that you are recording**. Half of the bandwidth for the device will be above that frequency and the other half below.
+When you set the center frequency for a source, **you are picking the frequency that will be in the _middle_ of the block of spectrum that you are recording**. Half of the bandwidth for the device will be above that frequency and the other half below.
-For example, if you are using a HackRF, with 8MHz of bandwidth, and you tune the center frequency to 854MHz, it would cover from 850.0MHz to 858.0MHz.
+For example, if you are using a HackRF, with 8MHz of bandwidth, and you tune the center frequency to 854MHz, it would cover from 850.0MHz to 858.0MHz.
To find your ideal center frequency, look at what the lowest frequency you want to cover is and what the highest is. You need to need to be able cover slightly beyond the frequncy of a channel. This is because the frequency is for the center of the channel and the actual channel is wider and a bit of filtering is done to receive it. The sample rate should be higher than the difference between the low and high frequency. Most SDRs do not perform as well right at the beginnging and end of the frequency range they are set to. It is best to set a slightly higher sample rate than needed, to avoid those spots. Also, some SDRs have some artifacts right at there center frequency, so ensure that center frequency doesn't land on the frequency of a channel you are trying to record.
### Multiple Sources
-If the low frequency and high frequency of the system you are trying to capture is greater than the amount of bandwidth your SDR can capture, you need to use multiple SDRs.
+If the low frequency and high frequency of the system you are trying to capture is greater than the amount of bandwidth your SDR can capture, you need to use multiple SDRs.
-In addition to being able to use a cheaper SDR, it also helps with general performance of the devices. When a single SDR is used, each of the Recorders gets fed all of the sampled signals. Each Recorder needs to cut down the multi-mega samples per second into a small 12.5Khz or even 6.25Khz(!) slivers.
+In addition to being able to use a cheaper SDR, it also helps with general performance of the devices. When a single SDR is used, each of the Recorders gets fed all of the sampled signals. Each Recorder needs to cut down the multi-mega samples per second into a small 12.5Khz or even 6.25Khz(!) slivers.
When you use multiple SDRs, each SDR is capturing only a partial slice of the system so the recorders have to cut down a much smaller amount of sample to get to the sliver they are interested in. This ultimately denotes that you can have a lot more recorders running!
@@ -91,11 +91,11 @@ Here is a map of the different sections of the *config.json* file:
```json
{
- Global Configs
-
- "sources": [{ Source Object }, { Source Object }],
- "systems": [{ System Object }, { System Object }],
- "plugins": [{ Plugin Object }]
+ Global Configs
+
+ "sources": [{ Source Object }, { Source Object }],
+ "systems": [{ System Object }, { System Object }],
+ "plugins": [{ Plugin Object }]
}
```
@@ -103,29 +103,30 @@ Here is a map of the different sections of the *config.json* file:
### Global Configs
-| Key | Required | Default Value | Type | Description |
-| ----------------------- | :------: | ----------------- | ----------------------------------------------------------- | ------------------------------------------------------------ |
-| ver | ✓ | | number | the version of formatting for the config file. **This should be set to 2**. Trunk Recorder will not start without this set. |
-| sources | ✓ | | array of JSON objects<br />[{}] | An array of JSON formatted [Source Objects](#source-object) that define the different SDRs available. Source Objects are described below. |
-| systems | ✓ | | array of JSON objects<br />[{}] | An array of JSON formatted [System Objects](#system-object) that define the trunking systems that will be recorded. System Objects are described below. |
-| plugins | | | array of JSON objects<br />[{}] | An array of JSON formatted [Plugin Objects](#plugin-object) that define the different plugins to use. Refer to the [Plugin System](notes/PLUGIN-SYSTEM.md) documentation for more details. |
-| defaultMode | | "digital" | **"analog"** or **"digital"** | Default mode to use when a talkgroups is not listed in the **talkgroupsFile**. The options are *digital* or *analog*. The default is *digital*. This argument is global and not system-specific, and only affects `smartnet` trunking systems which can have both analog and digital talkpaths. |
-| captureDir | | current directory | string | The complete path to the directory where recordings should be saved. |
-| callTimeout | | 3 | number | A Call will stop recording and save if it has not received anything on the control channel, after this many seconds. |
-| uploadServer | | | string | The URL for uploading to OpenMHz. The default is an empty string. See the Config tab for your system in OpenMHz to find what the value should be. |
-| broadcastifyCallsServer | | | string | The URL for uploading to Broadcastify Calls. The default is an empty string. Refer to [Broadcastify's wiki](https://wiki.radioreference.com/index.php/Broadcastify-Calls-API) for the upload URL. |
-| | | | | |
-| logFile | | false | **true** / **false** | Save the console output to a file. |
-| frequencyFormat | | "exp" | **"exp" "mhz"** or **"hz"** | the display format for frequencies to display in the console and log file. |
-| controlWarnRate | | 10 | number | Log the control channel decode rate when it falls bellow this threshold. The value of *-1* will always log the decode rate. |
-| statusAsString | | true | **true** / **false** | Show status as strings instead of numeric values |
-| statusServer | | | string | The URL for a WebSocket connect. Trunk Recorder will send JSON formatted update message to this address. HTTPS is currently not supported, but will be in the future. OpenMHz does not support this currently. [JSON format of messages](./notes/STATUS-JSON.md) |
-| broadcastSignals | | true | **true** / **false** | Broadcast decoded signals to the status server. |
-| logLevel | | "info" | **"trace" "debug" "info" "warning" "error"** or **"fatal"** | the logging level to display in the console and log file. The options are *trace*, *debug*, *info*, *warning*, *error* & *fatal*. The default is *info*. |
-| debugRecorder | | true | **true** / **false** | Will attach a debug recorder to each Source. The debug recorder will allow you to examine the channel of a call be recorded. There is a single Recorder per Source. It will monitor a recording and when it is done, it will monitor the next recording started. The information is sent over a network connection and can be viewed using the `udp-debug.grc` graph in GnuRadio Companion |
-| debugRecorderPort | | 1234 | number | The network port that the Debug Recorders will start on. For each Source an additional Debug Recorder will be added and the port used will be one higher than the last one. For example the ports for a system with 3 Sources would be: 1234, 12345, 1236. |
-| debugRecorderAddress | | "127.0.0.1" | string | The network address of the computer that will be monitoring the Debug Recorders. UDP packets will be sent from Trunk Recorder to this computer. The default is *"127.0.0.1"* which is the address used for monitoring on the same computer as Trunk Recorder. |
-| audioStreaming | | false | **true** / **false** | whether or not to enable the audio streaming callbacks for plugins. |
+| Key | Required | Default Value | Type | Description |
+| ---------------------------- | :------: | ----------------- | ----------------------------------------------------------- | ------------------------------------------------------------ |
+| ver | ✓ | | number | the version of formatting for the config file. **This should be set to 2**. Trunk Recorder will not start without this set. |
+| sources | ✓ | | array of JSON objects<br />[{}] | An array of JSON formatted [Source Objects](#source-object) that define the different SDRs available. Source Objects are described below. |
+| systems | ✓ | | array of JSON objects<br />[{}] | An array of JSON formatted [System Objects](#system-object) that define the trunking systems that will be recorded. System Objects are described below. |
+| plugins | | | array of JSON objects<br />[{}] | An array of JSON formatted [Plugin Objects](#plugin-object) that define the different plugins to use. Refer to the [Plugin System](notes/PLUGIN-SYSTEM.md) documentation for more details. |
+| defaultMode | | "digital" | **"analog"** or **"digital"** | Default mode to use when a talkgroups is not listed in the **talkgroupsFile**. The options are *digital* or *analog*. The default is *digital*. This argument is global and not system-specific, and only affects `smartnet` trunking systems which can have both analog and digital talkpaths. |
+| captureDir | | current directory | string | The complete path to the directory where recordings should be saved. |
+| callTimeout | | 3 | number | A Call will stop recording and save if it has not received anything on the control channel, after this many seconds. |
+| uploadServer | | | string | The URL for uploading to OpenMHz. The default is an empty string. See the Config tab for your system in OpenMHz to find what the value should be. |
+| broadcastifyCallsServer | | | string | The URL for uploading to Broadcastify Calls. The default is an empty string. Refer to [Broadcastify's wiki](https://wiki.radioreference.com/index.php/Broadcastify-Calls-API) for the upload URL. |
+| broadcastifySslVerifyDisable | | false | **true** / **false** | Optionally disable SSL verification for Broadcastify uploads, given their apparent habit of letting their SSL certificate expire |
+| | | | | |
+| logFile | | false | **true** / **false** | Save the console output to a file. |
+| frequencyFormat | | "exp" | **"exp" "mhz"** or **"hz"** | the display format for frequencies to display in the console and log file. |
+| controlWarnRate | | 10 | number | Log the control channel decode rate when it falls bellow this threshold. The value of *-1* will always log the decode rate. |
+| statusAsString | | true | **true** / **false** | Show status as strings instead of numeric values |
+| statusServer | | | string | The URL for a WebSocket connect. Trunk Recorder will send JSON formatted update message to this address. HTTPS is currently not supported, but will be in the future. OpenMHz does not support this currently. [JSON format of messages](./notes/STATUS-JSON.md) |
+| broadcastSignals | | true | **true** / **false** | Broadcast decoded signals to the status server. |
+| logLevel | | "info" | **"trace" "debug" "info" "warning" "error"** or **"fatal"** | the logging level to display in the console and log file. The options are *trace*, *debug*, *info*, *warning*, *error* & *fatal*. The default is *info*. |
+| debugRecorder | | true | **true** / **false** | Will attach a debug recorder to each Source. The debug recorder will allow you to examine the channel of a call be recorded. There is a single Recorder per Source. It will monitor a recording and when it is done, it will monitor the next recording started. The information is sent over a network connection and can be viewed using the `udp-debug.grc` graph in GnuRadio Companion |
+| debugRecorderPort | | 1234 | number | The network port that the Debug Recorders will start on. For each Source an additional Debug Recorder will be added and the port used will be one higher than the last one. For example the ports for a system with 3 Sources would be: 1234, 12345, 1236. |
+| debugRecorderAddress | | "127.0.0.1" | string | The network address of the computer that will be monitoring the Debug Recorders. UDP packets will be sent from Trunk Recorder to this computer. The default is *"127.0.0.1"* which is the address used for monitoring on the same computer as Trunk Recorder. |
+| audioStreaming | | false | **true** / **false** | whether or not to enable the audio streaming callbacks for plugins. |
@@ -151,6 +152,7 @@ Here is a map of the different sections of the *config.json* file:
| vga1Gain | | | number | [bladeRF only] sets the **VGA1** gain. |
| vga2Gain | | | number | [bladeRF only] sets the **VGA2** gain. |
| antenna | | | string, e.g.: **"TX/RX"** | [usrp] selects which antenna jack to use |
+| enabled | | true | **true** / **false** | control whether a configured source is enabled or disabled |
#### System Object
@@ -177,9 +179,9 @@ Here is a map of the different sections of the *config.json* file:
| analogLevels | | 8 | number (1-32) | The amount of amplification that will be applied to the analog audio. |
| maxDev | | 4000 | number | Allows you to set the maximum deviation for analog channels. If you analog recordings sound good or if you have a completely digital system, then there is no need to touch this. |
| digitalLevels | | 1 | number (1-16) | The amount of amplification that will be applied to the digital audio. |
-| unitTagsFile | | | string | This is the filename of a CSV files that provides information about the unit tags. It allows a Unit ID to be assigned a name. This file should be located in the same directory as the trunk-recorder executable. The format is 2 columns, the first being the decimal number of the Unit ID, the second is the Unit Name, |
+| unitTagsFile | | | string | This is the filename of a CSV file that provides information about the unit tags. The format for the file is described below. |
| recordUnknown | | true | **true** / **false** | Record talkgroups if they are not listed in the Talkgroups File. |
-| recordUUVCalls | | true | **true** / **false** | [ P25 only ] Record Unit to Unit Voice calls. |
+| recordUUVCalls | | true | **true** / **false** | [ P25 only ] Record Unit to Unit Voice calls. |
| hideEncrypted | | false | **true** / **false** | Hide encrypted talkgroups log entries |
| hideUnknownTalkgroups | | false | **true** / **false** | Hide unknown talkgroups log entries |
| minDuration | | 0<br />(which is disabled) | number | The minimum call duration in seconds (decimals allowed), calls below this number will have recordings deleted and will not be uploaded. |
@@ -195,6 +197,7 @@ Here is a map of the different sections of the *config.json* file:
| decodeFSync | | false | **true** / **false** | [ Conventional systems only ] enable the Fleet Sync signaling decoder. |
| decodeStar | | false | **true** / **false** | [ Conventional systems only ] enable the Star signaling decoder. |
| decodeTPS | | false | **true** / **false** | [ Conventional systems only ] enable the Motorola Tactical Public Safety (aka FDNY Fireground) signaling decoder. |
+| enabled | | true | **true** / **false** | control whether a configured system is enabled or disabled |
#### System Object - Experimental Options
@@ -211,6 +214,7 @@ Multi-Site mode attempts to avoid recording duplicate calls being broadcasted on
| ------- | :------: | ------------- | ------ | ------------------------------------------------------------ |
| library | ✓ | | string | the name of the library that contains the plugin. |
| name | ✓ | | string | the name of the plugin. This name is used to find the `<name>_plugin_new` method that creates a new instance of the plugin. |
+| enabled | | true | **true** / **false** | control whether a configured plugin is enabled or disabled |
| | | | | *Additional elements can be added, they will be passed into the `parse_config` method of the plugin.* |
##### Rdio Scanner Plugin
@@ -254,9 +258,9 @@ This plugin makes it easy to connect Trunk Recorder with [Rdio Scanner](https://
**Name:** simplestream
**Library:** libsimplestream.so
-This plugin streams uncompressed audio (16 bit Int, 8 kHz, mono) to UDP or TCP ports in real time as it is being recorded by trunk-recorder. It can be configured to stream audio from all talkgroups and systems being recorded or only specified talkgroups and systems. TGID information can be prepended to the audio data to allow the receiving program to take action based on the TGID. Audio from different Systems should be streamed to different UDP/TCP ports to prevent crosstalk and interleaved audio from talkgroups with the same TGID on different systems.
+This plugin streams uncompressed audio (16 bit Int, 8 kHz, mono) to UDP or TCP ports in real time as it is being recorded by trunk-recorder. It can be configured to stream audio from all talkgroups and systems being recorded or only specified talkgroups and systems. TGID information can be prepended to the audio data to allow the receiving program to take action based on the TGID. Audio from different Systems should be streamed to different UDP/TCP ports to prevent crosstalk and interleaved audio from talkgroups with the same TGID on different systems.
-This plugin does not, by itself, stream audio to any online services. Because it sends uncompressed PCM audio, it is not bandwidth efficient and is intended mostly to send audio to other programs running on the same computer as trunk-recorder or to other computers on the LAN. The programs receiving PCM audio from this plugin may play it on speakers, compress it and stream it to an online service, etc.
+This plugin does not, by itself, stream audio to any online services. Because it sends uncompressed PCM audio, it is not bandwidth efficient and is intended mostly to send audio to other programs running on the same computer as trunk-recorder or to other computers on the LAN. The programs receiving PCM audio from this plugin may play it on speakers, compress it and stream it to an online service, etc.
**NOTE 1: In order for this plugin to work, the audioStreaming option in the Global Configs section (see above) must be set to true.**
@@ -274,11 +278,11 @@ This plugin does not, by itself, stream audio to any online services. Because i
| port | ✓ | | number | UDP or TCP port that this stream will send audio to. |
| TGID | ✓ | | number | Audio from this Talkgroup ID will be sent on this stream. Set to 0 to stream all recorded talkgroups. |
| sendTGID | | false | boolean | When set to true, the TGID will be prepended in long integer format (4 bytes, little endian) to the audio data each time a packet is sent. |
-| shortName | | |string | shortName of the System that audio should be streamed for. This should match the shortName of a system that is defined in the main section of the config file. When omitted, all Systems will be streamed to the address and port configured. If TGIDs from Systems overlap, each system must be sent to a different port to prevent interleaved audio for talkgroups from different Systems with the same TGID.
+| shortName | | |string | shortName of the System that audio should be streamed for. This should match the shortName of a system that is defined in the main section of the config file. When omitted, all Systems will be streamed to the address and port configured. If TGIDs from Systems overlap, each system must be sent to a different port to prevent interleaved audio for talkgroups from different Systems with the same TGID.
| useTCP | | false |boolean | When set to true, TCP will be used instead of UDP.
###### Plugin Object Example #1:
-This example will stream audio from talkgroup 58914 on system "CountyTrunked" to the local machine on UDP port 9123.
+This example will stream audio from talkgroup 58914 on system "CountyTrunked" to the local machine on UDP port 9123.
```yaml
{
"name":"simplestream",
@@ -350,11 +354,11 @@ pulseaudio is the default sound system on many Linux computers, including the Ra
An example command to set up pulseaudio to receive 8 kHz audio (digital audio) from simplestream on TCP port 9125:
```
-pacmd load-module module-simple-protocol-tcp sink=1 playback=true port=9125 format=s16le rate=8000 channels=1
+pacmd load-module module-simple-protocol-tcp sink=1 playback=true port=9125 format=s16le rate=8000 channels=1
```
An example command to set up pulseaudio to receive 16 kHz audio (analog audio) from simplestream on TCP port 9125:
```
-pacmd load-module module-simple-protocol-tcp sink=1 playback=true port=9125 format=s16le rate=16000 channels=1
+pacmd load-module module-simple-protocol-tcp sink=1 playback=true port=9125 format=s16le rate=16000 channels=1
```
The matching simplestream config to send audio from talkgroup 58918 to TCP port 9125 would then be something like this:
```yaml
@@ -394,7 +398,7 @@ Here are the column headers and some sample data: NOTE: If you are adding the Pr
## channelFile
-This file allows for you to specify additional information about conventional channels. A recorder is started for each line in the file and set the to frequency specified. The type of recorder is based on the type of System. A *Conventional* system would have Analog Recorders, while a *ConventionalP25* or *ConventionalDMR* would have digital recorders.
+This file allows for you to specify additional information about conventional channels. A recorder is started for each line in the file and set the to frequency specified. The type of recorder is based on the type of System. A *Conventional* system would have Analog Recorders, while a *ConventionalP25* or *ConventionalDMR* would have digital recorders.
*Tone based squelch is currently not supported.*
@@ -404,3 +408,18 @@ The **Enable** Column is optional and defaults to *True*. It only needs to be ad
| --------- | --------- | -------- | ------------- | ---------------------- | ------ | ------ | ------------------- |
| 300 | 462275000 | 94.8 PL | Town A Police | Town A Police Dispatch | Police | Town A | |
| 325 | 462275000 | 151.4 PL | Town B DPW | Town B Trash Dispatch | DPW | Town B | False |
+
+
+## unitTagsFile
+
+This file allows for Unit IDs to be assigned a name. The format is 2 columns, the first being the decimal number of the Unit ID, the second is the Unit Name.
+
+Regex is also supported for the Unit ID, which can be used to match radio IDs of a specific pattern. By default, the regex must match the full string (`^pattern$`), however putting the pattern within `/` will allow partial matches. Within the unit name, `$1`, `$2`, etc. will be replaced by the corresponding capture group. For large radio systems, regex may be better instead of specifying a long list of radio IDs. In case a Unit ID will be matched by regex but you do not want to use the associated unit name, you can put the specific unit ID and unit name before the regex, so it will be chosen before reaching the regex.
+
+In the second row of the example below, the first capture group `([0-9]{2})` becomes `$1` for the unit name, so an ID like 1210207 gets translated to Engine 20. In the third row, only the start of the string is being matched, so an ID of 173102555 is translated into Ambulance 102.
+
+| Unit ID | Unit Name |
+| --------- | --------- |
+| 911000 | Dispatch |
+| 1[1245]10([0-9]{2})[127] | Engine $1 |
+| /^1[78]3(1[0-9]{2})/ | Ambulance $1 |
diff --git a/docs/INSTALL-LINUX.md b/docs/INSTALL-LINUX.md
index ef5d4a85..20a63db5 100644
--- a/docs/INSTALL-LINUX.md
+++ b/docs/INSTALL-LINUX.md
@@ -137,6 +137,32 @@ make
sudo make install
```
+## Configuring the UHD for Ettus SDRs
+
+If you haven't setup UHD yet there are a few extra steps you need to take:
+
+Install the UHD drivers:
+
+```bash
+sudo apt-get install libuhd-dev uhd-host
+```
+
+Download the firmware images. The location of the downloader is different than the error message:
+
+```bash
+cd /lib/uhd/utils/
+sudo ./uhd_images_downloader.py
+```
+
+Setup the udev rules so any user can access the USB, as documented [here](https://files.ettus.com/manual/page_transport.html#transport_usb_udev):
+
+```bash
+cd /usr/lib/uhd/utils
+sudo cp uhd-usrp.rules /etc/udev/rules.d/
+sudo udevadm control --reload-rules
+sudo udevadm trigger
+```
+
## Configuring Trunk Recorder
The next step is to [configure Trunk Recorder](CONFIGURE.md) for the system you are trying to capture.
diff --git a/docs/INSTALL-MAC.md b/docs/INSTALL-MAC.md
index 6e29e064..24be9caa 100644
--- a/docs/INSTALL-MAC.md
+++ b/docs/INSTALL-MAC.md
@@ -40,9 +40,11 @@ At this point, proceed to the [build instructions](#building-trunk-recorder).
Note that you will need to provide the flag `-DOPENSSL_ROOT_DIR=/usr/local/opt/openssl` to the invocation of `cmake` in the [Build Instructions](https://github.com/robotastic/trunk-recorder/wiki/Building-Trunk-Recorder) or you will receive an error from CMake about not finding libssl or a linking error from `make` about not having a library for `-lssl`:
```bash
-cmake ../trunk-recorder -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl
+cmake ../trunk-recorder -DOPENSSL_ROOT_DIR=/opt/homebrew/opt/openssl@3
```
+
+
## Using MacPorts
### These instructions should work on OS X 10.10, OS X 10.11, and macOS 10.12.
diff --git a/lib/op25_repeater/lib/frame_assembler_impl.h b/lib/op25_repeater/lib/frame_assembler_impl.h
index 1f508d2a..dc08ff82 100644
--- a/lib/op25_repeater/lib/frame_assembler_impl.h
+++ b/lib/op25_repeater/lib/frame_assembler_impl.h
@@ -29,7 +29,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <deque>
-
+#include <array>
#include "rx_base.h"
typedef std::deque<uint8_t> dibit_queue;
diff --git a/plugins/broadcastify_uploader/broadcastify_uploader.cc b/plugins/broadcastify_uploader/broadcastify_uploader.cc
index 350b5c73..1a32b45d 100644
--- a/plugins/broadcastify_uploader/broadcastify_uploader.cc
+++ b/plugins/broadcastify_uploader/broadcastify_uploader.cc
@@ -18,6 +18,7 @@ struct Broadcastify_System_Key {
struct Broadcastify_Uploader_Data {
std::vector<Broadcastify_System_Key> keys;
std::string bcfy_calls_server;
+ bool ssl_verify_disable;
};
class Broadcastify_Uploader : public Plugin_Api {
@@ -181,6 +182,12 @@ public:
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_buffer);
+ // broadcastify seems to make a habit out of letting their ssl certs expire
+ if (this->data.ssl_verify_disable) {
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
+ }
+
curl_multi_add_handle(multi_handle, curl);
curl_multi_perform(multi_handle, &still_running);
@@ -334,6 +341,11 @@ public:
return 1;
}
+ this->data.ssl_verify_disable = cfg.get<bool>("broadcastifySslVerifyDisable", false);
+ if (this->data.ssl_verify_disable) {
+ BOOST_LOG_TRIVIAL(info) << "Broadcastify SSL Verify Disabled";
+ }
+
BOOST_FOREACH (boost::property_tree::ptree::value_type &node, cfg.get_child("systems")) {
boost::optional<boost::property_tree::ptree &> broadcastify_exists = node.second.get_child_optional("broadcastifyApiKey");
if (broadcastify_exists) {
diff --git a/trunk-recorder/call_concluder/call_concluder.cc b/trunk-recorder/call_concluder/call_concluder.cc
index 1684294c..dbf17b39 100644
--- a/trunk-recorder/call_concluder/call_concluder.cc
+++ b/trunk-recorder/call_concluder/call_concluder.cc
@@ -288,8 +288,7 @@ Call_Data_t Call_Concluder::create_call_data(Call *call, System *sys, Config con
call_info.stop_time = t.stop_time;
}
- UnitTag *unit_tag = sys->find_unit_tag(t.source);
- std::string tag = (unit_tag == NULL || unit_tag->tag.empty() ? "" : unit_tag->tag);
+ std::string tag = sys->find_unit_tag(t.source);
Call_Source call_source = {t.source, t.start_time, total_length, false, "", tag};
Call_Error call_error = {t.start_time, total_length, t.length, t.error_count, t.spike_count};
call_info.transmission_source_list.push_back(call_source);
diff --git a/trunk-recorder/gr_blocks/decoders/signal_decoder_sink_impl.cc b/trunk-recorder/gr_blocks/decoders/signal_decoder_sink_impl.cc
index 8044fa10..56d6bbe0 100644
--- a/trunk-recorder/gr_blocks/decoders/signal_decoder_sink_impl.cc
+++ b/trunk-recorder/gr_blocks/decoders/signal_decoder_sink_impl.cc
@@ -91,7 +91,7 @@ void mdc_callback(int frameCount, // 1 or 2 - if 2 then extra0-3 are valid
"\"ex3\":\"%02x\"}\n",
(int)time(NULL), op, arg, unitID, extra0, extra1, extra2, extra3);
- fprintf(stdout, "%s\n", json_buffer);
+ BOOST_LOG_TRIVIAL(info) << json_buffer;
signal_decoder_sink_impl *decoder = (signal_decoder_sink_impl *)context;
@@ -116,7 +116,8 @@ void fsync_callback(int cmd, int subcmd, int from_fleet, int from_unit, int to_f
to_fleet, to_unit, allflag,
payload_len, payload,
is_fsync2, is_2400);
- fprintf(stdout, "%s\n", json_buffer);
+
+ BOOST_LOG_TRIVIAL(info) << json_buffer;
signal_decoder_sink_impl *decoder = (signal_decoder_sink_impl *)context;
decoder->log_decoder_msg(from_unit, "FLEETSYNC", SignalType::Normal);
@@ -131,7 +132,8 @@ void star_callback(int unitID, int tag, int status, int message, void *context)
"\"status\":\"%d\","
"\"message\":\"%d\"}\n",
(int)time(NULL), unitID, tag, status, message);
- fprintf(stdout, "%s\n", json_buffer);
+
+ BOOST_LOG_TRIVIAL(info) << json_buffer;
signal_decoder_sink_impl *decoder = (signal_decoder_sink_impl *)context;
decoder->log_decoder_msg(unitID, "STAR", SignalType::Normal);
diff --git a/trunk-recorder/main.cc b/trunk-recorder/main.cc
index 9647ae92..9063ae03 100644
--- a/trunk-recorder/main.cc
+++ b/trunk-recorder/main.cc
@@ -149,7 +149,18 @@ bool load_config(string config_file) {
BOOST_LOG_TRIVIAL(info) << "After you have made these updates, make sure you add \"ver\": 2, to the top.\n\n";
return false;
}
-
+ config.log_file = pt.get<bool>("logFile", false);
+ BOOST_LOG_TRIVIAL(info) << "Log to File: " << config.log_file;
+ config.log_dir = pt.get<std::string>("logDir", "logs");
+ BOOST_LOG_TRIVIAL(info) << "Log Directory: " << config.log_dir;
+ if (config.log_file) {
+ logging::add_file_log(
+ keywords::file_name = config.log_dir + "/%m-%d-%Y_%H%M_%2N.log",
+ keywords::format = "[%TimeStamp%] (%Severity%) %Message%",
+ keywords::rotation_size = 100 * 1024 * 1024,
+ keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0),
+ keywords::auto_flush = true);
+ }
BOOST_LOG_TRIVIAL(info) << "\n-------------------------------------\n Trunk Recorder\n-------------------------------------\n";
BOOST_LOG_TRIVIAL(info) << "\n\n-------------------------------------\nINSTANCE\n-------------------------------------\n";
@@ -177,10 +188,6 @@ bool load_config(string config_file) {
BOOST_LOG_TRIVIAL(info) << "Default Mode: " << default_mode;
config.call_timeout = pt.get<int>("callTimeout", 3);
BOOST_LOG_TRIVIAL(info) << "Call Timeout (seconds): " << config.call_timeout;
- config.log_file = pt.get<bool>("logFile", false);
- BOOST_LOG_TRIVIAL(info) << "Log to File: " << config.log_file;
- config.log_dir = pt.get<std::string>("logDir", "logs");
- BOOST_LOG_TRIVIAL(info) << "Log Directory: " << config.log_dir;
config.control_message_warn_rate = pt.get<int>("controlWarnRate", 10);
BOOST_LOG_TRIVIAL(info) << "Control channel warning rate: " << config.control_message_warn_rate;
config.control_retune_limit = pt.get<int>("controlRetuneLimit", 0);
@@ -215,341 +222,346 @@ bool load_config(string config_file) {
BOOST_FOREACH (boost::property_tree::ptree::value_type &node,
pt.get_child("systems")) {
- // each system should have a unique index value;
- System *system = System::make(sys_count++);
+ bool system_enabled = node.second.get<bool>("enabled", true);
+ if (system_enabled) {
+ // each system should have a unique index value;
+ System *system = System::make(sys_count++);
- std::stringstream default_script;
- unsigned long sys_id;
- unsigned long wacn;
- unsigned long nac;
- default_script << "sys_" << sys_count;
+ std::stringstream default_script;
+ unsigned long sys_id;
+ unsigned long wacn;
+ unsigned long nac;
+ default_script << "sys_" << sys_count;
- BOOST_LOG_TRIVIAL(info) << "\n\nSystem Number: " << sys_count << "\n-------------------------------------\n";
- system->set_short_name(node.second.get<std::string>("shortName", default_script.str()));
- BOOST_LOG_TRIVIAL(info) << "Short Name: " << system->get_short_name();
+ BOOST_LOG_TRIVIAL(info) << "\n\nSystem Number: " << sys_count << "\n-------------------------------------\n";
+ system->set_short_name(node.second.get<std::string>("shortName", default_script.str()));
+ BOOST_LOG_TRIVIAL(info) << "Short Name: " << system->get_short_name();
- system->set_system_type(node.second.get<std::string>("type"));
- BOOST_LOG_TRIVIAL(info) << "System Type: " << system->get_system_type();
+ system->set_system_type(node.second.get<std::string>("type"));
+ BOOST_LOG_TRIVIAL(info) << "System Type: " << system->get_system_type();
- // If it is a conventional System
- if ((system->get_system_type() == "conventional") || (system->get_system_type() == "conventionalP25") || (system->get_system_type() == "conventionalDMR")) {
+ // If it is a conventional System
+ if ((system->get_system_type() == "conventional") || (system->get_system_type() == "conventionalP25") || (system->get_system_type() == "conventionalDMR")) {
- boost::optional<std::string> channel_file_exist = node.second.get_optional<std::string>("channelFile");
- boost::optional<boost::property_tree::ptree &> channels_exist = node.second.get_child_optional("channels");
+ boost::optional<std::string> channel_file_exist = node.second.get_optional<std::string>("channelFile");
+ boost::optional<boost::property_tree::ptree &> channels_exist = node.second.get_child_optional("channels");
- if (channel_file_exist && channels_exist) {
- BOOST_LOG_TRIVIAL(error) << "Both \"channels\" and \"channelFile\" cannot be defined for a system!";
- return false;
- }
+ if (channel_file_exist && channels_exist) {
+ BOOST_LOG_TRIVIAL(error) << "Both \"channels\" and \"channelFile\" cannot be defined for a system!";
+ return false;
+ }
- if (channels_exist) {
- BOOST_LOG_TRIVIAL(info) << "Conventional Channels: ";
- BOOST_FOREACH (boost::property_tree::ptree::value_type &sub_node, node.second.get_child("channels")) {
- double channel = sub_node.second.get<double>("", 0);
+ if (channels_exist) {
+ BOOST_LOG_TRIVIAL(info) << "Conventional Channels: ";
+ BOOST_FOREACH (boost::property_tree::ptree::value_type &sub_node, node.second.get_child("channels")) {
+ double channel = sub_node.second.get<double>("", 0);
- BOOST_LOG_TRIVIAL(info) << " " << format_freq(channel);
- system->add_channel(channel);
+ BOOST_LOG_TRIVIAL(info) << " " << format_freq(channel);
+ system->add_channel(channel);
+ }
+ } else if (channel_file_exist) {
+ std::string channel_file = node.second.get<std::string>("channelFile");
+ BOOST_LOG_TRIVIAL(info) << "Channel File: " << channel_file;
+ system->set_channel_file(channel_file);
+ } else {
+ BOOST_LOG_TRIVIAL(error) << "Either \"channels\" or \"channelFile\" need to be defined for a conventional system!";
+ return false;
}
- } else if (channel_file_exist) {
- std::string channel_file = node.second.get<std::string>("channelFile");
- BOOST_LOG_TRIVIAL(info) << "Channel File: " << channel_file;
- system->set_channel_file(channel_file);
+ // If it is a Trunked System
+ } else if ((system->get_system_type() == "smartnet") || (system->get_system_type() == "p25")) {
+ BOOST_LOG_TRIVIAL(info) << "Control Channels: ";
+ BOOST_FOREACH (boost::property_tree::ptree::value_type &sub_node, node.second.get_child("control_channels")) {
+ double control_channel = sub_node.second.get<double>("", 0);
+ BOOST_LOG_TRIVIAL(info) << " " << format_freq(control_channel);
+ system->add_control_channel(control_channel);
+ }
+ system->set_talkgroups_file(node.second.get<std::string>("talkgroupsFile", ""));
+ BOOST_LOG_TRIVIAL(info) << "Talkgroups File: " << system->get_talkgroups_file();
} else {
- BOOST_LOG_TRIVIAL(error) << "Either \"channels\" or \"channelFile\" need to be defined for a conventional system!";
+ BOOST_LOG_TRIVIAL(error) << "System Type in config.json not recognized";
return false;
}
- // If it is a Trunked System
- } else if ((system->get_system_type() == "smartnet") || (system->get_system_type() == "p25")) {
- BOOST_LOG_TRIVIAL(info) << "Control Channels: ";
- BOOST_FOREACH (boost::property_tree::ptree::value_type &sub_node, node.second.get_child("control_channels")) {
- double control_channel = sub_node.second.get<double>("", 0);
- BOOST_LOG_TRIVIAL(info) << " " << format_freq(control_channel);
- system->add_control_channel(control_channel);
- }
- system->set_talkgroups_file(node.second.get<std::string>("talkgroupsFile", ""));
- BOOST_LOG_TRIVIAL(info) << "Talkgroups File: " << system->get_talkgroups_file();
- } else {
- BOOST_LOG_TRIVIAL(error) << "System Type in config.json not recognized";
- return false;
- }
-
- bool qpsk_mod = true;
- double digital_levels = node.second.get<double>("digitalLevels", 1.0);
- double analog_levels = node.second.get<double>("analogLevels", 8.0);
- double squelch_db = node.second.get<double>("squelch", -160);
- int max_dev = node.second.get<int>("maxDev", 4000);
- double filter_width = node.second.get<double>("filterWidth", 1.0);
- bool conversation_mode = node.second.get<bool>("conversationMode", true);
- boost::optional<std::string> mod_exists = node.second.get_optional<std::string>("modulation");
-
- if (mod_exists) {
- system_modulation = node.second.get<std::string>("modulation");
- if (boost::iequals(system_modulation, "qpsk")) {
- qpsk_mod = true;
- BOOST_LOG_TRIVIAL(info) << "Modulation: qpsk";
- } else if (boost::iequals(system_modulation, "fsk4")) {
- qpsk_mod = false;
- BOOST_LOG_TRIVIAL(info) << "Modulation: fsk4";
+ bool qpsk_mod = true;
+ double digital_levels = node.second.get<double>("digitalLevels", 1.0);
+ double analog_levels = node.second.get<double>("analogLevels", 8.0);
+ double squelch_db = node.second.get<double>("squelch", -160);
+ int max_dev = node.second.get<int>("maxDev", 4000);
+ double filter_width = node.second.get<double>("filterWidth", 1.0);
+ bool conversation_mode = node.second.get<bool>("conversationMode", true);
+ boost::optional<std::string> mod_exists = node.second.get_optional<std::string>("modulation");
+
+ if (mod_exists) {
+ system_modulation = node.second.get<std::string>("modulation");
+
+ if (boost::iequals(system_modulation, "qpsk")) {
+ qpsk_mod = true;
+ BOOST_LOG_TRIVIAL(info) << "Modulation: qpsk";
+ } else if (boost::iequals(system_modulation, "fsk4")) {
+ qpsk_mod = false;
+ BOOST_LOG_TRIVIAL(info) << "Modulation: fsk4";
+ } else {
+ qpsk_mod = true;
+ BOOST_LOG_TRIVIAL(error) << "! System Modulation Not Specified, could be fsk4 or qpsk, assuming qpsk";
+ }
} else {
qpsk_mod = true;
- BOOST_LOG_TRIVIAL(error) << "! System Modulation Not Specified, could be fsk4 or qpsk, assuming qpsk";
}
- } else {
- qpsk_mod = true;
- }
- system->set_squelch_db(squelch_db);
- system->set_analog_levels(analog_levels);
- system->set_digital_levels(digital_levels);
- system->set_qpsk_mod(qpsk_mod);
- system->set_max_dev(max_dev);
- system->set_filter_width(filter_width);
- system->set_conversation_mode(conversation_mode);
- BOOST_LOG_TRIVIAL(info) << "Conversation Mode: " << conversation_mode;
- BOOST_LOG_TRIVIAL(info) << "Analog Recorder Maximum Deviation: " << node.second.get<int>("maxDev", 4000);
- BOOST_LOG_TRIVIAL(info) << "Filter Width: " << filter_width;
- BOOST_LOG_TRIVIAL(info) << "Squelch: " << node.second.get<double>("squelch", -160);
- system->set_api_key(node.second.get<std::string>("apiKey", ""));
- BOOST_LOG_TRIVIAL(info) << "API Key: " << system->get_api_key();
- system->set_bcfy_api_key(node.second.get<std::string>("broadcastifyApiKey", ""));
- BOOST_LOG_TRIVIAL(info) << "Broadcastify API Key: " << system->get_bcfy_api_key();
- system->set_bcfy_system_id(node.second.get<int>("broadcastifySystemId", 0));
- BOOST_LOG_TRIVIAL(info) << "Broadcastify Calls System ID: " << system->get_bcfy_system_id();
- system->set_upload_script(node.second.get<std::string>("uploadScript", ""));
- BOOST_LOG_TRIVIAL(info) << "Upload Script: " << system->get_upload_script();
- system->set_compress_wav(node.second.get<bool>("compressWav", true));
- BOOST_LOG_TRIVIAL(info) << "Compress .wav Files: " << system->get_compress_wav();
- system->set_call_log(node.second.get<bool>("callLog", true));
- BOOST_LOG_TRIVIAL(info) << "Call Log: " << system->get_call_log();
- system->set_audio_archive(node.second.get<bool>("audioArchive", true));
- BOOST_LOG_TRIVIAL(info) << "Audio Archive: " << system->get_audio_archive();
- system->set_transmission_archive(node.second.get<bool>("transmissionArchive", false));
- BOOST_LOG_TRIVIAL(info) << "Transmission Archive: " << system->get_transmission_archive();
- system->set_unit_tags_file(node.second.get<std::string>("unitTagsFile", ""));
- BOOST_LOG_TRIVIAL(info) << "Unit Tags File: " << system->get_unit_tags_file();
- system->set_record_unknown(node.second.get<bool>("recordUnknown", true));
- BOOST_LOG_TRIVIAL(info) << "Record Unknown Talkgroups: " << system->get_record_unknown();
- system->set_mdc_enabled(node.second.get<bool>("decodeMDC", false));
- BOOST_LOG_TRIVIAL(info) << "Decode MDC: " << system->get_mdc_enabled();
- system->set_fsync_enabled(node.second.get<bool>("decodeFSync", false));
- BOOST_LOG_TRIVIAL(info) << "Decode FSync: " << system->get_fsync_enabled();
- system->set_star_enabled(node.second.get<bool>("decodeStar", false));
- BOOST_LOG_TRIVIAL(info) << "Decode Star: " << system->get_star_enabled();
- system->set_tps_enabled(node.second.get<bool>("decodeTPS", false));
- BOOST_LOG_TRIVIAL(info) << "Decode TPS: " << system->get_tps_enabled();
- std::string talkgroup_display_format_string = node.second.get<std::string>("talkgroupDisplayFormat", "Id");
- if (boost::iequals(talkgroup_display_format_string, "id_tag")) {
- system->set_talkgroup_display_format(talkGroupDisplayFormat_id_tag);
- } else if (boost::iequals(talkgroup_display_format_string, "tag_id")) {
- system->set_talkgroup_display_format(talkGroupDisplayFormat_tag_id);
- } else {
- system->set_talkgroup_display_format(talkGroupDisplayFormat_id);
- }
- BOOST_LOG_TRIVIAL(info) << "Talkgroup Display Format: " << talkgroup_display_format_string;
+ system->set_squelch_db(squelch_db);
+ system->set_analog_levels(analog_levels);
+ system->set_digital_levels(digital_levels);
+ system->set_qpsk_mod(qpsk_mod);
+ system->set_max_dev(max_dev);
+ system->set_filter_width(filter_width);
+ system->set_conversation_mode(conversation_mode);
+ BOOST_LOG_TRIVIAL(info) << "Conversation Mode: " << conversation_mode;
+ BOOST_LOG_TRIVIAL(info) << "Analog Recorder Maximum Deviation: " << node.second.get<int>("maxDev", 4000);
+ BOOST_LOG_TRIVIAL(info) << "Filter Width: " << filter_width;
+ BOOST_LOG_TRIVIAL(info) << "Squelch: " << node.second.get<double>("squelch", -160);
+ system->set_api_key(node.second.get<std::string>("apiKey", ""));
+ BOOST_LOG_TRIVIAL(info) << "API Key: " << system->get_api_key();
+ system->set_bcfy_api_key(node.second.get<std::string>("broadcastifyApiKey", ""));
+ BOOST_LOG_TRIVIAL(info) << "Broadcastify API Key: " << system->get_bcfy_api_key();
+ system->set_bcfy_system_id(node.second.get<int>("broadcastifySystemId", 0));
+ BOOST_LOG_TRIVIAL(info) << "Broadcastify Calls System ID: " << system->get_bcfy_system_id();
+ system->set_upload_script(node.second.get<std::string>("uploadScript", ""));
+ BOOST_LOG_TRIVIAL(info) << "Upload Script: " << system->get_upload_script();
+ system->set_compress_wav(node.second.get<bool>("compressWav", true));
+ BOOST_LOG_TRIVIAL(info) << "Compress .wav Files: " << system->get_compress_wav();
+ system->set_call_log(node.second.get<bool>("callLog", true));
+ BOOST_LOG_TRIVIAL(info) << "Call Log: " << system->get_call_log();
+ system->set_audio_archive(node.second.get<bool>("audioArchive", true));
+ BOOST_LOG_TRIVIAL(info) << "Audio Archive: " << system->get_audio_archive();
+ system->set_transmission_archive(node.second.get<bool>("transmissionArchive", false));
+ BOOST_LOG_TRIVIAL(info) << "Transmission Archive: " << system->get_transmission_archive();
+ system->set_unit_tags_file(node.second.get<std::string>("unitTagsFile", ""));
+ BOOST_LOG_TRIVIAL(info) << "Unit Tags File: " << system->get_unit_tags_file();
+ system->set_record_unknown(node.second.get<bool>("recordUnknown", true));
+ BOOST_LOG_TRIVIAL(info) << "Record Unknown Talkgroups: " << system->get_record_unknown();
+ system->set_mdc_enabled(node.second.get<bool>("decodeMDC", false));
+ BOOST_LOG_TRIVIAL(info) << "Decode MDC: " << system->get_mdc_enabled();
+ system->set_fsync_enabled(node.second.get<bool>("decodeFSync", false));
+ BOOST_LOG_TRIVIAL(info) << "Decode FSync: " << system->get_fsync_enabled();
+ system->set_star_enabled(node.second.get<bool>("decodeStar", false));
+ BOOST_LOG_TRIVIAL(info) << "Decode Star: " << system->get_star_enabled();
+ system->set_tps_enabled(node.second.get<bool>("decodeTPS", false));
+ BOOST_LOG_TRIVIAL(info) << "Decode TPS: " << system->get_tps_enabled();
+ std::string talkgroup_display_format_string = node.second.get<std::string>("talkgroupDisplayFormat", "Id");
+ if (boost::iequals(talkgroup_display_format_string, "id_tag")) {
+ system->set_talkgroup_display_format(talkGroupDisplayFormat_id_tag);
+ } else if (boost::iequals(talkgroup_display_format_string, "tag_id")) {
+ system->set_talkgroup_display_format(talkGroupDisplayFormat_tag_id);
+ } else {
+ system->set_talkgroup_display_format(talkGroupDisplayFormat_id);
+ }
+ BOOST_LOG_TRIVIAL(info) << "Talkgroup Display Format: " << talkgroup_display_format_string;
+
+ sys_id = node.second.get<unsigned long>("sysId", 0);
+ nac = node.second.get<unsigned long>("nac", 0);
+ wacn = node.second.get<unsigned long>("wacn", 0);
+ system->set_xor_mask(sys_id, wacn, nac);
+ system->set_bandplan(node.second.get<std::string>("bandplan", "800_standard"));
+ system->set_bandfreq(800); // Default to 800
+
+ if (boost::starts_with(system->get_bandplan(), "400")) {
+ system->set_bandfreq(400);
- sys_id = node.second.get<unsigned long>("sysId", 0);
- nac = node.second.get<unsigned long>("nac", 0);
- wacn = node.second.get<unsigned long>("wacn", 0);
- system->set_xor_mask(sys_id, wacn, nac);
- system->set_bandplan(node.second.get<std::string>("bandplan", "800_standard"));
- system->set_bandfreq(800); // Default to 800
+ }
+ system->set_bandplan_base(node.second.get<double>("bandplanBase", 0.0));
+ system->set_bandplan_high(node.second.get<double>("bandplanHigh", 0.0));
+ system->set_bandplan_spacing(node.second.get<double>("bandplanSpacing", 0.0));
+ system->set_bandplan_offset(node.second.get<int>("bandplanOffset", 0));
- if (boost::starts_with(system->get_bandplan(), "400")) {
- system->set_bandfreq(400);
- }
- system->set_bandplan_base(node.second.get<double>("bandplanBase", 0.0));
- system->set_bandplan_high(node.second.get<double>("bandplanHigh", 0.0));
- system->set_bandplan_spacing(node.second.get<double>("bandplanSpacing", 0.0));
- system->set_bandplan_offset(node.second.get<int>("bandplanOffset", 0));
-
- if (system->get_system_type() == "smartnet") {
- BOOST_LOG_TRIVIAL(info) << "Smartnet bandplan: " << system->get_bandplan();
- BOOST_LOG_TRIVIAL(info) << "Smartnet band: " << system->get_bandfreq();
-
- if (system->get_bandplan_base() || system->get_bandplan_spacing() || system->get_bandplan_offset()) {
- BOOST_LOG_TRIVIAL(info) << "Smartnet bandplan base freq: " << system->get_bandplan_base();
- BOOST_LOG_TRIVIAL(info) << "Smartnet bandplan high freq: " << system->get_bandplan_high();
- BOOST_LOG_TRIVIAL(info) << "Smartnet bandplan spacing: " << system->get_bandplan_spacing();
- BOOST_LOG_TRIVIAL(info) << "Smartnet bandplan offset: " << system->get_bandplan_offset();
+ if (system->get_system_type() == "smartnet") {
+ BOOST_LOG_TRIVIAL(info) << "Smartnet bandplan: " << system->get_bandplan();
+ BOOST_LOG_TRIVIAL(info) << "Smartnet band: " << system->get_bandfreq();
+
+ if (system->get_bandplan_base() || system->get_bandplan_spacing() || system->get_bandplan_offset()) {
+ BOOST_LOG_TRIVIAL(info) << "Smartnet bandplan base freq: " << system->get_bandplan_base();
+ BOOST_LOG_TRIVIAL(info) << "Smartnet bandplan high freq: " << system->get_bandplan_high();
+ BOOST_LOG_TRIVIAL(info) << "Smartnet bandplan spacing: " << system->get_bandplan_spacing();
+ BOOST_LOG_TRIVIAL(info) << "Smartnet bandplan offset: " << system->get_bandplan_offset();
+ }
}
- }
- system->set_hideEncrypted(node.second.get<bool>("hideEncrypted", system->get_hideEncrypted()));
- BOOST_LOG_TRIVIAL(info) << "Hide Encrypted Talkgroups: " << system->get_hideEncrypted();
- system->set_hideUnknown(node.second.get<bool>("hideUnknownTalkgroups", system->get_hideUnknown()));
- BOOST_LOG_TRIVIAL(info) << "Hide Unknown Talkgroups: " << system->get_hideUnknown();
- system->set_min_duration(node.second.get<double>("minDuration", 0));
- BOOST_LOG_TRIVIAL(info) << "Minimum Call Duration (in seconds): " << system->get_min_duration();
- system->set_max_duration(node.second.get<double>("maxDuration", 0));
- BOOST_LOG_TRIVIAL(info) << "Maximum Call Duration (in seconds): " << system->get_max_duration();
- system->set_min_tx_duration(node.second.get<double>("minTransmissionDuration", 0));
- BOOST_LOG_TRIVIAL(info) << "Minimum Transmission Duration (in seconds): " << system->get_min_tx_duration();
-
- system->set_multiSite(node.second.get<bool>("multiSite", false));
- BOOST_LOG_TRIVIAL(info) << "Multiple Site System: " << system->get_multiSite();
- system->set_multiSiteSystemName(node.second.get<std::string>("multiSiteSystemName", ""));
- BOOST_LOG_TRIVIAL(info) << "Multiple Site System Name: " << system->get_multiSiteSystemName();
-
- if (!system->get_compress_wav()) {
- if ((system->get_api_key().length() > 0) || (system->get_bcfy_api_key().length() > 0)) {
- BOOST_LOG_TRIVIAL(error) << "Compress WAV must be set to true if you are using OpenMHz or Broadcastify";
- return false;
+ system->set_hideEncrypted(node.second.get<bool>("hideEncrypted", system->get_hideEncrypted()));
+ BOOST_LOG_TRIVIAL(info) << "Hide Encrypted Talkgroups: " << system->get_hideEncrypted();
+ system->set_hideUnknown(node.second.get<bool>("hideUnknownTalkgroups", system->get_hideUnknown()));
+ BOOST_LOG_TRIVIAL(info) << "Hide Unknown Talkgroups: " << system->get_hideUnknown();
+ system->set_min_duration(node.second.get<double>("minDuration", 0));
+ BOOST_LOG_TRIVIAL(info) << "Minimum Call Duration (in seconds): " << system->get_min_duration();
+ system->set_max_duration(node.second.get<double>("maxDuration", 0));
+ BOOST_LOG_TRIVIAL(info) << "Maximum Call Duration (in seconds): " << system->get_max_duration();
+ system->set_min_tx_duration(node.second.get<double>("minTransmissionDuration", 0));
+ BOOST_LOG_TRIVIAL(info) << "Minimum Transmission Duration (in seconds): " << system->get_min_tx_duration();
+ system->set_multiSite(node.second.get<bool>("multiSite", false));
+ BOOST_LOG_TRIVIAL(info) << "Multiple Site System: " << system->get_multiSite();
+ system->set_multiSiteSystemName(node.second.get<std::string>("multiSiteSystemName", ""));
+ BOOST_LOG_TRIVIAL(info) << "Multiple Site System Name: " << system->get_multiSiteSystemName();
+
+ if (!system->get_compress_wav()) {
+ if ((system->get_api_key().length() > 0) || (system->get_bcfy_api_key().length() > 0)) {
+ BOOST_LOG_TRIVIAL(error) << "Compress WAV must be set to true if you are using OpenMHz or Broadcastify";
+ return false;
+ }
}
- }
- systems.push_back(system);
- BOOST_LOG_TRIVIAL(info);
+ systems.push_back(system);
+ BOOST_LOG_TRIVIAL(info);
+ }
}
BOOST_LOG_TRIVIAL(info) << "\n\n-------------------------------------\nSOURCES\n-------------------------------------\n";
BOOST_FOREACH (boost::property_tree::ptree::value_type &node,
pt.get_child("sources")) {
+ bool source_enabled = node.second.get<bool>("enabled", true);
+ if (source_enabled) {
+ bool gain_set = false;
+ int silence_frames = node.second.get<int>("silenceFrames", 0);
+ double center = node.second.get<double>("center", 0);
+ double rate = node.second.get<double>("rate", 0);
+ double error = node.second.get<double>("error", 0);
+ double ppm = node.second.get<double>("ppm", 0);
+ bool agc = node.second.get<bool>("agc", false);
+ int gain = node.second.get<double>("gain", 0);
+ int if_gain = node.second.get<double>("ifGain", 0);
+ int bb_gain = node.second.get<double>("bbGain", 0);
+ int mix_gain = node.second.get<double>("mixGain", 0);
+ int lna_gain = node.second.get<double>("lnaGain", 0);
+ int pga_gain = node.second.get<double>("pgaGain", 0);
+ int tia_gain = node.second.get<double>("tiaGain", 0);
+ int amp_gain = node.second.get<double>("ampGain", 0);
+ int vga_gain = node.second.get<double>("vgaGain", 0);
+ int vga1_gain = node.second.get<double>("vga1Gain", 0);
+ int vga2_gain = node.second.get<double>("vga2Gain", 0);
+
+ std::string antenna = node.second.get<string>("antenna", "");
+ int digital_recorders = node.second.get<int>("digitalRecorders", 0);
+ int sigmf_recorders = node.second.get<int>("sigmfRecorders", 0);
+ int analog_recorders = node.second.get<int>("analogRecorders", 0);
+
+ std::string driver = node.second.get<std::string>("driver", "");
+
+ if ((driver != "osmosdr") && (driver != "usrp")) {
+ BOOST_LOG_TRIVIAL(error) << "Driver specified in config.json not recognized, needs to be osmosdr or usrp";
+ }
- bool gain_set = false;
- int silence_frames = node.second.get<int>("silenceFrames", 0);
- double center = node.second.get<double>("center", 0);
- double rate = node.second.get<double>("rate", 0);
- double error = node.second.get<double>("error", 0);
- double ppm = node.second.get<double>("ppm", 0);
- bool agc = node.second.get<bool>("agc", false);
- int gain = node.second.get<double>("gain", 0);
- int if_gain = node.second.get<double>("ifGain", 0);
- int bb_gain = node.second.get<double>("bbGain", 0);
- int mix_gain = node.second.get<double>("mixGain", 0);
- int lna_gain = node.second.get<double>("lnaGain", 0);
- int pga_gain = node.second.get<double>("pgaGain", 0);
- int tia_gain = node.second.get<double>("tiaGain", 0);
- int amp_gain = node.second.get<double>("ampGain", 0);
- int vga_gain = node.second.get<double>("vgaGain", 0);
- int vga1_gain = node.second.get<double>("vga1Gain", 0);
- int vga2_gain = node.second.get<double>("vga2Gain", 0);
-
- std::string antenna = node.second.get<string>("antenna", "");
- int digital_recorders = node.second.get<int>("digitalRecorders", 0);
- int sigmf_recorders = node.second.get<int>("sigmfRecorders", 0);
- int analog_recorders = node.second.get<int>("analogRecorders", 0);
-
- std::string driver = node.second.get<std::string>("driver", "");
-
- if ((driver != "osmosdr") && (driver != "usrp")) {
- BOOST_LOG_TRIVIAL(error) << "Driver specified in config.json not recognized, needs to be osmosdr or usrp";
- }
+ std::string device = node.second.get<std::string>("device", "");
+ BOOST_LOG_TRIVIAL(info) << "Driver: " << node.second.get<std::string>("driver", "");
+ BOOST_LOG_TRIVIAL(info) << "Center: " << format_freq(node.second.get<double>("center", 0));
+ BOOST_LOG_TRIVIAL(info) << "Rate: " << FormatSamplingRate(node.second.get<double>("rate", 0));
+ BOOST_LOG_TRIVIAL(info) << "Error: " << node.second.get<double>("error", 0);
+ BOOST_LOG_TRIVIAL(info) << "PPM Error: " << node.second.get<double>("ppm", 0);
+ BOOST_LOG_TRIVIAL(info) << "Auto gain control: " << node.second.get<bool>("agc", false);
+ BOOST_LOG_TRIVIAL(info) << "Gain: " << node.second.get<double>("gain", 0);
+ BOOST_LOG_TRIVIAL(info) << "IF Gain: " << node.second.get<double>("ifGain", 0);
+ BOOST_LOG_TRIVIAL(info) << "BB Gain: " << node.second.get<double>("bbGain", 0);
+ BOOST_LOG_TRIVIAL(info) << "LNA Gain: " << node.second.get<double>("lnaGain", 0);
+ BOOST_LOG_TRIVIAL(info) << "PGA Gain: " << node.second.get<double>("pgaGain", 0);
+ BOOST_LOG_TRIVIAL(info) << "TIA Gain: " << node.second.get<double>("tiaGain", 0);
+ BOOST_LOG_TRIVIAL(info) << "MIX Gain: " << node.second.get<double>("mixGain", 0);
+ BOOST_LOG_TRIVIAL(info) << "AMP Gain: " << node.second.get<double>("ampGain", 0);
+ BOOST_LOG_TRIVIAL(info) << "VGA Gain: " << node.second.get<double>("vgaGain", 0);
+ BOOST_LOG_TRIVIAL(info) << "VGA1 Gain: " << node.second.get<double>("vga1Gain", 0);
+ BOOST_LOG_TRIVIAL(info) << "VGA2 Gain: " << node.second.get<double>("vga2Gain", 0);
+ BOOST_LOG_TRIVIAL(info) << "Idle Silence: " << node.second.get<bool>("silenceFrame", 0);
+ BOOST_LOG_TRIVIAL(info) << "Digital Recorders: " << node.second.get<int>("digitalRecorders", 0);
+ BOOST_LOG_TRIVIAL(info) << "SigMF Recorders: " << node.second.get<int>("sigmfRecorders", 0);
+ BOOST_LOG_TRIVIAL(info) << "Analog Recorders: " << node.second.get<int>("analogRecorders", 0);
+
+ if ((ppm != 0) && (error != 0)) {
+ BOOST_LOG_TRIVIAL(info) << "Both PPM and Error should not be set at the same time. Setting Error to 0.";
+ error = 0;
+ }
- std::string device = node.second.get<std::string>("device", "");
- BOOST_LOG_TRIVIAL(info) << "Driver: " << node.second.get<std::string>("driver", "");
- BOOST_LOG_TRIVIAL(info) << "Center: " << format_freq(node.second.get<double>("center", 0));
- BOOST_LOG_TRIVIAL(info) << "Rate: " << FormatSamplingRate(node.second.get<double>("rate", 0));
- BOOST_LOG_TRIVIAL(info) << "Error: " << node.second.get<double>("error", 0);
- BOOST_LOG_TRIVIAL(info) << "PPM Error: " << node.second.get<double>("ppm", 0);
- BOOST_LOG_TRIVIAL(info) << "Auto gain control: " << node.second.get<bool>("agc", false);
- BOOST_LOG_TRIVIAL(info) << "Gain: " << node.second.get<double>("gain", 0);
- BOOST_LOG_TRIVIAL(info) << "IF Gain: " << node.second.get<double>("ifGain", 0);
- BOOST_LOG_TRIVIAL(info) << "BB Gain: " << node.second.get<double>("bbGain", 0);
- BOOST_LOG_TRIVIAL(info) << "LNA Gain: " << node.second.get<double>("lnaGain", 0);
- BOOST_LOG_TRIVIAL(info) << "PGA Gain: " << node.second.get<double>("pgaGain", 0);
- BOOST_LOG_TRIVIAL(info) << "TIA Gain: " << node.second.get<double>("tiaGain", 0);
- BOOST_LOG_TRIVIAL(info) << "MIX Gain: " << node.second.get<double>("mixGain", 0);
- BOOST_LOG_TRIVIAL(info) << "AMP Gain: " << node.second.get<double>("ampGain", 0);
- BOOST_LOG_TRIVIAL(info) << "VGA Gain: " << node.second.get<double>("vgaGain", 0);
- BOOST_LOG_TRIVIAL(info) << "VGA1 Gain: " << node.second.get<double>("vga1Gain", 0);
- BOOST_LOG_TRIVIAL(info) << "VGA2 Gain: " << node.second.get<double>("vga2Gain", 0);
- BOOST_LOG_TRIVIAL(info) << "Idle Silence: " << node.second.get<bool>("silenceFrame", 0);
- BOOST_LOG_TRIVIAL(info) << "Digital Recorders: " << node.second.get<int>("digitalRecorders", 0);
- BOOST_LOG_TRIVIAL(info) << "SigMF Recorders: " << node.second.get<int>("sigmfRecorders", 0);
- BOOST_LOG_TRIVIAL(info) << "Analog Recorders: " << node.second.get<int>("analogRecorders", 0);
-
- if ((ppm != 0) && (error != 0)) {
- BOOST_LOG_TRIVIAL(info) << "Both PPM and Error should not be set at the same time. Setting Error to 0.";
- error = 0;
- }
+ Source *source = new Source(center, rate, error, driver, device, &config);
+ BOOST_LOG_TRIVIAL(info) << "Max Frequency: " << format_freq(source->get_max_hz());
+ BOOST_LOG_TRIVIAL(info) << "Min Frequency: " << format_freq(source->get_min_hz());
+ if (node.second.count("gainSettings") != 0) {
+ BOOST_FOREACH (boost::property_tree::ptree::value_type &sub_node, node.second.get_child("gainSettings")) {
+ source->set_gain_by_name(sub_node.first, sub_node.second.get<double>("", 0));
+ gain_set = true;
+ }
+ }
- Source *source = new Source(center, rate, error, driver, device, &config);
- BOOST_LOG_TRIVIAL(info) << "Max Frequency: " << format_freq(source->get_max_hz());
- BOOST_LOG_TRIVIAL(info) << "Min Frequency: " << format_freq(source->get_min_hz());
- if (node.second.count("gainSettings") != 0) {
- BOOST_FOREACH (boost::property_tree::ptree::value_type &sub_node, node.second.get_child("gainSettings")) {
- source->set_gain_by_name(sub_node.first, sub_node.second.get<double>("", 0));
+ if (if_gain != 0) {
gain_set = true;
+ source->set_gain_by_name("IF", if_gain);
}
- }
- if (if_gain != 0) {
- gain_set = true;
- source->set_gain_by_name("IF", if_gain);
- }
+ if (bb_gain != 0) {
+ gain_set = true;
+ source->set_gain_by_name("BB", bb_gain);
+ }
- if (bb_gain != 0) {
- gain_set = true;
- source->set_gain_by_name("BB", bb_gain);
- }
+ if (mix_gain != 0) {
+ gain_set = true;
+ source->set_gain_by_name("MIX", mix_gain);
+ }
- if (mix_gain != 0) {
- gain_set = true;
- source->set_gain_by_name("MIX", mix_gain);
- }
+ if (lna_gain != 0) {
+ gain_set = true;
+ source->set_gain_by_name("LNA", lna_gain);
+ }
- if (lna_gain != 0) {
- gain_set = true;
- source->set_gain_by_name("LNA", lna_gain);
- }
+ if (tia_gain != 0) {
+ gain_set = true;
+ source->set_gain_by_name("TIA", tia_gain);
+ }
- if (tia_gain != 0) {
- gain_set = true;
- source->set_gain_by_name("TIA", tia_gain);
- }
+ if (pga_gain != 0) {
+ gain_set = true;
+ source->set_gain_by_name("PGA", pga_gain);
+ }
- if (pga_gain != 0) {
- gain_set = true;
- source->set_gain_by_name("PGA", pga_gain);
- }
+ if (amp_gain != 0) {
+ gain_set = true;
+ source->set_gain_by_name("AMP", amp_gain);
+ }
- if (amp_gain != 0) {
- gain_set = true;
- source->set_gain_by_name("AMP", amp_gain);
- }
+ if (vga_gain != 0) {
+ gain_set = true;
+ source->set_gain_by_name("VGA", vga_gain);
+ }
- if (vga_gain != 0) {
- gain_set = true;
- source->set_gain_by_name("VGA", vga_gain);
- }
+ if (vga1_gain != 0) {
+ gain_set = true;
+ source->set_gain_by_name("VGA1", vga1_gain);
+ }
- if (vga1_gain != 0) {
- gain_set = true;
- source->set_gain_by_name("VGA1", vga1_gain);
- }
+ if (vga2_gain != 0) {
+ gain_set = true;
+ source->set_gain_by_name("VGA2", vga2_gain);
+ }
- if (vga2_gain != 0) {
- gain_set = true;
- source->set_gain_by_name("VGA2", vga2_gain);
- }
+ if (gain != 0) {
+ gain_set = true;
+ source->set_gain(gain);
+ }
- if (gain != 0) {
- gain_set = true;
- source->set_gain(gain);
- }
+ if (!gain_set) {
+ BOOST_LOG_TRIVIAL(error) << "! No Gain was specified! Things will probably not work";
+ }
- if (!gain_set) {
- BOOST_LOG_TRIVIAL(error) << "! No Gain was specified! Things will probably not work";
- }
+ source->set_gain_mode(agc);
+ source->set_antenna(antenna);
+ source->set_silence_frames(silence_frames);
- source->set_gain_mode(agc);
- source->set_antenna(antenna);
- source->set_silence_frames(silence_frames);
+ if (ppm != 0) {
+ source->set_freq_corr(ppm);
+ }
+ source->create_digital_recorders(tb, digital_recorders);
+ source->create_analog_recorders(tb, analog_recorders);
+ source->create_sigmf_recorders(tb, sigmf_recorders);
+ if (config.debug_recorder) {
+ source->create_debug_recorder(tb, source_count);
+ }
- if (ppm != 0) {
- source->set_freq_corr(ppm);
+ sources.push_back(source);
+ source_count++;
+ BOOST_LOG_TRIVIAL(info) << "\n-------------------------------------\n\n";
}
- source->create_digital_recorders(tb, digital_recorders);
- source->create_analog_recorders(tb, analog_recorders);
- source->create_sigmf_recorders(tb, sigmf_recorders);
- if (config.debug_recorder) {
- source->create_debug_recorder(tb, source_count);
- }
-
- sources.push_back(source);
- source_count++;
- BOOST_LOG_TRIVIAL(info) << "\n-------------------------------------\n\n";
}
BOOST_LOG_TRIVIAL(info) << "\n\n-------------------------------------\nPLUGINS\n-------------------------------------\n";
@@ -1677,7 +1689,7 @@ int main(int argc, char **argv) {
// std::locale::global(std::locale("C"));
boost::program_options::options_description desc("Options");
- desc.add_options()("help,h", "Help screen")("config", boost::program_options::value<string>()->default_value("./config.json"), "Config File")("version", "Version Informaiotn");
+ desc.add_options()("help,h", "Help screen")("config,c", boost::program_options::value<string>()->default_value("./config.json"), "Config File")("version,v", "Version Information");
boost::program_options::variables_map vm;
boost::program_options::store(parse_command_line(argc, argv, desc), vm);
@@ -1689,7 +1701,7 @@ int main(int argc, char **argv) {
}
if (vm.count("help")) {
- std::cout << "Usage: options_description [options]\n";
+ std::cout << "Usage: trunk-recorder [options]\n";
std::cout << desc;
exit(0);
}
diff --git a/trunk-recorder/plugin_manager/plugin_manager.cc b/trunk-recorder/plugin_manager/plugin_manager.cc
index 1d77d19a..c1643807 100644
--- a/trunk-recorder/plugin_manager/plugin_manager.cc
+++ b/trunk-recorder/plugin_manager/plugin_manager.cc
@@ -41,9 +41,11 @@ void initialize_plugins(boost::property_tree::ptree &cfg, Config *config, std::v
BOOST_FOREACH (boost::property_tree::ptree::value_type &node, cfg.get_child("plugins")) {
std::string plugin_lib = node.second.get<std::string>("library", "");
std::string plugin_name = node.second.get<std::string>("name", "");
-
- Plugin *plugin = setup_plugin(plugin_lib, plugin_name);
- plugin->api->parse_config(node.second);
+ bool plugin_enabled = node.second.get<bool>("enabled", true);
+ if (plugin_enabled) {
+ Plugin *plugin = setup_plugin(plugin_lib, plugin_name);
+ plugin->api->parse_config(node.second);
+ }
}
if (plugins.size() == 1) {
diff --git a/trunk-recorder/source.cc b/trunk-recorder/source.cc
index cf37d0fe..ecf6a03e 100644
--- a/trunk-recorder/source.cc
+++ b/trunk-recorder/source.cc
@@ -485,6 +485,7 @@ Source::Source(double c, double r, double e, std::string drv, std::string dev, C
BOOST_LOG_TRIVIAL(info) << "Setting sample rate to: " << FormatSamplingRate(rate);
osmo_src->set_sample_rate(rate);
actual_rate = osmo_src->get_sample_rate();
+ rate = round(actual_rate);
BOOST_LOG_TRIVIAL(info) << "Actual sample rate: " << FormatSamplingRate(actual_rate);
BOOST_LOG_TRIVIAL(info) << "Tuning to " << format_freq(center + error);
osmo_src->set_center_freq(center + error, 0);
diff --git a/trunk-recorder/systems/system.h b/trunk-recorder/systems/system.h
index 6d37e389..117bd093 100644
--- a/trunk-recorder/systems/system.h
+++ b/trunk-recorder/systems/system.h
@@ -108,7 +108,7 @@ public:
virtual void set_source(Source *) = 0;
virtual Talkgroup *find_talkgroup(long tg) = 0;
virtual Talkgroup *find_talkgroup_by_freq(double freq) = 0;
- virtual UnitTag *find_unit_tag(long unitID) = 0;
+ virtual std::string find_unit_tag(long unitID) = 0;
virtual void set_talkgroups_file(std::string) = 0;
virtual void set_channel_file(std::string channel_file) = 0;
virtual bool has_channel_file() = 0;
diff --git a/trunk-recorder/systems/system_impl.cc b/trunk-recorder/systems/system_impl.cc
index 6b09e32b..b6488fa2 100644
--- a/trunk-recorder/systems/system_impl.cc
+++ b/trunk-recorder/systems/system_impl.cc
@@ -306,7 +306,7 @@ Talkgroup *System_impl::find_talkgroup(long tg_number) {
Talkgroup *System_impl::find_talkgroup_by_freq(double freq) {
return talkgroups->find_talkgroup_by_freq(sys_num, freq);
}
-UnitTag *System_impl::find_unit_tag(long unitID) {
+std::string System_impl::find_unit_tag(long unitID) {
return unit_tags->find_unit_tag(unitID);
}
diff --git a/trunk-recorder/systems/system_impl.h b/trunk-recorder/systems/system_impl.h
index 60be03e0..216f1842 100644
--- a/trunk-recorder/systems/system_impl.h
+++ b/trunk-recorder/systems/system_impl.h
@@ -166,7 +166,7 @@ public:
void set_source(Source *);
Talkgroup *find_talkgroup(long tg);
Talkgroup *find_talkgroup_by_freq(double freq);
- UnitTag *find_unit_tag(long unitID);
+ std::string find_unit_tag(long unitID);
void set_talkgroups_file(std::string);
void set_channel_file(std::string channel_file);
bool has_channel_file();
diff --git a/trunk-recorder/unit_tag.cc b/trunk-recorder/unit_tag.cc
index d39908b7..182a3781 100644
--- a/trunk-recorder/unit_tag.cc
+++ b/trunk-recorder/unit_tag.cc
@@ -1,6 +1,7 @@
#include "unit_tag.h"
+#include <boost/regex.hpp>
-UnitTag::UnitTag(long num, std::string t) {
- number = num;
+UnitTag::UnitTag(std::string p, std::string t) {
+ pattern = p;
tag = t;
}
diff --git a/trunk-recorder/unit_tag.h b/trunk-recorder/unit_tag.h
index d888f805..6850dd79 100644
--- a/trunk-recorder/unit_tag.h
+++ b/trunk-recorder/unit_tag.h
@@ -4,14 +4,14 @@
#include <iostream>
#include <stdio.h>
#include <string>
-//#include <sstream>
+#include <boost/regex.hpp>
class UnitTag {
public:
- long number;
+ boost::regex pattern;
std::string tag;
- UnitTag(long num, std::string t);
+ UnitTag(std::string p, std::string t);
};
#endif // UNIT_TAG_H
diff --git a/trunk-recorder/unit_tags.cc b/trunk-recorder/unit_tags.cc
index e8455d8c..b3ebda70 100644
--- a/trunk-recorder/unit_tags.cc
+++ b/trunk-recorder/unit_tags.cc
@@ -5,6 +5,7 @@
#include <boost/intrusive_ptr.hpp>
#include <boost/log/trivial.hpp>
#include <boost/tokenizer.hpp>
+#include <boost/regex.hpp>
#include "csv_helper.h"
#include <cstdio>
@@ -60,7 +61,7 @@ void UnitTags::load_unit_tags(std::string filename) {
continue;
}
- add(atoi(vec[0].c_str()), vec[1].c_str());
+ add(vec[0].c_str(), vec[1].c_str());
lines_pushed++;
}
@@ -75,21 +76,31 @@ void UnitTags::load_unit_tags(std::string filename) {
}
}
-UnitTag *UnitTags::find_unit_tag(long tg_number) {
- UnitTag *tg_match = NULL;
+std::string UnitTags::find_unit_tag(long tg_number) {
+ std::string tg_num_str = std::to_string(tg_number);
+ std::string tag = "";
for (std::vector<UnitTag *>::iterator it = unit_tags.begin(); it != unit_tags.end(); ++it) {
UnitTag *tg = (UnitTag *)*it;
- if (tg->number == tg_number) {
- tg_match = tg;
+ if (regex_match(tg_num_str, tg->pattern)) {
+ tag = regex_replace(tg_num_str, tg->pattern, tg->tag, boost::regex_constants::format_no_copy);
break;
}
}
- return tg_match;
+
+ return tag;
}
-void UnitTags::add(long num, std::string tag) {
- UnitTag *unit_tag = new UnitTag(num, tag);
+void UnitTags::add(std::string pattern, std::string tag) {
+ // If the pattern is like /someregex/
+ if (pattern.substr(0, 1).compare("/") == 0 && pattern.substr(pattern.length()-1, 1).compare("/") == 0) {
+ // then remove the / at the beginning and end
+ pattern = pattern.substr(1, pattern.length()-2);
+ } else {
+ // otherwise add ^ and $ to the pattern e.g. ^123$ to make a regex for simple IDs
+ pattern = "^" + pattern + "$";
+ }
+ UnitTag *unit_tag = new UnitTag(pattern, tag);
unit_tags.push_back(unit_tag);
}
diff --git a/trunk-recorder/unit_tags.h b/trunk-recorder/unit_tags.h
index a048214b..5f95df28 100644
--- a/trunk-recorder/unit_tags.h
+++ b/trunk-recorder/unit_tags.h
@@ -12,7 +12,7 @@ class UnitTags {
public:
UnitTags();
void load_unit_tags(std::string filename);
- UnitTag *find_unit_tag(long unitID);
- void add(long num, std::string tag);
+ std::string find_unit_tag(long unitID);
+ void add(std::string pattern, std::string tag);
};
#endif // UNIT_TAGS_H