Client Fully Connects with BrandMeister
Thanks to Colin Durbridge G4EML for figuring out MANY of the BrandMeister changes to HB Protocol (some not documented).
This commit is contained in:
parent
a8dc160bb4
commit
addc9cb52c
12
hb_config.py
12
hb_config.py
@ -23,7 +23,8 @@ def build_config(_config_file):
|
||||
|
||||
# Process GLOBAL items in the configuration
|
||||
CONFIG['GLOBAL'].update({
|
||||
'PATH': config.get(section, 'PATH')
|
||||
'PATH': config.get(section, 'PATH'),
|
||||
'PING_TIME': config.getint(section, 'PING_TIME')
|
||||
})
|
||||
|
||||
elif section == 'LOGGER':
|
||||
@ -49,13 +50,14 @@ def build_config(_config_file):
|
||||
'RADIO_ID': hex(int(config.get(section, 'RADIO_ID')))[2:].rjust(8,'0').decode('hex'),
|
||||
'RX_FREQ': config.get(section, 'RX_FREQ').rjust(9),
|
||||
'TX_FREQ': config.get(section, 'TX_FREQ').rjust(9),
|
||||
'TX_POWER': config.get(section, 'TX_POWER').rjust(2),
|
||||
'COLORCODE': config.get(section, 'COLORCODE').rjust(2),
|
||||
'TX_POWER': config.get(section, 'TX_POWER').rjust(2,'0'),
|
||||
'COLORCODE': config.get(section, 'COLORCODE').rjust(2,'0'),
|
||||
'LATITUDE': config.get(section, 'LATITUDE').rjust(8),
|
||||
'LONGITUDE': config.get(section, 'LONGITUDE').rjust(9),
|
||||
'HEIGHT': config.get(section, 'HEIGHT').rjust(3),
|
||||
'HEIGHT': config.get(section, 'HEIGHT').rjust(3,'0'),
|
||||
'LOCATION': config.get(section, 'LOCATION').rjust(20),
|
||||
'DESCRIPTION': config.get(section, 'DESCRIPTION').rjust(20),
|
||||
'DESCRIPTION': config.get(section, 'DESCRIPTION').rjust(19),
|
||||
'SLOTS': config.get(section, 'SLOTS'),
|
||||
'URL': config.get(section, 'URL').rjust(124),
|
||||
'SOFTWARE_ID': config.get(section, 'SOFTWARE_ID').rjust(40),
|
||||
'PACKAGE_ID': config.get(section, 'PACKAGE_ID').rjust(40)
|
||||
|
@ -1,21 +0,0 @@
|
||||
# Copyright (c) 2016 Cortney T. Buffington, N0MJS and the K0USY Group. n0mjs@me.com
|
||||
#
|
||||
# This work is licensed under the Creative Attribution-NonCommercial-ShareAlike
|
||||
# 3.0 Unported License.To view a copy of this license, visit
|
||||
# http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to
|
||||
# Creative Commons, 444 Castro Street, Suite 900, Mountain View,
|
||||
# California, 94041, USA.
|
||||
|
||||
# Known HomeBrew Repeater Message Types
|
||||
# In message below, "ID" is taken to mean the 4-byte HEX repeater ID string of the repaeter(DMR Radio ID)
|
||||
RPTL = 'RPTL' # Initial LOGIN, RPTL+ID
|
||||
MSTNAK = 'MSTNAK' # Master negatvive ack, MSTNAK+ID
|
||||
MSTACK = 'MSTACK' # Master acknowledgement, MSTACK+ID
|
||||
# if in response to a login, MSTACK+ID+(random 32-bit integer (as a string))
|
||||
RPTK = 'RPTK' # See explantation elsewhere about passphrase, ID and SHA-256 hash!
|
||||
MSTPING = 'MSTPING' # From the repeater, MSTPING+ID
|
||||
RPTPONG = 'RPTPONG' # From the master, MSTPONG+ID
|
||||
MSTCL = 'MSTCL' # From the master, MSTCL+ID indicates close-down of the master
|
||||
RPTCL = 'RPTCL' # From the repeater, RPTCL+ID indicates close-down of the repeater
|
||||
RPTC = 'RPTC' # From the repeater, information packet about the repeater
|
||||
DMRD = 'DMRD' # DMR data, format documented elsewhere
|
@ -1,12 +1,25 @@
|
||||
# PROGRAM-WIDE PARAMETERS GO HERE
|
||||
# PATH - working path for files, leave it alone unless you NEED to change it
|
||||
# PING_TIME - the interval that clients will ping the master, and re-try registraion
|
||||
[GLOBAL]
|
||||
PATH: ./
|
||||
PING_TIME
|
||||
|
||||
# LOGGING CONFIGURATION
|
||||
# Should be self explanatory. See Python logging module for more information
|
||||
# Several convenient handlers have been pre-configured, check out the module
|
||||
# hb_log.py to see them
|
||||
[LOGGER]
|
||||
LOG_FILE: /tmp/hblink.log
|
||||
LOG_HANDLERS: console-timed
|
||||
LOG_LEVEL: DEBUG
|
||||
LOG_NAME: HBlink
|
||||
|
||||
# MASTER INSTANCES - DUPLICATE SECTION FOR MULTIPLE CLIENTS
|
||||
# HomeBrew Protocol Master instances go here.
|
||||
# IP may be left blank if there's one interface on your system.
|
||||
# Port should be the port you want this master to listen on. It must be unique
|
||||
# and unused by anything else.
|
||||
[MASTER-1]
|
||||
MODE: MASTER
|
||||
ENABLED: True
|
||||
@ -14,13 +27,13 @@ IP:
|
||||
PORT: 54000
|
||||
PASSPHRASE: s3cr37w0rd
|
||||
|
||||
[MASTER-2]
|
||||
MODE: MASTER
|
||||
ENABLED: False
|
||||
IP:
|
||||
PORT: 55000
|
||||
PASSPHRASE: 13370p3r470r
|
||||
|
||||
# CLIENT INSTANCES - DUPLICATE SECTION FOR MULTIPLE CLIENTS
|
||||
# There are a LOT of errors in the HB Protocol specifications on this one!
|
||||
# MOST of these items are just strings and will be properly dealt with by the program
|
||||
# The TX & RX Frequencies are 9-digit numbers, and are the frequency in Hz.
|
||||
# Latitude is an 8-digit unsigned floating point number.
|
||||
# Longitude is a 9-digit signed floating point number.
|
||||
# Height is in meters
|
||||
[REPEATER-1]
|
||||
MODE: CLIENT
|
||||
ENABLED: True
|
||||
@ -31,38 +44,15 @@ MASTER_PORT: 54000
|
||||
PASSPHRASE: homebrew
|
||||
CALLSIGN: W1ABC
|
||||
RADIO_ID: 312000
|
||||
RX_FREQ: 449.000000
|
||||
TX_FREQ: 444.000000
|
||||
RX_FREQ: 449000000
|
||||
TX_FREQ: 444000000
|
||||
TX_POWER: 25
|
||||
ColorCode: 1
|
||||
LATITUDE: 38.00000
|
||||
LONGITUDE: -95.00000
|
||||
LATITUDE: 038.0000
|
||||
LONGITUDE: -095.0000
|
||||
HEIGHT: 75
|
||||
LOCATION: Anywhere, USA
|
||||
DESCRIPTION: This is a cool repeater
|
||||
URL: www.w1abc.org
|
||||
SOFTWARE_ID: HBlink v1.0
|
||||
PACKAGE_ID: HBlink v1.0
|
||||
|
||||
[REPEATER-2]
|
||||
MODE: CLIENT
|
||||
ENABLED: False
|
||||
IP:
|
||||
PORT: 54002
|
||||
MASTER_IP: 172.16.1.1
|
||||
MASTER_PORT: 54000
|
||||
PASSPHRASE: homebrew
|
||||
CALLSIGN: K9ABC
|
||||
RADIO_ID: 312001
|
||||
RX_FREQ: 448.000000
|
||||
TX_FREQ: 443.000000
|
||||
TX_POWER: 40
|
||||
ColorCode: 1
|
||||
LATITUDE: 38.10000
|
||||
LONGITUDE: -95.10000
|
||||
HEIGHT: 50
|
||||
LOCATION: Somewhere, USA
|
||||
DESCRIPTION: This is a cooler repeater
|
||||
URL: www.k9abc.org
|
||||
SOFTWARE_ID: HBlink v1.0
|
||||
PACKAGE_ID: HBlink v1.0
|
||||
SOFTWARE_ID: HBlink
|
||||
PACKAGE_ID: v0.1
|
55
hblink.py
55
hblink.py
@ -12,6 +12,7 @@ from __future__ import print_function
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
import signal
|
||||
|
||||
# Specifig functions from modules we need
|
||||
from binascii import b2a_hex as h
|
||||
@ -31,12 +32,11 @@ from twisted.internet import task
|
||||
# Other files we pull from -- this is mostly for readability and segmentation
|
||||
import hb_log
|
||||
import hb_config
|
||||
from hb_message_types import *
|
||||
|
||||
# Does anybody read this stuff? There's a PEP somewhere that says I should do this.
|
||||
__author__ = 'Cortney T. Buffington, N0MJS'
|
||||
__copyright__ = 'Copyright (c) 2013 - 2016 Cortney T. Buffington, N0MJS and the K0USY Group'
|
||||
__credits__ = 'Steve Zingman, N4IRS; Mike Zingman, N4IRR; Jonathan Naylor, G4KLX; Hans Barthen, DL5DI; Torsten Shultze, DG1HT'
|
||||
__credits__ = 'Colin Durbridge, G4EML, Steve Zingman, N4IRS; Mike Zingman, N4IRR; Jonathan Naylor, G4KLX; Hans Barthen, DL5DI; Torsten Shultze, DG1HT'
|
||||
__license__ = 'Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported'
|
||||
__maintainer__ = 'Cort Buffington, N0MJS'
|
||||
__email__ = 'n0mjs@me.com'
|
||||
@ -69,7 +69,20 @@ if cli_args.LOG_LEVEL:
|
||||
logger = hb_log.config_logging(CONFIG['LOGGER'])
|
||||
logger.debug('Logging system started, anything from here on gets logged')
|
||||
|
||||
# Shut ourselves down gracefully by disconnecting from the masters and clients.
|
||||
def handler(_signal, _frame):
|
||||
logger.info('*** HBLINK IS TERMINATING WITH SIGNAL %s ***', str(_signal))
|
||||
|
||||
for client in clients:
|
||||
this_client = clients[client]
|
||||
this_client.send_packet('RPTCL'+CONFIG['CLIENTS'][client]['RADIO_ID'])
|
||||
logger.info('(%s) De-Registering From the Master', client)
|
||||
|
||||
reactor.stop()
|
||||
|
||||
# Set signal handers so that we can gracefully exit if need be
|
||||
for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]:
|
||||
signal.signal(sig, handler)
|
||||
|
||||
#************************************************
|
||||
# HERE ARE THE IMPORTANT PARTS
|
||||
@ -95,39 +108,37 @@ class HBCLIENT(DatagramProtocol):
|
||||
logger.error('(%s) HBCLIENT was not called with an argument. Terminating', self._client)
|
||||
sys.exit()
|
||||
|
||||
def send_packet(self, _packet):
|
||||
print('did this')
|
||||
self.transport.write(_packet, (self._config['MASTER_IP'], self._config['MASTER_PORT']))
|
||||
# KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!!
|
||||
logger.debug('(%s) TX Packet to %s on port %s: %s', self._client, self._config['MASTER_IP'], self._config['MASTER_PORT'], h(_packet))
|
||||
|
||||
def startProtocol(self):
|
||||
# Set up periodic loop for sending pings to the master. Run every minute
|
||||
self._peer_maintenance = task.LoopingCall(self.peer_maintenance_loop)
|
||||
self._peer_maintenance_loop = self._peer_maintenance.start(10)
|
||||
self._peer_maintenance_loop = self._peer_maintenance.start(CONFIG['GLOBAL']['PING_TIME'])
|
||||
|
||||
def peer_maintenance_loop(self):
|
||||
if self._stats['CONNECTION'] == 'NO':
|
||||
self.send_packet(RPTL+self._config['RADIO_ID'])
|
||||
self._stats['PINGS_SENT'] = 0
|
||||
self._stats['PINGS_ACKD'] = 0
|
||||
self._stats['CONNECTION'] = 'RTPL_SENT'
|
||||
self.send_packet('RPTL'+self._config['RADIO_ID'])
|
||||
logger.debug('(%s) Sending login request to master', self._client)
|
||||
if self._stats['CONNECTION'] == 'YES':
|
||||
self.send_packet('RPTPING'+self._config['RADIO_ID'])
|
||||
logger.debug('(%s) Ping Sent to Master', self._client)
|
||||
self._stats['PINGS_SENT'] += 1
|
||||
logger.info('(%s) RPTPING Sent to Master. Total Pings Since Connected: %s', self._client, self._stats['PINGS_SENT'])
|
||||
|
||||
def send_packet(self, _packet):
|
||||
self.transport.write(_packet, (self._config['MASTER_IP'], self._config['MASTER_PORT']))
|
||||
# KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!!
|
||||
logger.debug('(%s) TX Packet to %s on port %s: %s', self._client, self._config['MASTER_IP'], self._config['MASTER_PORT'], h(_packet))
|
||||
#logger.debug('(%s) TX Packet to %s on port %s: %s', self._client, self._config['MASTER_IP'], self._config['MASTER_PORT'], h(_packet))
|
||||
|
||||
def datagramReceived(self, _data, (_host, _port)):
|
||||
|
||||
_command = _data[:4]
|
||||
if _command == 'DMRD': # DMRData -- encapsulated DMR data frame
|
||||
print('DMRD Received')
|
||||
logger.debug('(%s) DMRD Received', self._client)
|
||||
|
||||
elif _command == 'MSTN': # Actually MSTNAK -- a NACK from the master
|
||||
print('MSTNAC Received')
|
||||
print('(%s) MSTNAC Received', self._client)
|
||||
self._stats['CONNECTION'] = 'NO'
|
||||
|
||||
elif _command == 'RPTA': # Actually RPTACK -- an ACK from the master
|
||||
if self._stats['CONNECTION'] == 'RTPL_SENT':
|
||||
@ -141,7 +152,7 @@ class HBCLIENT(DatagramProtocol):
|
||||
elif self._stats['CONNECTION'] == 'AUTHENTICATED':
|
||||
if _data[6:10] == self._config['RADIO_ID']:
|
||||
logger.info('(%s) Repeater Authentication Accepted', self._client)
|
||||
_config_packet = str(int(h(self._config['RADIO_ID']), 16)).rjust(8)+\
|
||||
_config_packet = self._config['RADIO_ID']+\
|
||||
self._config['CALLSIGN']+\
|
||||
self._config['RX_FREQ']+\
|
||||
self._config['TX_FREQ']+\
|
||||
@ -152,30 +163,34 @@ class HBCLIENT(DatagramProtocol):
|
||||
self._config['HEIGHT']+\
|
||||
self._config['LOCATION']+\
|
||||
self._config['DESCRIPTION']+\
|
||||
self._config['SLOTS']+\
|
||||
self._config['URL']+\
|
||||
self._config['SOFTWARE_ID']+\
|
||||
self._config['PACKAGE_ID']
|
||||
|
||||
self.send_packet('RPTC'+_config_packet)
|
||||
print(len('RPTC'+_config_packet))
|
||||
self._stats['CONNECTION'] = 'CONFIG-SENT'
|
||||
logger.info('(%s) Repeater Configuration Sent', self._client)
|
||||
|
||||
elif self._stats['CONNECTION'] == 'CONFIG-SENT':
|
||||
if _data[6:10] == self._config['RADIO_ID']:
|
||||
logger.info('(%s) Repeater Configuration Accepted', self._client)
|
||||
self._stats['CONNECTION'] = 'YES'
|
||||
logger.info('(%s) Connection to Master Completed', self._client)
|
||||
|
||||
elif _command == 'MSTP': # Actually MSTPONG -- a reply to RPTPING (send by client)
|
||||
print('MSTPONG Received')
|
||||
self._stats['PINGS_ACKD'] += 1
|
||||
logger.info('(%s) MSTPONG Received. Total Pongs Since Connected: %s', self._client, self._stats['PINGS_ACKD'])
|
||||
|
||||
elif _command == 'MSTC': # Actually MSTCL -- notify the master this client is closing
|
||||
print('MSTCL Recieved')
|
||||
elif _command == 'MSTC': # Actually MSTCL -- notify us the master is closing down
|
||||
self._stats['CONNECTION'] = 'NO'
|
||||
logger.info('(%s) MSTCL Recieved', self._client)
|
||||
|
||||
else:
|
||||
logger.error('(%s) Received an invalid command in packet: %s', self._client, h(_data))
|
||||
|
||||
|
||||
print('Received Packet:', h(_data))
|
||||
#print('Received Packet:', h(_data))
|
||||
|
||||
|
||||
#************************************************
|
||||
|
Loading…
x
Reference in New Issue
Block a user