Merge pull request #17 from N4IRS/master

Add Changes From N4IRS and N4IRR to original
This commit is contained in:
MrBungle42 2015-12-12 08:11:25 -05:00
commit 7607a5309d
14 changed files with 26716 additions and 33 deletions

9
ambe_audio.cfg Normal file
View File

@ -0,0 +1,9 @@
[SETTINGS]
_debug = False
_outToFile = False
_outToUDP = True
_gateway = 127.0.0.1
_gateway_port = 1234
_remote_control_port = 1235
_tg_filter = 2,3,13,3174,3777215,3100,9,9998,3112

View File

@ -14,9 +14,10 @@ from twisted.internet import reactor
from binascii import b2a_hex as h
from bitstring import BitArray
import sys
import sys, socket, ConfigParser, thread, traceback
import cPickle as pickle
from dmrlink import IPSC, NETWORK, networks, logger, int_id, hex_str_3
from dmrlink import IPSC, NETWORK, networks, logger, int_id, hex_str_3, get_info, talkgroup_ids, subscriber_ids, peer_ids
from time import time
__author__ = 'Cortney T. Buffington, N0MJS'
__copyright__ = 'Copyright (c) 2015 Cortney T. Buffington, N0MJS and the K0USY Group'
@ -27,18 +28,91 @@ __version__ = '0.1a'
__email__ = 'n0mjs@me.com'
__status__ = 'pre-alpha'
try:
from ipsc.ipsc_message_types import *
except ImportError:
sys.exit('IPSC message types file not found or invalid')
#
# ambeIPSC class,
#
class ambeIPSC(IPSC):
_configFile='ambe_audio.cfg'
_debug = False
_outToFile = False
_outToUDP = True
#_gateway = "192.168.1.184"
_gateway = "127.0.0.1"
_gateway_port = 1234
_remote_control_port = 1235
_tg_filter = [2,3,13,3174,3777215,3100,9,9998,3112] #set this to the tg to monitor
_no_tg = -99
_sock = -1;
lastPacketTimeout = 0
_transmitStartTime = 0
def __init__(self, *args, **kwargs):
IPSC.__init__(self, *args, **kwargs)
self.CALL_DATA = []
#
# Define default values for operation. These will be overridden by the .cfg file if found
#
self._currentTG = self._no_tg
self._sequenceNr = 0
self.readConfigFile(self._configFile)
print('DMRLink ambe server')
#
# Open output sincs
#
if self._outToFile == True:
f = open('ambe.bin', 'wb')
print('Opening output file: ambe.bin')
if self._outToUDP == True:
self._sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
print('Send UDP frames to DMR gateway {}:{}'.format(self._gateway, self._gateway_port))
try:
thread.start_new_thread( self.remote_control, (self._remote_control_port, ) )
except:
traceback.print_exc()
print( "Error: unable to start thread" )
# Utility function to convert bytes to string of hex values (for debug)
def ByteToHex( self, byteStr ):
return ''.join( [ "%02X " % ord(x) for x in byteStr ] ).strip()
#
# Now read the configuration file and parse out the values we need
#
def readConfigFile(self, configFileName):
config = ConfigParser.ConfigParser()
try:
self._tg_filter=[]
config.read(configFileName)
for sec in config.sections():
for key, val in config.items(sec):
if self._debug == True:
print( '%s="%s"' % (key, val) )
self._debug = (config.get(sec, '_debug') == "True")
self._outToFile = (config.get(sec, '_outToFile') == "True")
self._outToUDP = (config.get(sec, '_outToUDP') == "True")
self._gateway = config.get(sec, '_gateway')
self._gateway_port = int(config.get(sec, '_gateway_port'))
_tgs = config.get(sec, '_tg_filter')
self._tg_filter = map(int, _tgs.split(','))
except:
traceback.print_exc()
sys.exit('Configuration file \''+configFileName+'\' is not a valid configuration file! Exiting...')
#************************************************
# CALLBACK FUNCTIONS FOR USER PACKET TYPES
#************************************************
@ -53,22 +127,79 @@ class ambeIPSC(IPSC):
_ambe_frame2 = _ambe_frames[50:99]
_ambe_frame3 = _ambe_frames[100:149]
if _payload_type == BURST_DATA_TYPE['VOICE_HEAD']:
print('Voice Transmission Start')
if _payload_type == BURST_DATA_TYPE['VOICE_TERM']:
print('Voice Transmission End')
if _payload_type == BURST_DATA_TYPE['SLOT1_VOICE']:
print(_ambe_frames)
print('Frame 1:', _ambe_frame1.bytes)
print('Frame 2:', _ambe_frame2.bytes)
print('Frame 3:', _ambe_frame3.bytes)
if _payload_type == BURST_DATA_TYPE['SLOT2_VOICE']:
print(_ambe_frames)
print('Frame 1:', _ambe_frame1.bytes)
print('Frame 2:', _ambe_frame2.bytes)
print('Frame 3:', _ambe_frame3.bytes)
_tg_id = int_id(_dst_sub)
if _tg_id in self._tg_filter: #All TGs
_dst_sub = get_info(int_id(_dst_sub), talkgroup_ids)
if _payload_type == BURST_DATA_TYPE['VOICE_HEAD']:
if self._currentTG == self._no_tg:
_src_sub = get_info(int_id(_src_sub), subscriber_ids)
print('Voice Transmission Start on TS {} and TG {} ({}) from {}'.format("2" if _ts else "1", _dst_sub, _tg_id, _src_sub))
self._currentTG = _tg_id
self._transmitStartTime = time()
else:
if self._currentTG != _tg_id:
if time() > self.lastPacketTimeout:
self._currentTG = self._no_tg #looks like we never saw an EOT from the last stream
print('EOT timeout')
else:
print('Transmission in progress, will not decode stream on TG {}'.format(_tg_id))
if self._currentTG == _tg_id:
if _payload_type == BURST_DATA_TYPE['VOICE_TERM']:
print('Voice Transmission End %.2f seconds' % (time() - self._transmitStartTime))
self._currentTG = self._no_tg
if _payload_type == BURST_DATA_TYPE['SLOT1_VOICE']:
self.outputFrames(_ambe_frames, _ambe_frame1, _ambe_frame2, _ambe_frame3)
if _payload_type == BURST_DATA_TYPE['SLOT2_VOICE']:
self.outputFrames(_ambe_frames, _ambe_frame1, _ambe_frame2, _ambe_frame3)
self.lastPacketTimeout = time() + 10
else:
if _payload_type == BURST_DATA_TYPE['VOICE_HEAD']:
_dst_sub = get_info(int_id(_dst_sub), talkgroup_ids)
print('Ignored Voice Transmission Start on TS {} and TG {}'.format("2" if _ts else "1", _dst_sub))
def outputFrames(self, _ambe_frames, _ambe_frame1, _ambe_frame2, _ambe_frame3):
if self._debug == True:
print(_ambe_frames)
print('Frame 1:', self.ByteToHex(_ambe_frame1.tobytes()))
print('Frame 2:', self.ByteToHex(_ambe_frame2.tobytes()))
print('Frame 3:', self.ByteToHex(_ambe_frame3.tobytes()))
if self._outToFile == True:
f.write( _ambe_frame1.tobytes() )
f.write( _ambe_frame2.tobytes() )
f.write( _ambe_frame3.tobytes() )
if self._outToUDP == True:
self._sock.sendto(_ambe_frame1.tobytes(), (self._gateway, self._gateway_port))
self._sock.sendto(_ambe_frame2.tobytes(), (self._gateway, self._gateway_port))
self._sock.sendto(_ambe_frame3.tobytes(), (self._gateway, self._gateway_port))
#
# Define a function for the thread
# Use netcat to dynamically change the TGs that are forwarded to Allstar
# echo "x,y,z" | nc 127.0.0.1 1235
#
def remote_control(self, port):
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
s.bind((host, port)) # Bind to the port
s.listen(5) # Now wait for client connection.
print('Remote control is listening on:', host, port)
while True:
c, addr = s.accept() # Establish connection with client.
print( 'Got connection from', addr )
tgs = c.recv(1024)
if tgs:
self._tg_filter = map(int, tgs.split(','))
print( 'New TGs=', self._tg_filter )
c.close() # Close the connection
if __name__ == '__main__':
logger.info('DMRlink \'ambe_audio.py\' (c) 2015 N0MJS & the K0USY Group - SYSTEM STARTING...')
for ipsc_network in NETWORK:

View File

@ -218,7 +218,7 @@ class bridgeIPSC(IPSC):
# Calculate and append the authentication hash for the target network... if necessary
if NETWORK[_target]['LOCAL']['AUTH_ENABLED']:
_tmp_data = self.hashed_packet(NETWORK[_target]['LOCAL']['AUTH_KEY'], _tmp_data)
_tmp_data = self.auth_hashed_packet(NETWORK[_target]['LOCAL']['AUTH_KEY'], _tmp_data)
# Send the packet to all peers in the target IPSC
networks[_target].send_to_ipsc(_tmp_data)
@ -242,7 +242,7 @@ class bridgeIPSC(IPSC):
# Calculate and append the authentication hash for the target network... if necessary
if NETWORK[target]['LOCAL']['AUTH_ENABLED']:
_tmp_data = self.hashed_packet(NETWORK[target]['LOCAL']['AUTH_KEY'], _tmp_data)
_tmp_data = self.auth_hashed_packet(NETWORK[target]['LOCAL']['AUTH_KEY'], _tmp_data)
# Send the packet to all peers in the target IPSC
networks[target].send_to_ipsc(_tmp_data)
@ -258,7 +258,7 @@ class bridgeIPSC(IPSC):
# Calculate and append the authentication hash for the target network... if necessary
if NETWORK[target]['LOCAL']['AUTH_ENABLED']:
_tmp_data = self.hashed_packet(NETWORK[target]['LOCAL']['AUTH_KEY'], _tmp_data)
_tmp_data = self.auth_hashed_packet(NETWORK[target]['LOCAL']['AUTH_KEY'], _tmp_data)
# Send the packet to all peers in the target IPSC
networks[target].send_to_ipsc(_tmp_data)

