mirror of https://gerrit.osmocom.org/osmo-dev
add sysmobts-calib.py
Change-Id: I0cb372bddd115246ad1822dc06d318815387e8a4
This commit is contained in:
parent
0ec459258a
commit
eb446fe27f
|
@ -0,0 +1,200 @@
|
|||
#!/usr/bin/env python3
|
||||
doc = '''Remotely do a clock calibration of a sysmoBTS.
|
||||
|
||||
You need is ssh root access to the BTS, and an antenna connected to the NWL.
|
||||
|
||||
Remotely goes through the steps to obtain a OCXO calibration value from netlisten.
|
||||
- Obtain the current calibration value from /etc/osmocom/osmo-bts-sysmo.cfg.
|
||||
- Stop the osmo-bts-sysmo.service.
|
||||
- Do a scan to get the strongest received ARFCN.
|
||||
- Run n passes of sysmobts-calib (default: 7) to obtain an average calibration val.
|
||||
- Write this calibration value back to /etc/osmocom/osmo-bts-sysmo.cfg.
|
||||
- Start osmo-bts-sysmo.service.
|
||||
'''
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import re
|
||||
import shlex
|
||||
import argparse
|
||||
|
||||
calib_val_re = re.compile(r'clock-calibration +([0-9]+)')
|
||||
result_re = re.compile('The calibration value is: ([0-9]*)')
|
||||
|
||||
class Globals:
|
||||
orig_calib_val = None
|
||||
calib_val = None
|
||||
bts = 'bts0'
|
||||
band = '900'
|
||||
arfcn = None
|
||||
|
||||
def error(*msgs):
|
||||
sys.stderr.write(''.join(str(m) for m in msgs))
|
||||
sys.stderr.write('\n')
|
||||
exit(1)
|
||||
|
||||
def log(*msgs):
|
||||
print(''.join(str(m) for m in msgs))
|
||||
|
||||
def cmd_to_str(cmd):
|
||||
return ' '.join(shlex.quote(c) for c in cmd)
|
||||
|
||||
def call_output(*cmd):
|
||||
cmd = ('ssh', Globals.bts,) + cmd
|
||||
log('+ %s' % cmd_to_str(cmd))
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
p = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
|
||||
o,e = p.communicate()
|
||||
return o.decode('utf-8')
|
||||
|
||||
def call(*cmd):
|
||||
o = call_output(*cmd)
|
||||
if o:
|
||||
log(o)
|
||||
|
||||
def reload_dsp():
|
||||
#call('/bin/sh', '-c', r"'cat /lib/firmware/sysmobts-v?.bit > /dev/fpgadl_par0 ; sleep 3s; cat /lib/firmware/sysmobts-v?.out > /dev/dspdl_dm644x_0; sleep 1s'")
|
||||
# systemd service contains the DSP reload commands in the ExecStopPost.
|
||||
# So starting and stopping the service is the easy way to reload the DSP.
|
||||
call('systemctl', 'start', 'osmo-bts-sysmo')
|
||||
call('systemctl', 'stop', 'osmo-bts-sysmo')
|
||||
|
||||
def get_cfg_calib_val():
|
||||
o = call_output('grep', 'clock-calibration', '/etc/osmocom/osmo-bts-sysmo.cfg')
|
||||
if not o:
|
||||
return None
|
||||
o = o.strip()
|
||||
m = calib_val_re.match(o)
|
||||
if not m:
|
||||
return None
|
||||
return m.group(1)
|
||||
|
||||
def set_cfg_calib_val(calib_val):
|
||||
if get_cfg_calib_val() is None:
|
||||
call('sed', '-i', "'s/^ instance 0$/&\\n clock-calibration %s/'" % calib_val, '/etc/osmocom/osmo-bts-sysmo.cfg');
|
||||
else:
|
||||
call('sed', '-i', "'s/clock-calibration.*$/clock-calibration %s/'" % calib_val, '/etc/osmocom/osmo-bts-sysmo.cfg');
|
||||
|
||||
now = get_cfg_calib_val()
|
||||
if now != calib_val:
|
||||
print('Failed to set calibration value, set manually in osmo-bts-sysmo.cfg')
|
||||
print('phy 0\n instance 0\n clock-calibration %s' % calib_val)
|
||||
|
||||
|
||||
def ask(*question, valid_answers=('*',)):
|
||||
while True:
|
||||
print('\n' + '\n '.join(question))
|
||||
|
||||
answer = sys.stdin.readline().strip()
|
||||
for v in valid_answers:
|
||||
if v == answer:
|
||||
return answer
|
||||
if v == '*':
|
||||
return answer
|
||||
if v == '+' and len(answer):
|
||||
return answer
|
||||
|
||||
def call_sysmobts_calib(mode, *args):
|
||||
o = call_output('sysmobts-calib', '-c', 'ocxo', '-s', 'netlisten', '-b', Globals.band, '-i', Globals.calib_val, '-m', mode, *args)
|
||||
log(o)
|
||||
reload_dsp()
|
||||
return o
|
||||
|
||||
def int_be_one(string):
|
||||
val = int(string)
|
||||
if val < 1:
|
||||
raise argparse.ArgumentTypeError('value must be at least 1')
|
||||
return val
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description=doc)
|
||||
parser.add_argument('-b', '--band', dest='band', default=None,
|
||||
help='Which GSM band to scan and calibrate to (850, 900, 1800, 1900)')
|
||||
parser.add_argument('-a', '--arfcn', dest='arfcn', default=None,
|
||||
help="Don't scan, directly use this ARFCN to calibrate to")
|
||||
parser.add_argument('-i', '--initial-clock-correction', dest='calib_val', default=None,
|
||||
help='Clock calibration value to start out with. If omitted, this is obtained from'
|
||||
' /etc/osmocom/osmo-bts-sysmo.cfg from the BTS file system.')
|
||||
parser.add_argument('-I', '--set-clock-correction', dest='set_calib_val', default=None,
|
||||
help="Don't scan or calibrate, just set the given value in the config file")
|
||||
parser.add_argument('-G', '--get-clock-correction', dest='get_calib_val', default=False, action='store_true',
|
||||
help="Don't scan or calibrate, just read the given value in the config file")
|
||||
parser.add_argument('-n', '--passes', dest='passes', default=7, type=int_be_one,
|
||||
help="How many times to run sysmobts-calib to obtain a resulting calibration value average")
|
||||
parser.add_argument('args', nargs=1, help='Hostname (SSH) to reach the BTS at')
|
||||
|
||||
cmdline = parser.parse_args()
|
||||
|
||||
Globals.bts = cmdline.args[0]
|
||||
if cmdline.band:
|
||||
Globals.band = cmdline.band
|
||||
|
||||
if cmdline.set_calib_val:
|
||||
set_cfg_calib_val(cmdline.set_calib_val)
|
||||
exit(0)
|
||||
|
||||
if cmdline.get_calib_val:
|
||||
print(get_cfg_calib_val())
|
||||
exit(0)
|
||||
|
||||
Globals.orig_calib_val = cmdline.calib_val
|
||||
if Globals.orig_calib_val is None:
|
||||
Globals.orig_calib_val = get_cfg_calib_val() or '0'
|
||||
Globals.calib_val = Globals.orig_calib_val
|
||||
|
||||
print('Starting out with clock calibration value %s' % Globals.calib_val)
|
||||
|
||||
#call('systemctl', 'stop', 'osmo-bts-sysmo')
|
||||
reload_dsp()
|
||||
|
||||
if cmdline.arfcn:
|
||||
Globals.arfcn = cmdline.arfcn
|
||||
else:
|
||||
arfcns = call_sysmobts_calib('scan')
|
||||
best_arfcn_line = arfcns.splitlines()[-1]
|
||||
Globals.arfcn = best_arfcn_line.split(':')[0].split(' ')[-1]
|
||||
try:
|
||||
int(Globals.arfcn)
|
||||
except:
|
||||
error('Error while scanning bands')
|
||||
|
||||
print('Using ARFCN %r' % Globals.arfcn)
|
||||
|
||||
collected_values = []
|
||||
|
||||
passes = cmdline.passes
|
||||
if passes < 1:
|
||||
passes = 1
|
||||
|
||||
for i in range(passes):
|
||||
print('\npass %d of %d' % (i+1, passes))
|
||||
o = call_sysmobts_calib('calibrate', '-a', Globals.arfcn)
|
||||
for m in result_re.finditer(o):
|
||||
collected_values.append(int(m.group(1)))
|
||||
|
||||
collected_values = list(sorted(collected_values))
|
||||
print(collected_values)
|
||||
if not collected_values:
|
||||
continue
|
||||
|
||||
best_values = collected_values
|
||||
if len(best_values) > 3:
|
||||
best_values = best_values[1:-1]
|
||||
|
||||
avg = sum(best_values) / len(best_values)
|
||||
Globals.calib_val = str(int(avg))
|
||||
print('clock-calibration: started with %s, current=%s' %
|
||||
(Globals.orig_calib_val, Globals.calib_val))
|
||||
|
||||
print('RESULT:', Globals.calib_val, ' (was %s)' % Globals.orig_calib_val)
|
||||
|
||||
cfg_calib_val = get_cfg_calib_val()
|
||||
if Globals.calib_val != cfg_calib_val:
|
||||
a = ask('osmo-bts-sysmo.cfg currently has %s\nmodify osmo-bts-sysmo.cfg to clock-calibration %s? (ok, no)'
|
||||
% (cfg_calib_val, Globals.calib_val),
|
||||
valid_answers=('ok', 'no', ''))
|
||||
if a == 'ok':
|
||||
set_cfg_calib_val(Globals.calib_val)
|
||||
call('systemctl', 'start', 'osmo-bts-sysmo')
|
||||
# vim: shiftwidth=4 expandtab tabstop=4
|
Loading…
Reference in New Issue