core rc2-final
parent
180a4dec97
commit
51042858e8
|
@ -0,0 +1,265 @@
|
|||
|
||||
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
|
||||
* Experimental TDMA Control Channel support
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
{
|
||||
"channels": [
|
||||
{
|
||||
"demod_type": "cqpsk",
|
||||
"destination": "udp://127.0.0.1:23456",
|
||||
"excess_bw": 0.2,
|
||||
"filter_type": "rc",
|
||||
"frequency": 0,
|
||||
"if_rate": 24000,
|
||||
"name": "Oswego CC",
|
||||
"plot": "symbol",
|
||||
"decode": "p25_decoder:role=cc:dev=rtl12:nac=0x2a4",
|
||||
"symbol_rate": 4800
|
||||
},
|
||||
{
|
||||
"demod_type": "cqpsk",
|
||||
"destination": "udp://127.0.0.1:23456",
|
||||
"excess_bw": 0.2,
|
||||
"filter_type": "rc",
|
||||
"frequency": 0,
|
||||
"if_rate": 24000,
|
||||
"name": "Cayuga CC",
|
||||
"plot": "symbol",
|
||||
"decode": "p25_decoder:role=cc:dev=rtl12:nac=0x2a8",
|
||||
"symbol_rate": 4800
|
||||
},
|
||||
{
|
||||
"demod_type": "cqpsk",
|
||||
"destination": "udp://127.0.0.1:23456",
|
||||
"excess_bw": 0.2,
|
||||
"filter_type": "rc",
|
||||
"frequency": 0,
|
||||
"if_rate": 24000,
|
||||
"name": "460 MHz VC",
|
||||
"plot": "symbol",
|
||||
"decode": "p25_decoder:role=vc:dev=rtl12",
|
||||
"symbol_rate": 4800
|
||||
},
|
||||
{
|
||||
"demod_type": "cqpsk",
|
||||
"destination": "udp://127.0.0.1:23456",
|
||||
"excess_bw": 0.2,
|
||||
"filter_type": "rc",
|
||||
"frequency": 0,
|
||||
"if_rate": 24000,
|
||||
"name": "453-454 MHz VC",
|
||||
"plot": "symbol",
|
||||
"decode": "p25_decoder:role=vc:dev=rtl11",
|
||||
"symbol_rate": 4800
|
||||
},
|
||||
{
|
||||
"demod_type": "cqpsk",
|
||||
"destination": "udp://127.0.0.1:56124",
|
||||
"excess_bw": 0.2,
|
||||
"filter_type": "rc",
|
||||
"frequency": 0,
|
||||
"if_rate": 24000,
|
||||
"name": "Onondaga CC",
|
||||
"plot": "symbol",
|
||||
"decode": "p25_decoder:role=cc:dev=rtl12:nac=0x2a0",
|
||||
"symbol_rate": 4800
|
||||
},
|
||||
{
|
||||
"demod_type": "cqpsk",
|
||||
"destination": "udp://127.0.0.1:56124",
|
||||
"excess_bw": 0.2,
|
||||
"filter_type": "rc",
|
||||
"frequency": 0,
|
||||
"if_rate": 24000,
|
||||
"name": "Cortland CC",
|
||||
"plot": "constellation",
|
||||
"decode": "p25_decoder:role=cc:dev=rtl11:nac=0x4e1",
|
||||
"symbol_rate": 4800
|
||||
}
|
||||
],
|
||||
"devices": [
|
||||
{
|
||||
"args": "rtl=00000012",
|
||||
"frequency": 460500000,
|
||||
"gains": "lna:49",
|
||||
"name": "rtl12",
|
||||
"offset": 0,
|
||||
"ppm": 54,
|
||||
"rate": 1000000,
|
||||
"tunable": false
|
||||
},
|
||||
{
|
||||
"args": "rtl=00000011",
|
||||
"frequency": 453850000,
|
||||
"gains": "lna:49",
|
||||
"name": "rtl11",
|
||||
"offset": 0,
|
||||
"ppm": 55,
|
||||
"rate": 2048000,
|
||||
"tunable": false
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,602 @@
|
|||
[
|
||||
[
|
||||
500,
|
||||
"placeholder",
|
||||
"do-not-use",
|
||||
false
|
||||
],
|
||||
[
|
||||
1,
|
||||
"#0066ff",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
2,
|
||||
"#ff0000",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
3,
|
||||
"#ff9900",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
4,
|
||||
"#eeeeee",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
5,
|
||||
"#9966ff",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
6,
|
||||
"#00ff00",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
7,
|
||||
"#009933",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
8,
|
||||
"#ffff00",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
9,
|
||||
"#eee",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
10,
|
||||
"#ff6666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
11,
|
||||
"#0080C0",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
12,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
13,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
14,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
15,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
16,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
17,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
18,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
19,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
20,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
21,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
22,
|
||||
"#ff0000",
|
||||
"",
|
||||
true
|
||||
],
|
||||
[
|
||||
23,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
24,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
25,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
26,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
27,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
28,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
29,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
30,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
31,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
32,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
33,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
34,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
35,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
36,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
37,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
38,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
39,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
40,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
41,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
42,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
43,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
44,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
45,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
46,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
47,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
48,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
49,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
50,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
51,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
52,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
53,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
54,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
55,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
56,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
57,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
58,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
59,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
60,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
61,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
62,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
63,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
64,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
65,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
66,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
67,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
68,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
69,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
70,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
71,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
72,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
73,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
74,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
75,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
76,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
77,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
78,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
79,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
80,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
81,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
82,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
83,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
84,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
85,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
86,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
87,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
88,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
89,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
90,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
91,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
92,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
93,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
94,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
95,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
96,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
97,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
98,
|
||||
"#666666",
|
||||
"",
|
||||
false
|
||||
],
|
||||
[
|
||||
99,
|
||||
"#00ff00",
|
||||
"#000000",
|
||||
false
|
||||
]
|
||||
]
|
|
@ -0,0 +1,383 @@
|
|||
#sql_dbi events map
|
||||
|
||||
events_map = {
|
||||
"grp_v_ch_grant_mbt": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['p', 'options'],
|
||||
['frequency', 'frequency'],
|
||||
['tgid', 'group'],
|
||||
['suid', 'srcaddr'],
|
||||
],
|
||||
"grg_exenc_cmd": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['mfrid', 'mfrid'],
|
||||
['tgid', 'sg'],
|
||||
['p', 'keyid'],
|
||||
],
|
||||
"grp_v_ch_grant": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['mfrid', 'mfrid'],
|
||||
['p', 'options'],
|
||||
['frequency', 'frequency'],
|
||||
['tgid', 'group'],
|
||||
['suid', 'srcaddr'],
|
||||
],
|
||||
"mot_grg_cn_grant": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['mfrid', 'mfrid'],
|
||||
['frequency', 'frequency'],
|
||||
['tgid', 'sg'],
|
||||
['suid', 'sa'],
|
||||
],
|
||||
"grp_v_ch_grant_updt": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['mfrid', 'mfrid'],
|
||||
['frequency', 'frequency1'],
|
||||
['tgid', 'group1'],
|
||||
],
|
||||
"grp_v_ch_grant_updt_exp": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['mfrid', 'mfrid'],
|
||||
['p', 'options'],
|
||||
['frequency', 'frequency'],
|
||||
['tgid', 'group'],
|
||||
],
|
||||
"ack_resp_fne": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['p', 'aiv'],
|
||||
['p2', 'ex'],
|
||||
['p3', 'addl'],
|
||||
['wacn', 'wacn'],
|
||||
['suid', 'source'],
|
||||
['suid2', 'target'],
|
||||
],
|
||||
"deny_resp": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['p', 'aiv'],
|
||||
['p2', 'reason'],
|
||||
['p3', 'additional'],
|
||||
['suid', 'target'],
|
||||
],
|
||||
"grp_aff_resp": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['p', 'affiliation'],
|
||||
['p2', 'group_aff_value'],
|
||||
['tgid', 'announce_group'],
|
||||
['tgid2', 'group'],
|
||||
['suid', 'target'],
|
||||
],
|
||||
"grp_aff_q": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['suid', 'source'],
|
||||
['suid2', 'target'],
|
||||
],
|
||||
"loc_reg_resp": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['p', 'rv'],
|
||||
['p2', 'rfss'],
|
||||
['p3', 'siteid'],
|
||||
['tgid', 'group'],
|
||||
['suid', 'target'],
|
||||
],
|
||||
"u_reg_resp": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['p', 'rv'],
|
||||
['suid', 'source'],
|
||||
['suid2', 'target'],
|
||||
],
|
||||
"u_reg_cmd": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['suid', 'source'],
|
||||
['suid2', 'target'],
|
||||
],
|
||||
"u_de_reg_ack": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['wacn', 'wacn'],
|
||||
['suid', 'source'],
|
||||
],
|
||||
"ext_fnct_cmd": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['mfrid', 'mfrid'],
|
||||
['p', 'efclass'],
|
||||
['p2', 'efoperand'],
|
||||
['suid', 'efargs'],
|
||||
],
|
||||
"end_call": [
|
||||
['time', 'time'],
|
||||
['sysid', 'sysid'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['p', 'code'],
|
||||
['suid', 'srcaddr'],
|
||||
['tgid', 'tgid'],
|
||||
['p2', 'duration'],
|
||||
['p3', 'count'],
|
||||
],
|
||||
}
|
||||
|
||||
# cc_event to numerical id (oplog and sql_dbi)
|
||||
cc_events = {
|
||||
"ack_resp_fne": 1,
|
||||
"deny_resp": 2,
|
||||
"end_call": 3,
|
||||
"ext_fnct_cmd": 4,
|
||||
"grg_exenc_cmd": 5,
|
||||
"grp_aff_q": 6,
|
||||
"grp_aff_resp": 7,
|
||||
"grp_v_ch_grant": 8,
|
||||
"grp_v_ch_grant_mbt": 9,
|
||||
"grp_v_ch_grant_updt": 10,
|
||||
"grp_v_ch_grant_updt_exp": 11,
|
||||
"loc_reg_resp": 12,
|
||||
"u_de_reg_ack": 13,
|
||||
"u_reg_cmd": 14,
|
||||
"u_reg_resp": 15,
|
||||
"mot_grg_cn_grant": 16,
|
||||
}
|
||||
|
||||
# sql column names to DataTables (Oplog)
|
||||
oplog_map = {
|
||||
"grp_v_ch_grant_mbt": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['mfrid', 'MFRID'],
|
||||
['p', 'Options'],
|
||||
['frequency', 'Frequency'],
|
||||
['tgid', 'Talkgroup ID'],
|
||||
['tgid', 'Talkgroup'],
|
||||
['suid', 'Source ID'],
|
||||
['suid', 'Source'],
|
||||
],
|
||||
"grg_exenc_cmd": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['mfrid', 'MFRID'],
|
||||
['tgid', 'SG (tgid)'],
|
||||
['p', 'Key ID'],
|
||||
],
|
||||
"grp_v_ch_grant": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['mfrid', 'MFRID'],
|
||||
['p', 'Options'],
|
||||
['frequency', 'Frequency'],
|
||||
['tgid', 'Talkgroup ID'],
|
||||
['tgid', 'Talkgroup'],
|
||||
['suid', 'Source ID'],
|
||||
['suid', 'Source'],
|
||||
],
|
||||
"mot_grg_cn_grant": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['mfrid', 'MFRID'],
|
||||
['frequency', 'Frequency'],
|
||||
['tgid', 'Talkgroup ID'],
|
||||
['tgid', 'Talkgroup'],
|
||||
['suid', 'Source ID'],
|
||||
['suid', 'Source'],
|
||||
],
|
||||
"grp_v_ch_grant_updt": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['mfrid', 'MFRID'],
|
||||
['frequency', 'Frequency'],
|
||||
['tgid', 'Talkgroup ID'],
|
||||
['tgid', 'Talkgroup'],
|
||||
],
|
||||
"grp_v_ch_grant_updt_exp": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['mfrid', 'mfrid'],
|
||||
['p', 'Options'],
|
||||
['frequency', 'Frequency'],
|
||||
['tgid', 'Talkgroup ID'],
|
||||
['tgid', 'Talkgroup'],
|
||||
],
|
||||
"ack_resp_fne": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['p', 'aiv'],
|
||||
['p2', 'ex'],
|
||||
['p3', 'Additional'],
|
||||
['wacn', 'wacn'],
|
||||
['suid', 'System Source'],
|
||||
['suid2', 'Target ID'],
|
||||
['suid2', 'Target'],
|
||||
],
|
||||
"deny_resp": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['p', 'aiv'],
|
||||
['p2', 'Reason'],
|
||||
['p3', 'Additional'],
|
||||
['suid', 'Target ID'],
|
||||
['suid', 'Target'],
|
||||
],
|
||||
"grp_aff_resp": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['p', 'Affiliation'],
|
||||
['p2', 'Group Aff Value'],
|
||||
['tgid', 'Announce Group'],
|
||||
['tgid2', 'Talkgroup ID'],
|
||||
['tgid2', 'Talkgroup'],
|
||||
['suid', 'Target ID'],
|
||||
['suid', 'Target'],
|
||||
],
|
||||
"grp_aff_q": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['suid', 'System Source'],
|
||||
['suid2', 'Target ID'],
|
||||
['suid2', 'Target'],
|
||||
],
|
||||
"loc_reg_resp": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['p', 'rv'],
|
||||
['p2', 'RFSS'],
|
||||
['p3', 'Site'],
|
||||
['tgid', 'Talkgroup ID'],
|
||||
['tgid', 'Talkgroup'],
|
||||
['suid', 'Target ID'],
|
||||
['suid', 'Target'],
|
||||
],
|
||||
"u_reg_resp": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['p', 'rv'],
|
||||
['suid', 'Source ID'],
|
||||
['suid', 'Source'],
|
||||
['suid2', 'Target'],
|
||||
],
|
||||
"u_reg_cmd": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['suid', 'System Source'],
|
||||
['suid2', 'Target ID'],
|
||||
['suid2', 'Target'],
|
||||
],
|
||||
"u_de_reg_ack": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['wacn', 'WACN'],
|
||||
['suid', 'Source ID'],
|
||||
['suid', 'Source'],
|
||||
],
|
||||
"ext_fnct_cmd": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['mfrid', 'MFRID'],
|
||||
['p', 'Class'],
|
||||
['p2', 'Operand'],
|
||||
['suid', 'System Source'],
|
||||
],
|
||||
"end_call": [
|
||||
['time', 'Time'],
|
||||
['sysid', 'System'],
|
||||
['opcode', 'opcode'],
|
||||
['cc_event', 'cc_event'],
|
||||
['p', 'Code'],
|
||||
['suid', 'Source ID'],
|
||||
['suid', 'Source'],
|
||||
['tgid', 'Talkgroup ID'],
|
||||
['tgid', 'Talkgroup'],
|
||||
['p2', 'Duration (ms)'],
|
||||
['p3', 'Count (p3)'],
|
||||
],
|
||||
}
|
||||
|
||||
# friendly long description strings, used in Oplog
|
||||
cc_desc = {
|
||||
"ack_resp_fne": "Acknowledge Response FNE - 0x20",
|
||||
"deny_resp": "Deny Response - 0x27",
|
||||
"end_call": "End Call (not a naitve control channel event)",
|
||||
"ext_fnct_cmd": "Extended Function Command - 0x24",
|
||||
"grg_exenc_cmd": "Harris Group Regroup Explicit Encryption Command - 0x30",
|
||||
"grp_aff_q": "Group Affiliation Query - 0x2A",
|
||||
"grp_aff_resp": "Group Affiliation Response - 0x2B",
|
||||
"grp_v_ch_grant": "Group Voice Channel Grant - 0x00",
|
||||
"grp_v_ch_grant_mbt": "Group Voice Channel Grant, Multiple Block Trunking",
|
||||
"grp_v_ch_grant_updt": "Group Voice Channel Grant Update - 0x02",
|
||||
"grp_v_ch_grant_updt_exp": "Group Voice Channel Grant Update, Explicit - 0x03",
|
||||
"loc_reg_resp": "Location Registration Response 0x2B",
|
||||
"mot_grg_cn_grant": "Motorola Patch Channel Grant - 0x02",
|
||||
"u_de_reg_ack": "De-Registration Acknowledge (Logout) - 0x2F",
|
||||
"u_reg_cmd": "Unit Registration Command (Force Unit Registration) - 0x2D",
|
||||
"u_reg_resp": "Unit Registration Response - 0x2C"
|
||||
}
|
|
@ -58,7 +58,7 @@ def limit(a,lim):
|
|||
PSEQ = 0
|
||||
|
||||
class wrap_gp(object):
|
||||
def __init__(self, sps=_def_sps, logfile=None, title=None, color_cfg='plot-colors.json'):
|
||||
def __init__(self, sps=_def_sps, logfile=None, title="", color_cfg='plot-colors.json'):
|
||||
global PSEQ
|
||||
self.sps = sps
|
||||
self.center_freq = 0.0
|
||||
|
@ -270,16 +270,16 @@ class wrap_gp(object):
|
|||
h += 'set format ""\n'
|
||||
h += 'set style line 11 lt 1 lw 2 pt 2 ps 2\n'
|
||||
|
||||
h+= 'set title "Constellation" %s\n' % (label_color)
|
||||
h+= 'set title "Constellation %s" %s\n' % (self.title, label_color)
|
||||
elif mode == 'eye':
|
||||
h+= background
|
||||
h+= 'set yrange [-4:4]\n'
|
||||
h+= 'set title "Datascope" %s\n' % (label_color)
|
||||
h+= 'set title "Datascope %s" %s\n' % (self.title, label_color)
|
||||
plot_color = ''
|
||||
elif mode == 'symbol':
|
||||
h+= background
|
||||
h+= 'set yrange [-4:4]\n'
|
||||
h+= 'set title "Symbol" %s\n' % (label_color)
|
||||
h+= 'set title "Symbol %s" %s\n' % (self.title, label_color)
|
||||
elif mode == 'fft' or mode == 'mixer':
|
||||
h+= background
|
||||
h+= 'unset arrow; unset title\n'
|
||||
|
@ -289,9 +289,9 @@ class wrap_gp(object):
|
|||
h+= 'set grid\n'
|
||||
h+= 'set yrange [-100:0]\n'
|
||||
if mode == 'mixer': # mixer
|
||||
h+= 'set title "Mixer: balance %3.0f (smaller is better)" %s\n' % (np.abs(self.avg_sum_pwr * 1000), label_color)
|
||||
h+= 'set title "Mixer %s: balance %3.0f (smaller is better)" %s\n' % (self.title, np.abs(self.avg_sum_pwr * 1000), label_color)
|
||||
else: # fft
|
||||
h+= 'set title "Spectrum" %s\n' % (label_color)
|
||||
h+= 'set title "Spectrum %s" %s\n' % (self.title, label_color)
|
||||
if self.center_freq:
|
||||
arrow_pos = (self.center_freq - self.relative_freq) / 1e6
|
||||
h+= 'set arrow from %f, graph 0 to %f, graph 1 nohead\n' % (arrow_pos, arrow_pos)
|
||||
|
@ -299,7 +299,7 @@ class wrap_gp(object):
|
|||
elif mode == 'float':
|
||||
h+= background
|
||||
h+= 'set yrange [-2:2]\n'
|
||||
h+= 'set title "Oscilloscope" %s\n' % (label_color)
|
||||
h+= 'set title "Oscilloscope %s" %s\n' % (self.title, label_color)
|
||||
elif mode == 'correlation':
|
||||
h+= background
|
||||
title = 'Correlation'
|
||||
|
@ -358,6 +358,9 @@ class eye_sink_f(gr.sync_block):
|
|||
consumed = self.gnuplot.plot(in0, 100*self.sps, mode='eye')
|
||||
return consumed ### len(input_items[0])
|
||||
|
||||
def set_title(self, title):
|
||||
self.gnuplot.set_title(title)
|
||||
|
||||
def kill(self):
|
||||
self.gnuplot.kill()
|
||||
|
||||
|
@ -377,6 +380,9 @@ class constellation_sink_c(gr.sync_block):
|
|||
self.gnuplot.plot(in0, 1000, mode='constellation')
|
||||
return len(input_items[0])
|
||||
|
||||
def set_title(self, title):
|
||||
self.gnuplot.set_title(title)
|
||||
|
||||
def kill(self):
|
||||
self.gnuplot.kill()
|
||||
|
||||
|
@ -400,6 +406,9 @@ class fft_sink_c(gr.sync_block):
|
|||
self.gnuplot.plot(in0, FFT_BINS, mode='fft')
|
||||
return len(input_items[0])
|
||||
|
||||
def set_title(self, title):
|
||||
self.gnuplot.set_title(title)
|
||||
|
||||
def kill(self):
|
||||
self.gnuplot.kill()
|
||||
|
||||
|
@ -436,6 +445,9 @@ class mixer_sink_c(gr.sync_block):
|
|||
self.gnuplot.plot(in0, FFT_BINS, mode='mixer')
|
||||
return len(input_items[0])
|
||||
|
||||
def set_title(self, title):
|
||||
self.gnuplot.set_title(title)
|
||||
|
||||
def kill(self):
|
||||
self.gnuplot.kill()
|
||||
|
||||
|
@ -455,6 +467,9 @@ class symbol_sink_f(gr.sync_block):
|
|||
self.gnuplot.plot(in0, 2400, mode='symbol')
|
||||
return len(input_items[0])
|
||||
|
||||
def set_title(self, title):
|
||||
self.gnuplot.set_title(title)
|
||||
|
||||
def kill(self):
|
||||
self.gnuplot.kill()
|
||||
|
||||
|
@ -474,6 +489,9 @@ class float_sink_f(gr.sync_block):
|
|||
self.gnuplot.plot(in0, 2000, mode='float')
|
||||
return len(input_items[0])
|
||||
|
||||
def set_title(self, title):
|
||||
self.gnuplot.set_title(title)
|
||||
|
||||
def kill(self):
|
||||
self.gnuplot.kill()
|
||||
|
||||
|
|
|
@ -37,6 +37,9 @@ from optparse import OptionParser
|
|||
from multi_rx import byteify
|
||||
from tsvfile import load_tsv, make_config
|
||||
|
||||
import logging
|
||||
logging.basicConfig()
|
||||
|
||||
my_input_q = None
|
||||
my_output_q = None
|
||||
my_recv_q = None
|
||||
|
@ -57,9 +60,41 @@ def ensure_str(s): # for python 2/3
|
|||
ns += chr(s[i])
|
||||
return ns
|
||||
|
||||
class event_iterator:
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
_jslog_file = None # set to str(filename) to enable json log
|
||||
msgs = []
|
||||
while True:
|
||||
msg = my_input_q.delete_head()
|
||||
assert msg.type() == -4
|
||||
d = json.loads(msg.to_string())
|
||||
msgs.append(d)
|
||||
if my_input_q.empty_p():
|
||||
break
|
||||
js = json.dumps(msgs)
|
||||
# TODO: json.loads followed by dumps is redundant -
|
||||
# can this be optimized?
|
||||
s = 'data:%s\r\n\r\n' % (js)
|
||||
|
||||
if _jslog_file:
|
||||
t = json.dumps(msgs, indent=4, separators=[',',':'], sort_keys=True)
|
||||
with open(_jslog_file, 'a') as logfd:
|
||||
logfd.write('%s\n' % t)
|
||||
|
||||
if sys.version[0] != '2':
|
||||
if isinstance(s, str):
|
||||
s = s.encode()
|
||||
return s
|
||||
|
||||
next = __next__ # for python2
|
||||
|
||||
def static_file(environ, start_response):
|
||||
content_types = { 'png': 'image/png', 'jpeg': 'image/jpeg', 'jpg': 'image/jpeg', 'gif': 'image/gif', 'css': 'text/css', 'js': 'application/javascript', 'html': 'text/html', 'ico': 'image/vnd.microsoft.icon'}
|
||||
content_types = {'tsv': 'text/tab-separated-values', 'json': 'application/json', 'png': 'image/png', 'jpeg': 'image/jpeg', 'jpg': 'image/jpeg', 'gif': 'image/gif', 'css': 'text/css', 'js': 'application/javascript', 'html': 'text/html', 'ico': 'image/vnd.microsoft.icon'}
|
||||
img_types = 'png jpg jpeg gif ico'.split()
|
||||
data_types = 'tsv txt json db'.split()
|
||||
if environ['PATH_INFO'] == '/':
|
||||
filename = 'index.html'
|
||||
else:
|
||||
|
@ -68,10 +103,12 @@ def static_file(environ, start_response):
|
|||
pathname = '../www/www-static'
|
||||
if suf in img_types:
|
||||
pathname = '../www/images'
|
||||
elif suf in data_types:
|
||||
pathname = TSV_DIR
|
||||
pathname = '%s/%s' % (pathname, filename)
|
||||
if suf not in content_types.keys() or '..' in filename or not os.access(pathname, os.R_OK):
|
||||
sys.stderr.write('404 %s\n' % pathname)
|
||||
status = '404 NOT FOUND'
|
||||
status = '404 NOT FOUND - PATHNAME: %s FILENAME: %s CWD: %s' % (pathname, filename, os. getcwd())
|
||||
content_type = 'text/plain'
|
||||
output = status
|
||||
else:
|
||||
|
@ -152,6 +189,32 @@ def do_request(d):
|
|||
filename = '%s%s.json' % (CFG_DIR, d['data']['name'])
|
||||
open(filename, 'w').write(json.dumps(d['data']['value'], indent=4, separators=[',',':'], sort_keys=True))
|
||||
return None
|
||||
elif d['command'] == 'config-savesettings':
|
||||
filename = 'ui-settings.json'
|
||||
open(filename, 'w').write(d['data'])
|