-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Change-Id: I0cb372bddd115246ad1822dc06d318815387e8a4
- Loading branch information
Showing
1 changed file
with
200 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |