
New features in this release (June, 2021)
=========================================

1. With thanks to OP25 user Triptolemus, the web client is enhanced to
   include comprehensive logs of recent control channel signalling and
   call activity.  Many other features are also added: 
    * unit ID (subscriber ID) tagging - similar to the existing TGID
      tags setup.
    * tag color coding (for both TGID and SUID tags).
    * tag ranges and wildcarding - for both the TGID and SUID tag maps,
      a single definition line may be used to create tags for a range of
      IDs.
    * real time system frequency status table
    * smart colors
    * user settings (colors, preferences) may be edited and saved via a
      convenient set of web forms and applications

2. The multi_rx app adds extensions to include trunked P25 call following 
   concurrent with full-time tracking of one or more P25 control channels.
   If necessary, additional SDR devices may be configured to allow full
   coverage of all control channels without loss of CC data even during voice
   call reception.  Several new command line options to multi_rx have been
   added - -T (trunking TSV file) -l (terminal type) as well as -X and -U,
   all having the same meaning as in rx.py.

3. Control channel logging to SQL database is added.  For details see the
   section on the Flask Datatables App, below.

4. Experimental TDMA Control Channel support

Installation
============

First locate and change to your current OP25 install build/ directory and
run the command
     sude make uninstall

Since this version includes library C++ code updates it requires a full
source rebuild via the standard install script (install.sh).

The installation will include one or more SDR receivers, depending
on the the amount of spectrum utilized by the target trunking system, how
many control channels are to be monitored concurrently, and whether voice
call following is desired.

 * When SQL logging is used, it is most desirable to keep the control channel
   tuned in 100% of the time.  With a single SDR this is not possible when the
   range of control channel and voice channel frequencies exceed the tuning band
   of the SDR.  
 * When voice call following is to be used, a separate voice channel must be
   defined for each device over which voice reception is desired.  It is 
   redundant to have more than one voice channel assigned to a given device.
 * A separate SDR can be dedicated to voice call following if needed.  If there
   is already a frequency-locked ("tunable"=false) device whose tuning band 
   includes all desired voice frequencies, a separate voice SDR is not needed.
 * This version of OP25 follows the same voice call system as in rx.py.
   That is, a single call at a time is monitored and a 3-second (nominal)
   time delay is applied at the end of each call to catch possible replies.
 * A single device may be shared by multiple channels.  When more than one channel
   is assigned to a device, the device should be tuned to a fixed frequency and 
   "tunable" should be set to "false".

Simplified example:  Of all frequencies (control and voice) in the system,
the lowest frequency is 464.05 and the highest is 464.6.  An RTL-SDR having
a maximum sample rate of 2.56 MHz is to be used.  Since the band required is
0.55 MHz, a single SDR configuration can be used.  The sample rate for 
this example, 2.56 MHz, could be reduced to 1.0 MHz to conserve CPU.

NOTE: Proper logging of CC activity requires two things:
      1) Device and/or channel resources must be allocated so that there
         is 100% time coverage of the control channel.  Voice channel
         operation on the same SDR can only occur when the entire system
         fits within the SDR tuning band.
      2) Control channel reception and demodulation must be 100% error-free.
         Occasional errors are potentially corrected by the FEC but a better
         course is to increase the receive SNR and/or decrease the system BER.

Notes on JSON Configuration/Parameters
======================================
Example json config files are included in the apps/ directory.  You
should choose one of these files (as described above) and make edits
to a working copy of the file.  The name of the resulting JSON config
file must be passed to multi_rx.py via the "-c" parameter.
   cfg-trunk.json  - When all system frequencies (CC and VC) will fit
                     within the SDR tuning band (without retuning the SDR),
                     or voice decode is not needed.
   cfg-trunk2.json - When two SDRs are needed to cover both CC and all VCs.
   cfg-trunkx.json - Large system example with voice following and several CCs.

There are several key values to note:
"tunable"	In the single-SDR configuration where all system frequencies
                (primary/secondary CCs and VCs) are within the SDR band,
                you should set this to "false".  In this case the SDR is
                fixed-tuned and remains on a single frequency, the center
                frequency.  You must set the center frequency to a value
                halfway between the lowest and highest frequencies in the
                system, via the device "frequency" setting.
"frequency"     See above.  When "tunable" is set to "true" this value must
                be filled in.  Otherwise the value is used to set the device
                frequency at startup time (must be a valid frequency for the
                device).  The device will most likely be retuned one or more
                times during execution.
"decode"        Assists multi_rx in assigning channels to the proper device(s).
                If the value of "decode" starts with the string "p25_decoder",
                multi_rx uses the p25 decoder instead of its standard decoder.

Note that "tunable" is a device-specific parameter, and that "decode" is a
channel-specific parameter.  Also, while both the device and channel define
the "frequency" parameter, the description above is for device entries.  A
channel entry may also define a frequency, but the channel "frequency" parameter
is ignored (in this version).

When the p25_decoder is used, there is a parameter string consisting of a 
colon-separated list of parameters with each parameter in the form "key=value",
with the parameter string defined as the value of the "decode" parameter.

Here are two examples:
	"decode": "p25_decoder:role=cc:dev=rtl11:nac=0x4e1",   [control]
	"decode": "p25_decoder:role=vc:dev=rtl12_vc",          [voice]
The valid parameter keywords are:
"p25_decoder"   Required for trunked P25.  This keyword introduces the
                parameter list.  There is no value.
"role"          Must be set to "vc" or "cc".
"dev"           Must be set to the name of the device.  Each channel is
                assigned to exactly one device.
"nac"           Comma-separated list of NACs for the channel.  Only trunked
                systems having a NAC in the list can be assigned to this
                channel.
"sysid"         Comma-separated list of SYSIDs for the channel.  Only trunked
                systems having a SYSID in the list can be assigned to this
                channel.

The "nac" and "sysid" options are only checked for control channels ("role=cc").
Values starting with "0x" are hexadecimal; otherwise decimal values are assumed .
A blank/default value for "sysid" and/or "nac" indicates that parameter is not 
checked.

The following startup messages in the stderr log are typical in a 2-SDR config:
    assigning channel "p25 control channel" (channel id 1) to device "rtl11_cc"
    assigning channel "p25 voice channel" (channel id 2) to device "rtl12_vc"
Note that the channel ID displayed in the "tuning error +/-1200" messages can be 
linked to the specific device(s) encountering the error using this ID.

Experimental TDMA Control Channel Support
=========================================

The following specifics detail the JSON configuration file channel parameters
needed to define a TDMA control channel:
        "demod_type": "cqpsk",
        "if_rate": 24000,
        "symbol_rate": 6000,
	"decode": "p25_decoder:role=cc:dev=<device-name>:nac=0x4e1",
The NAC should be changed to match that of the system being received, and
<device-name> should refer to the assigned device.

Colors and Tags for Talkgroup and Radio IDs
===========================================
Tags and colors are defined in two TSV files, one for TGIDs and one for SUIDs.
The TSV file format, compatible with earlier versions of OP25 has the TAB
separated columns defined as:
column one: decimal TG or SU ID.  May contain wildcards (see below)
column two: tag text (string)
column three(optional): encoded priority/color value, decimal (see below)
The color code is directly mapped by client JS into style sheet (CSS) colors.
If only two columns are present the third column is defaulted to zero.

The file names of the two files are specified (comma-separated) in the
trunking TSV "TGID Tags File" column (the trunking TSV in turn is the
file referred to by the "-T" command option of rx.py or multi_rx.py).
The talkgroup tags file name is specified first, followed by a comma,
then the SUID tags file.  The SUID tags file can't be specified alone.

Wildcard IDs (column one) may be (for example)
 * 123-678 [all IDs in range, inclusive, are set to same tag/color]
 * 444.... [all IDs from 4440000 to 4449999]
 * 456* [all IDs starting with 456]
 * 54321 [defines that one ID]

Column three contains a color value from 0-99 (decimal).
In the TGID file (only), the column value also contains a talkgroup
priority, encoded as follows:
 - the low-order two decimal digits (tens and units digits) are the
   color code
 - the remaining upper-order decimal digits (hundreds digit and above) are
   the priority value for talkgroup pre-emption purposes.

Setup SQL Log Database (Optional)
=================================