56
dmr_install Executable file
View File

@ -0,0 +1,56 @@
#! /bin/sh
#################################################
# #
# Create directory structure for DMRlink #
# #
#################################################
# Minor updates to DIAL
# rm /etc/asterisk/firsttime
cd /etc/asterisk/
wget https://github.com/N4IRS/AllStar/raw/master/configs/dnsmgr.conf
# wget https://github.com/N4IRS/AllStar/raw/master/configs/modules.conf
# Checkout DMRlink and put it in /opt
cd /srv
git clone https://github.com/N4IRS/DMRlink
cd /srv/DMRlink/
./mk_dmrlink
# setup boot for DV3000
cd /srv
systemctl stop getty@ttyAMA0.service
systemctl disable getty@ttyAMA0.service
apt-get install -y sudo
# Setup WiringPi
git clone git://git.drogon.net/wiringPi
cd wiringPi/
./build
cd ..
# Setup AMBEserverGPIO
git clone https://github.com/dl5di/OpenDV.git
mv OpenDV/DummyRepeater/DV3000 DV3000
rm -rf OpenDV
cd DV3000/
make clean
make
make install
make init-install
python AMBEtest3.py
cd /etc/init.d
update-rc.d AMBEserverGPIO start 50 2 3 4 5
# Setup DMRGateway
cd /srv
git clone https://github.com/N4IRS/DMRGateway.git
cd DMRGateway/
./install.sh
cp config.txt /boot
cp cmdline.txt /boot
# reboot

View File

@ -46,6 +46,8 @@ __maintainer__ = 'Cort Buffington, N0MJS'
__email__ = 'n0mjs@me.com'
__status__ = 'beta'
# Change the current directory to the location of the application
os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])))
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--config', action='store', dest='CFG_FILE', help='/full/path/to/config.file (usually dmrlink.cfg)')
@ -290,15 +292,15 @@ try:
with open(PATH+'subscriber_ids.csv', 'rU') as subscriber_ids_csv:
subscribers = csv.reader(subscriber_ids_csv, dialect='excel', delimiter=',')
for row in subscribers:
subscriber_ids[int(row[1])] = (row[0])
subscriber_ids[int(row[0])] = (row[1])
except ImportError:
logger.warning('subscriber_ids.csv not found: Subscriber aliases will not be available')
try:
with open(PATH+'peer_ids.csv', 'rU') as peer_ids_csv:
peers = csv.reader(peer_ids_csv, dialect='excel', delimiter=',')
for row in peers:
peer_ids[int(row[1])] = (row[0])
peer_ids[int(row[0])] = (row[1])
except ImportError:
logger.warning('peer_ids.csv not found: Peer aliases will not be available')

View File

