<p>neels has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-dev/+/15074">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add sysmobts-calib.py<br><br>Change-Id: I0cb372bddd115246ad1822dc06d318815387e8a4<br>---<br>A sysmobts-calib.py<br>1 file changed, 176 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-dev refs/changes/74/15074/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/sysmobts-calib.py b/sysmobts-calib.py</span><br><span>new file mode 100755</span><br><span>index 0000000..9551fb2</span><br><span>--- /dev/null</span><br><span>+++ b/sysmobts-calib.py</span><br><span>@@ -0,0 +1,176 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/usr/bin/env python3</span><br><span style="color: hsl(120, 100%, 40%);">+doc = '''Remotely do a clock calibration of a sysmoBTS. All you need is ssh root access to the BTS.'''</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+import sys</span><br><span style="color: hsl(120, 100%, 40%);">+import subprocess</span><br><span style="color: hsl(120, 100%, 40%);">+import re</span><br><span style="color: hsl(120, 100%, 40%);">+import shlex</span><br><span style="color: hsl(120, 100%, 40%);">+import argparse</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class Globals:</span><br><span style="color: hsl(120, 100%, 40%);">+    orig_calib_val = None</span><br><span style="color: hsl(120, 100%, 40%);">+    calib_val = None</span><br><span style="color: hsl(120, 100%, 40%);">+    bts = 'bts0'</span><br><span style="color: hsl(120, 100%, 40%);">+    band = '900'</span><br><span style="color: hsl(120, 100%, 40%);">+    arfcn = None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def error(*msgs):</span><br><span style="color: hsl(120, 100%, 40%);">+    sys.stderr.write(''.join(str(m) for m in msgs))</span><br><span style="color: hsl(120, 100%, 40%);">+    sys.stderr.write('\n')</span><br><span style="color: hsl(120, 100%, 40%);">+    exit(1)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def log(*msgs):</span><br><span style="color: hsl(120, 100%, 40%);">+    print(''.join(str(m) for m in msgs))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def cmd_to_str(cmd):</span><br><span style="color: hsl(120, 100%, 40%);">+    return ' '.join(shlex.quote(c) for c in cmd)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def call_output(*cmd):</span><br><span style="color: hsl(120, 100%, 40%);">+    cmd = ('ssh', Globals.bts,) + cmd</span><br><span style="color: hsl(120, 100%, 40%);">+    log('+ %s' % cmd_to_str(cmd))</span><br><span style="color: hsl(120, 100%, 40%);">+    sys.stdout.flush()</span><br><span style="color: hsl(120, 100%, 40%);">+    sys.stderr.flush()</span><br><span style="color: hsl(120, 100%, 40%);">+    p = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)</span><br><span style="color: hsl(120, 100%, 40%);">+    o,e = p.communicate()</span><br><span style="color: hsl(120, 100%, 40%);">+    return o.decode('utf-8')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def call(*cmd):</span><br><span style="color: hsl(120, 100%, 40%);">+    o = call_output(*cmd)</span><br><span style="color: hsl(120, 100%, 40%);">+    if o:</span><br><span style="color: hsl(120, 100%, 40%);">+        log(o)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def reload_dsp():</span><br><span style="color: hsl(120, 100%, 40%);">+    #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'")</span><br><span style="color: hsl(120, 100%, 40%);">+    # systemd service contains the DSP reload commands in the ExecStopPost.</span><br><span style="color: hsl(120, 100%, 40%);">+    # So starting and stopping the service is the easy way to reload the DSP.</span><br><span style="color: hsl(120, 100%, 40%);">+    call('systemctl', 'start', 'osmo-bts-sysmo')</span><br><span style="color: hsl(120, 100%, 40%);">+    call('systemctl', 'stop', 'osmo-bts-sysmo')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def get_cfg_calib_val():</span><br><span style="color: hsl(120, 100%, 40%);">+    o = call_output('grep', 'clock-calibration', '/etc/osmocom/osmo-bts-sysmo.cfg')</span><br><span style="color: hsl(120, 100%, 40%);">+    if not o:</span><br><span style="color: hsl(120, 100%, 40%);">+        return None</span><br><span style="color: hsl(120, 100%, 40%);">+    o = o.strip()</span><br><span style="color: hsl(120, 100%, 40%);">+    calib_val_re = re.compile(r'clock-calibration +([0-9]+)')</span><br><span style="color: hsl(120, 100%, 40%);">+    m = calib_val_re.match(o)</span><br><span style="color: hsl(120, 100%, 40%);">+    if not m:</span><br><span style="color: hsl(120, 100%, 40%);">+        return None</span><br><span style="color: hsl(120, 100%, 40%);">+    return m.group(1)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def set_cfg_calib_val(calib_val):</span><br><span style="color: hsl(120, 100%, 40%);">+    if get_cfg_calib_val() is None:</span><br><span style="color: hsl(120, 100%, 40%);">+        call('sed', '-i', "'s/^ instance 0$/&\\n  clock-calibration %s/'" % calib_val, '/etc/osmocom/osmo-bts-sysmo.cfg');</span><br><span style="color: hsl(120, 100%, 40%);">+    else:</span><br><span style="color: hsl(120, 100%, 40%);">+        call('sed', '-i', "'s/clock-calibration.*$/clock-calibration %s/'" % calib_val, '/etc/osmocom/osmo-bts-sysmo.cfg');</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    now = get_cfg_calib_val()</span><br><span style="color: hsl(120, 100%, 40%);">+    if now != calib_val:</span><br><span style="color: hsl(120, 100%, 40%);">+        print('Failed to set calibration value, set manually in osmo-bts-sysmo.cfg')</span><br><span style="color: hsl(120, 100%, 40%);">+        print('phy 0\n instance 0\n  clock-calibration %s' % calib_val)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def ask(*question, valid_answers=('*',)):</span><br><span style="color: hsl(120, 100%, 40%);">+    while True:</span><br><span style="color: hsl(120, 100%, 40%);">+        print('\n' + '\n  '.join(question))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        answer = sys.stdin.readline().strip()</span><br><span style="color: hsl(120, 100%, 40%);">+        for v in valid_answers:</span><br><span style="color: hsl(120, 100%, 40%);">+            if v == answer:</span><br><span style="color: hsl(120, 100%, 40%);">+                return answer</span><br><span style="color: hsl(120, 100%, 40%);">+            if v == '*':</span><br><span style="color: hsl(120, 100%, 40%);">+                return answer</span><br><span style="color: hsl(120, 100%, 40%);">+            if v == '+' and len(answer):</span><br><span style="color: hsl(120, 100%, 40%);">+                return answer</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def call_sysmobts_calib(mode, *args):</span><br><span style="color: hsl(120, 100%, 40%);">+    o = call_output('sysmobts-calib', '-c', 'ocxo', '-s', 'netlisten', '-b', Globals.band, '-i', Globals.calib_val, '-m', mode, *args)</span><br><span style="color: hsl(120, 100%, 40%);">+    log(o)</span><br><span style="color: hsl(120, 100%, 40%);">+    reload_dsp()</span><br><span style="color: hsl(120, 100%, 40%);">+    return o</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+if __name__ == '__main__':</span><br><span style="color: hsl(120, 100%, 40%);">+    parser = argparse.ArgumentParser(description=doc)</span><br><span style="color: hsl(120, 100%, 40%);">+    parser.add_argument('-b', '--band', dest='band', default=None,</span><br><span style="color: hsl(120, 100%, 40%);">+                        help='Which GSM band to scan and calibrate to (850, 900, 1800, 1900)')</span><br><span style="color: hsl(120, 100%, 40%);">+    parser.add_argument('-a', '--arfcn', dest='arfcn', default=None,</span><br><span style="color: hsl(120, 100%, 40%);">+                        help="Don't scan, directly use this ARFCN to calibrate to")</span><br><span style="color: hsl(120, 100%, 40%);">+    parser.add_argument('-i', '--initial-clock-correction', dest='calib_val', default=None,</span><br><span style="color: hsl(120, 100%, 40%);">+                        help='Clock calibration value to start out with. If omitted, this is obtained from'</span><br><span style="color: hsl(120, 100%, 40%);">+                        '/etc/osmocom/osmo-bts-sysmo.cfg from the BTS file system.')</span><br><span style="color: hsl(120, 100%, 40%);">+    parser.add_argument('-I', '--set-clock-correction', dest='set_calib_val', default=None,</span><br><span style="color: hsl(120, 100%, 40%);">+                        help="Don't scan or calibrate, just set the given value in the config file")</span><br><span style="color: hsl(120, 100%, 40%);">+    parser.add_argument('-G', '--get-clock-correction', dest='get_calib_val', default=False, action='store_true',</span><br><span style="color: hsl(120, 100%, 40%);">+                        help="Don't scan or calibrate, just read the given value in the config file")</span><br><span style="color: hsl(120, 100%, 40%);">+    parser.add_argument('args', nargs=1, help='Hostname (SSH) to reach the BTS at')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    cmdline = parser.parse_args()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    Globals.bts = cmdline.args[0]</span><br><span style="color: hsl(120, 100%, 40%);">+    if cmdline.band:</span><br><span style="color: hsl(120, 100%, 40%);">+        Globals.band = cmdline.band</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if cmdline.set_calib_val:</span><br><span style="color: hsl(120, 100%, 40%);">+        set_cfg_calib_val(cmdline.set_calib_val)</span><br><span style="color: hsl(120, 100%, 40%);">+        exit(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if cmdline.get_calib_val:</span><br><span style="color: hsl(120, 100%, 40%);">+        print(get_cfg_calib_val())</span><br><span style="color: hsl(120, 100%, 40%);">+        exit(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    Globals.orig_calib_val = cmdline.calib_val</span><br><span style="color: hsl(120, 100%, 40%);">+    if Globals.orig_calib_val is None:</span><br><span style="color: hsl(120, 100%, 40%);">+        Globals.orig_calib_val = get_cfg_calib_val() or '0'</span><br><span style="color: hsl(120, 100%, 40%);">+    Globals.calib_val = Globals.orig_calib_val</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    print('Starting out with clock calibration value %s' % Globals.calib_val)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    #call('systemctl', 'stop', 'osmo-bts-sysmo')</span><br><span style="color: hsl(120, 100%, 40%);">+    reload_dsp()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if cmdline.arfcn:</span><br><span style="color: hsl(120, 100%, 40%);">+        Globals.arfcn = cmdline.arfcn</span><br><span style="color: hsl(120, 100%, 40%);">+    else:</span><br><span style="color: hsl(120, 100%, 40%);">+        arfcns = call_sysmobts_calib('scan')</span><br><span style="color: hsl(120, 100%, 40%);">+        best_arfcn_line = arfcns.splitlines()[-1]</span><br><span style="color: hsl(120, 100%, 40%);">+        Globals.arfcn = best_arfcn_line.split(':')[0].split(' ')[-1]</span><br><span style="color: hsl(120, 100%, 40%);">+        try:</span><br><span style="color: hsl(120, 100%, 40%);">+            int(Globals.arfcn)</span><br><span style="color: hsl(120, 100%, 40%);">+        except:</span><br><span style="color: hsl(120, 100%, 40%);">+            error('Error while scanning bands')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    print('Using ARFCN %r' % Globals.arfcn)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    collected_values = []</span><br><span style="color: hsl(120, 100%, 40%);">+    result_re = re.compile('The calibration value is: ([0-9]*)')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    for i in range(7):</span><br><span style="color: hsl(120, 100%, 40%);">+        print('\nround %d' % (i+1))</span><br><span style="color: hsl(120, 100%, 40%);">+        o = call_sysmobts_calib('calibrate', '-a', Globals.arfcn)</span><br><span style="color: hsl(120, 100%, 40%);">+        for m in result_re.finditer(o):</span><br><span style="color: hsl(120, 100%, 40%);">+            collected_values.append(int(m.group(1)))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        collected_values = list(sorted(collected_values))</span><br><span style="color: hsl(120, 100%, 40%);">+        print(collected_values)</span><br><span style="color: hsl(120, 100%, 40%);">+        if not collected_values:</span><br><span style="color: hsl(120, 100%, 40%);">+            continue</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        best_values = collected_values</span><br><span style="color: hsl(120, 100%, 40%);">+        if len(best_values) > 3:</span><br><span style="color: hsl(120, 100%, 40%);">+            best_values = best_values[1:-1]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        avg = sum(best_values) / len(best_values)</span><br><span style="color: hsl(120, 100%, 40%);">+        Globals.calib_val = str(int(avg))</span><br><span style="color: hsl(120, 100%, 40%);">+        print('clock-calibration: started with %s,  current=%s' %</span><br><span style="color: hsl(120, 100%, 40%);">+              (Globals.orig_calib_val, Globals.calib_val))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    print('RESULT:', Globals.calib_val, ' (was %s)' % Globals.orig_calib_val)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    cfg_calib_val = get_cfg_calib_val()</span><br><span style="color: hsl(120, 100%, 40%);">+    if Globals.calib_val != cfg_calib_val:</span><br><span style="color: hsl(120, 100%, 40%);">+        a = ask('osmo-bts-sysmo.cfg currently has %s\nmodify osmo-bts-sysmo.cfg to clock-calibration %s? (ok, no)'</span><br><span style="color: hsl(120, 100%, 40%);">+                % (cfg_calib_val, Globals.calib_val),</span><br><span style="color: hsl(120, 100%, 40%);">+                valid_answers=('ok', 'no', ''))</span><br><span style="color: hsl(120, 100%, 40%);">+        if a == 'ok':</span><br><span style="color: hsl(120, 100%, 40%);">+            set_cfg_calib_val(Globals.calib_val)</span><br><span style="color: hsl(120, 100%, 40%);">+    call('systemctl', 'start', 'osmo-bts-sysmo')</span><br><span style="color: hsl(120, 100%, 40%);">+# vim: shiftwidth=4 expandtab tabstop=4</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-dev/+/15074">change 15074</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-dev/+/15074"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-dev </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I0cb372bddd115246ad1822dc06d318815387e8a4 </div>
<div style="display:none"> Gerrit-Change-Number: 15074 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>