This addition provides a permanent server-side log of control channel 
activity via logging to an SQL database.  See the next section for details
on installing and using the log viewer.

1. Make sure that sqlite3 is installed in python

          WARNING:          OP25 MUST NOT BE RUNNING DURING THIS STEP
2. Initialize DB (any existing DB data will be destroyed)
op25/.../apps$ python sql_dbi.py reset_db
          WARNING:          OP25 MUST NOT BE RUNNING DURING THIS STEP

3. Import talkgroups tags file
op25/.../apps$ python sql_dbi.py import_tgid tags.tsv <sysid>
   also, import the radio ID tags file (optional)
op25/.../apps$ python sql_dbi.py import_unit radio-tags.tsv <sysid>
   import the System ID tags file (see below)
op25/.../apps$ python sql_dbi.py import_sysid sysid-tags.tsv 0

The sysid tags must be a TSV file containing two columns
column 1 is the P25 trunked sysid (int, decimal)
colunn 2 is the System Name (text)
(Note: there is no header row line in this TSV file).

NOTE: in the various import commands above, the sysid (decimal) must follow
as the next argument after the TSV file name.  For the sysid tags file, the
sysid should be set to zero.

4. Run op25 as usual.  Logfile data should be inserted into DB in real time
   and you should be able to view activity via the OP25 http console (once 
   the flask/datatables app has been set up; see next section).

Setup Flask Datatables App
==========================

0. The DB must first be established (see previous section)

1. Install the necessary libs.  If you are running the install in Ubuntu
   16.04 there are two lines in the script that must be un-commented prior
   to running; then, in any case do:
op25/.../apps$ sh install-sql.sh

Note: you may need to 'sudo apt install git' prior to running this script.

2. Update your .bashrc file as instructed, then re-login to pick up the
   update to PATH.  Verify that the updated PATH is correct.  You can run 
   the command "echo $PATH" to display its current value.  Here is an example
   response:  /home/op25/.local/bin:/usr/local/sbin:/usr/local/bin.....
   You should confirm that the file "flask" exists and is executable (see 
   warning below).

 $ ls -l ~/.local/bin/flask
-rwxr-xr-x 1 op25 op25 212 Apr 29 21:43 /home/op25/.local/bin/flask

3. First change to the "..../apps/oplog" directory, then run the following
   commands to start the flask http process (listens on port 5000)

op25/.../apps/oplog$ export FLASK_APP=op25
op25/.../apps/oplog$ FLASK_DEBUG=1 flask run

WARNING: if you receive the following messages when attempting the "flask run"
command 
-------------------------------------------------------------
Command 'flask' not found, but can be installed with:
sudo apt install python3-flask
-------------------------------------------------------------
most likely this indicates the PATH is not properly set up (see step 2).
In this case we do NOT recommend that you attempt to install the apt version
of flask.  The install-sql.sh script (step 1, above) should have installed a
version of flask in a directory such as:

 $ ls -l ~/.local/bin/flask
-rwxr-xr-x 1 op25 op25 212 Apr 29 21:43 /home/op25/.local/bin/flask

If install of the apt version of flask is attempted, it may result in an 
obsolete and/or incompatible flask version being installed.

NOTE: The following command example can be used when starting the oplog
process as a system service:
    /home/<user>/op25/op25/gr-op25_repeater/apps/oplog/oplog.sh 
 * Change <user> to match the username
 * Make appropriate corrections if the git repo is cloned into a different
   directory than in the command shown
 * Verify the resulting path and filename is correct.
============ oplog.sh ============
#! /bin/sh

export FLASK_APP=op25
FLASK_DEBUG=1 flask run --host=0.0.0.0
==================================

In lieu of setting the flask PATH (as per step 2, above) you could also
specify it explicitly.  In that case, replace the last line of oplog.sh as
follows:
FLASK_DEBUG=1 /home/<user>/.local/bin/flask run --host=0.0.0.0
 * Change <user> to match the username
 * Confirm the "flask" file is present in ..../bin/ and is executable
 * Set "host" to "127.0.0.1" to restrict HTTP connections to the local 
   machine.
 * WARNING The web server is not security-hardened.   It is not
   designed for exposure to public web-facing applications.
   