@ -2,13 +2,15 @@
#
# Rename to dmrlink.cfg and add your information
#
# minor tweaks to match install for use by DMRGateway
# N4IRS
#
#
# GLOBAL CONFIGURATION ITEMS
#
[GLOBAL]
PATH: /absolute/path/to/DMRlink
PATH: /opt/dmrlink/
# NETWORK REPORTING CONFIGURATION
@ -54,9 +56,9 @@ PRINT_PEERS_INC_FLAGS: 0
# used.
#
[LOGGER]
LOG_FILE: /tmp/dmrlink.log
LOG_HANDLERS: console
LOG_LEVEL: CRITICAL
LOG_FILE: /var/log/dmrlink/dmrlink.log
LOG_HANDLERS: file
LOG_LEVEL: INFO
LOG_NAME: DMRlink
@ -67,7 +69,7 @@ LOG_NAME: DMRlink
# [NAME] The name you want to use to identify the IPSC instance (use
# something better than "IPSC1"...)
# ENABLED: Should we communiate with this network? Handy if you need to
# shut one down but don't want to lose the config
# shut one down but don't want to lose the config
# RADIO_ID: This is the radio ID that DMRLink should use to communicate
# IP: This is the local IPv4 address to listen on. It may be left
blank if you do not need or wish to specify. It is mostly
@ -103,10 +105,10 @@ LOG_NAME: DMRlink
# ...Repeat the block for each IPSC network to join.
#
[IPSC1]
[SAMPLE_PEER]
ENABLED: True
RADIO_ID: 12345
IP: 4.3.2.1
IP: 127.0.0.1
PORT: 50000
ALIVE_TIMER: 5
MAX_MISSED: 20
@ -126,3 +128,31 @@ AUTH_ENABLED: True
AUTH_KEY: 1A2B3C
MASTER_IP: 1.2.3.4
MASTER_PORT: 50000
[SAMPLE_MASTER]
ENABLED: False
RADIO_ID: 54321
IP: 192.168.1.1
PORT: 50000
ALIVE_TIMER: 5
MAX_MISSED: 20
PEER_OPER: True
IPSC_MODE: DIGITAL
TS1_LINK: True
TS2_LINK: True
CSBK_CALL: False
RCM: True
CON_APP: True
XNL_CALL: False
XNL_MASTER: False
DATA_CALL: True
VOICE_CALL: True
MASTER_PEER: True
AUTH_ENABLED: True
AUTH_KEY: 1A2B3C
# Below not used for a Master
# MASTER_IP: 1.2.3.4
# MASTER_PORT: 50000

32
get_ids.sh Normal file
View File

@ -0,0 +1,32 @@
#! /bin/sh
#################################################
# #
# Create directory structure for DMRlink #
# #
#################################################
# To provide more readable output from DMRlink with current subscriber and repeater IDs, we download the CSV files from DMR-MARC
# If you are going to use this in a cron task, don't run it more then once a day.
# It might be good to find alternale a source as a backup.
# <http://www.dmr-marc.net/cgi-bin/trbo-database/datadump.cgi>
# wget -O users.csv -q "http://www.dmr-marc.net/cgi-bin/trbo-database/datadump.cgi?table=users&format=csv&header=0"
# Options are:
# table { users | repeaters }
# format { table | csv | csvq | json }
# header { 0 | 1 } (only applies to table and csv formats)
# id { nnnnnn } (query an individual record)
# Get the user IDs.
wget -O subscriber_ids.csv -q "http://www.dmr-marc.net/cgi-bin/trbo-database/datadump.cgi?table=users&format=csv&header=0"
# Get the peer IDs
wget -O peer_ids.csv -q "http://www.dmr-marc.net/cgi-bin/trbo-database/datadump.cgi?table=repeaters&format=csv&header=0"

64
init.d/bridge Executable file
View File

@ -0,0 +1,64 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: Mototrbo_IPSC_bridging
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: DMRlink Bridge
# Description: Open Source IPSC bridging
### END INIT INFO
# Where is the directory containing DMRlink
DIR=/opt/dmrlink/bridge
# Filename of the python script
DAEMON=$DIR/bridge.py
# Daemon name
DAEMON_NAME=bridge
# Add any command line options for your daemon where
DAEMON_OPTS=""
# This next line determines what user the script runs as.
# Root generally not recommended but necessary if you are using the Raspberry Pi GPIO from Python.
DAEMON_USER=root
# The process ID of the script when it runs is stored here:
PIDFILE=/var/run/$DAEMON_NAME.pid
. /lib/lsb/init-functions
do_start () {
log_daemon_msg "Starting system $DAEMON_NAME daemon"
start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --chuid $DAEMON_USER --startas $DAEMON -- $DAEMON_OPTS
log_end_msg $?
}
do_stop () {
log_daemon_msg "Stopping system $DAEMON_NAME daemon"
start-stop-daemon --stop --pidfile $PIDFILE --remove-pidfile --retry 10
log_end_msg $?
}
case "$1" in
start|stop)
do_${1}
;;
restart|reload|force-reload)
do_stop
do_start
;;
status)
status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $?
;;
*)
echo "Usage: /etc/init.d/$DAEMON_NAME {start|stop|restart|status}"
exit 1
;;
esac
exit 0

6
install.txt Normal file
View File

@ -0,0 +1,6 @@
To install DMRlink for DMRGateway
cd /srv
git clone https://github.com/N4IRS/DMRlink.git
cd DMRlink
./mk_dmrlink

115
mk_dmrlink Executable file
View File

@ -0,0 +1,115 @@
#! /bin/sh
#################################################
# #
# Create directory structure for DMRlink #
# #
#################################################
apt-get install unzip -y
apt-get install python-twisted -y
# To allow multiple instances of DMRlink to run
# You need multiple ipsc directories, dmrlink.py and dmrlink.cfg
# The needed files are copied to /opt/dmrlink
# Make needed directories
mkdir -p /opt/dmrlink/ambe_audio/ipsc
mkdir -p /opt/dmrlink/bridge/ipsc
mkdir -p /opt/dmrlink/gateway/ipsc
mkdir -p /opt/dmrlink/log/ipsc
mkdir -p /opt/dmrlink/playback/ipsc
mkdir -p /opt/dmrlink/play_group/ipsc
mkdir -p /opt/dmrlink/record/ipsc
mkdir -p /opt/dmrlink/rcm/ipsc
mkdir -p /opt/dmrlink/doc
mkdir -p /opt/dmrlink/samples
mkdir -p /var/log/dmrlink
# Put scripts in /opt/dmrlink
cp /srv/DMRlink/get_ids.sh /opt/dmrlink # should be linked to /etc/cron.daily
cp /srv/DMRlink/init.d/bridge /opt/dmrlink/rc.bridge
# bitstring install
cd /opt/dmrlink
wget https://pypi.python.org/packages/source/b/bitstring/bitstring-3.1.3.zip
unzip bitstring-3.1.3.zip
cd bitstring-3.1.3
python setup.py install
cd /opt/dmrlink
rm bitstring-3.1.3.zip
# Put common files in /opt/dmrlink
cp /srv/DMRlink/subscriber_ids.csv /opt/dmrlink
cp /srv/DMRlink/talkgroup_ids.csv /opt/dmrlink
cp /srv/DMRlink/peer_ids.csv /opt/dmrlink
cp /srv/DMRlink/get_ids.sh /opt/dmrlink
# Copy ipsc directory into each app directory
cp /srv/DMRlink/ipsc/* /opt/dmrlink/ambe_audio/ipsc
cp /srv/DMRlink/ipsc/* /opt/dmrlink/bridge/ipsc
cp /srv/DMRlink/ipsc/* /opt/dmrlink/gateway/ipsc
cp /srv/DMRlink/ipsc/* /opt/dmrlink/log/ipsc
cp /srv/DMRlink/ipsc/* /opt/dmrlink/playback/ipsc
cp /srv/DMRlink/ipsc/* /opt/dmrlink/play_group/ipsc
cp /srv/DMRlink/ipsc/* /opt/dmrlink/record/ipsc
cp /srv/DMRlink/ipsc/* /opt/dmrlink/rcm/ipsc
# Put the samples together for easy ref
cp /srv/DMRlink/bridge_rules_SAMPLE.py /opt/dmrlink/samples
cp /srv/DMRlink/dmrlink_SAMPLE.cfg /opt/dmrlink/samples
cp /srv/DMRlink/known_bridges_SAMPLE.py /opt/dmrlink/samples
cp /srv/DMRlink/playback_config_SAMPLE.py /opt/dmrlink/samples
# Put the doc together for easy ref
cp /srv/DMRlink/FAQ.md /opt/dmrlink/doc
cp /srv/DMRlink/internal_data_decode.txt /opt/dmrlink/doc
cp /srv/DMRlink/LICENSE.txt /opt/dmrlink/doc
cp /srv/DMRlink/README.md /opt/dmrlink/doc
cp /srv/DMRlink/requirements.txt /opt/dmrlink/doc
# Stock ambe_audio
cp /srv/DMRlink/ambe_audio.cfg /opt/dmrlink/ambe_audio/
cp /srv/DMRlink/ambe_audio.py /opt/dmrlink/ambe_audio/
cp /srv/DMRlink/dmrlink.py /opt/dmrlink/ambe_audio/
cp /srv/DMRlink/dmrlink_SAMPLE.cfg /opt/dmrlink/ambe_audio/dmrlink.cfg
# ambe_audio for DMRGateway
cp /srv/DMRlink/ambe_audio.cfg /opt/dmrlink/gateway/
cp /srv/DMRlink/ambe_audio.py /opt/dmrlink/gateway/
cp /srv/DMRlink/dmrlink.py /opt/dmrlink/gateway/
cp /srv/DMRlink/dmrlink_SAMPLE.cfg /opt/dmrlink/gateway/dmrlink.cfg
# Bridge app
cp /srv/DMRlink/bridge.py /opt/dmrlink/bridge/
cp /srv/DMRlink/dmrlink.py /opt/dmrlink/bridge/
cp /srv/DMRlink/bridge_rules_SAMPLE.py /opt/dmrlink/bridge/
cp /srv/DMRlink/dmrlink_SAMPLE.cfg /opt/dmrlink/bridge/dmrlink.cfg
# Log app
cp /srv/DMRlink/log.py /opt/dmrlink/log/
cp /srv/DMRlink/dmrlink.py /opt/dmrlink/log/
cp /srv/DMRlink/dmrlink_SAMPLE.cfg /opt/dmrlink/log/dmrlink.cfg
# Playback (Parrot)
cp /srv/DMRlink/playback.py /opt/dmrlink/playback/
cp /srv/DMRlink/dmrlink.py /opt/dmrlink/playback/
cp /srv/DMRlink/dmrlink_SAMPLE.cfg /opt/dmrlink/playback/dmrlink.cfg
# Play Group app
cp /srv/DMRlink/play_group.py /opt/dmrlink/play_group/
cp /srv/DMRlink/dmrlink.py /opt/dmrlink/play_group/
cp /srv/DMRlink/dmrlink_SAMPLE.cfg /opt/dmrlink/play_group/dmrlink.cfg
# record app
cp /srv/DMRlink/record.py /opt/dmrlink/record/
cp /srv/DMRlink/dmrlink.py /opt/dmrlink/record/
cp /srv/DMRlink/dmrlink_SAMPLE.cfg /opt/dmrlink/record/dmrlink.cfg
# rcm app
cp /srv/DMRlink/rcm_db_log.py /opt/dmrlink/rcm/
cp /srv/DMRlink/rcm.py /opt/dmrlink/rcm/
cp /srv/DMRlink/dmrlink.py /opt/dmrlink/rcm/
cp /srv/DMRlink/dmrlink_SAMPLE.cfg /opt/dmrlink/rcm/dmrlink.cfg
cp /srv/DMRlink/pickle_stat_reader.py /opt/dmrlink/rcm/

File diff suppressed because one or more lines are too long

View File

@ -1 +1,3 @@
Twisted>=12.0.0
https://pypi.python.org/packages/source/b/bitstring/bitstring-3.1.3.zip

File diff suppressed because one or more lines are too long

View File

@ -1 +1,11 @@
Worldwide,1 Local,2 North America,3 T6-DCI Bridge,3100 Kansas Statewide,3120 Missouri,3129 Massachussetts,3125 Midwest,3169 Northeast,3172
Worldwide,1 Local,2 North America,3
DMRPlus,9
Worldwide English,13
TAC 310,310
DCI Bridge 2,3100 DCI 1,3160
Midwest,3169 Northeast,3172
Southeast,3174
Flordia,3112
Kansas Statewide,3120 Massachussetts,3125 Missouri,3129
DCI Comm 1,3777215
Echo Server,9998
1 Worldwide Worldwide,1 Local,2 North America,3 1 Local 2 North America 3 T6-DCI Bridge 3100 Kansas Statewide 3120 Missouri 3129 Massachussetts 3125 Midwest 3169 Northeast 3172
2 DMRPlus,9
3 Worldwide English,13
4 TAC 310,310
5 DCI Bridge 2,3100 DCI 1,3160
6 Midwest,3169 Northeast,3172
7 Southeast,3174
8 Flordia,3112
9 Kansas Statewide,3120 Massachussetts,3125 Missouri,3129
10 DCI Comm 1,3777215
11 Echo Server,9998