aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax <msuraev@sysmocom.de>2016-10-19 19:07:12 +0200
committerMax <msuraev@sysmocom.de>2016-10-26 17:33:55 +0200
commit64a2bd72f591a27105d94c4f860886e17e16d44a (patch)
treea45c1b0140921af507c00c4d49d527a688220c82
parentced9a5d0e2c7e3371760f1c07df7b41cfe7ab71d (diff)
Add tools to check DTX operation
* superfemto.sh can parse superfemto-compatible DSP log output to properly sort records into MT/MO and DL/UL parts * dtx_check.gawk can process output of superfemto.sh and check for common scheduling errors This allows to check lc15 and sysmo for errors in DTX DL scheduling. As dtx_check.gawk is generic it can be used with any other BTS hw (or virtual BTS) as long as raw logs from this hw can be converted to simple input format 'FN EVENT' per-line. Change-Id: Ib1c70c4543b24c2a05a7df8eec5ce3f4eda2c02e Related: OS#1801
-rwxr-xr-xcontrib/dtx_check.gawk77
-rwxr-xr-xcontrib/superfemto.sh99
2 files changed, 176 insertions, 0 deletions
diff --git a/contrib/dtx_check.gawk b/contrib/dtx_check.gawk
new file mode 100755
index 00000000..9e753e46
--- /dev/null
+++ b/contrib/dtx_check.gawk
@@ -0,0 +1,77 @@
+#!/usr/bin/gawk -f
+
+# Expected input format: FN TYPE
+
+BEGIN {
+ DELTA = 0
+ ERR = 0
+ FORCE = 0
+ FN = 0
+ SILENCE = 0
+ TYPE = ""
+ CHK = ""
+ U_MAX = 8 * 20 + 120 / 26
+ U_MIN = 8 * 20 - 120 / 26
+ F_MAX = 3 * 20 + 120 / 26
+ F_MIN = 3 * 20 - 120 / 26
+}
+
+{
+ if (NR > 2) { # we have data from previous record to compare to
+ DELTA = ($1 - FN) * 120 / 26
+ CHK = "OK"
+ if ("FACCH" == $2 && "ONSET" == TYPE) { # ONSET due to FACCH is NOT a talkspurt
+ SILENCE = 1
+ }
+ if (("UPDATE" == TYPE || "FIRST" == TYPE) && ("FACCH" == $2 || "SPEECH" == $2)) { # check for missing ONSET:
+ CHK = "FAIL: missing ONSET (" $2 ") after " TYPE "."
+ ERR++
+ }
+ if ("FORCED_FIRST" == $2 || "FORCED_NODATA" == $2) {
+ CHK = "FAIL: event " $2 " inserted by DSP."
+ FORCE++
+ ERR++
+ }
+ if ("OK" == CHK) { # check inter-SID distances:
+ if ("UPDATE" == TYPE) {
+ if (DELTA > U_MAX) {
+ CHK = "FAIL: delta (" $1 - FN "fn) from previous SID UPDATE (@" FN ") too big " DELTA "ms > " U_MAX "ms."
+ ERR++
+ }
+ if ("UPDATE" == $2 && DELTA < U_MIN) {
+ CHK = "FAIL: delta (" $1 - FN "fn) from previous SID UPDATE (@" FN ") too small " DELTA "ms < " U_MIN "ms."
+ ERR++
+ }
+ }
+ if ("FIRST" == TYPE) {
+ if (DELTA > F_MAX) {
+ CHK = "FAIL: delta (" $1 - FN "fn) from previous SID FIRST (@" FN ") too big " DELTA "ms > " F_MAX "ms."
+ ERR++
+ }
+ if ("UPDATE" == $2 && DELTA < F_MIN) {
+ CHK = "FAIL: delta (" $1 - FN "fn) from previous SID UPDATE (@" FN ") too small " DELTA "ms < " F_MIN "ms."
+ ERR++
+ }
+ }
+ }
+ if ("FACCH" == TYPE && "FIRST" != $2 && 1 == SILENCE) { # check FACCH handling
+ CHK = "FAIL: incorrect silence resume after FACCH."
+ ERR++
+ }
+ }
+ if ("SPEECH" == $2 || "ONSET" == $2) { # talkspurt
+ SILENCE = 0
+ }
+ if ("UPDATE" == $2 || "FIRST" == $2) { # silence
+ SILENCE = 1
+ }
+ print $1, $2, CHK, TYPE, DELTA, SILENCE
+ if ($2 != "EMPTY") { # skip over EMPTY records
+ TYPE = $2
+ FN = $1
+ }
+}
+
+END {
+ print "Check completed: found " ERR " errors (" FORCE " events inserted by DSP) in " NR " records."
+}
diff --git a/contrib/superfemto.sh b/contrib/superfemto.sh
new file mode 100755
index 00000000..cb871c03
--- /dev/null
+++ b/contrib/superfemto.sh
@@ -0,0 +1,99 @@
+#!/bin/sh
+
+# Split common DSP call log file (produced by superfemto-compatible firmware) into 4 separate call leg files (MO/MT & DL/UL) with events in format "FN EVENT_TYPE":
+# MO Mobile Originated
+# MT Mobile Terminated
+# DL DownLink (BTS -> L1)
+# UL UpLink (L1 -> BTS)
+
+if [ -z $1 ]; then
+ echo "expecting DSP log file name as parameter"
+ exit 1
+fi
+
+# MO handle appear 1st in the logs
+MO=$(grep 'h=' $1 | head -n 1 | cut -f2 -d',' | cut -f2 -d= | cut -f1 -d']')
+
+# direction markers:
+DLST="_CodeBurst"
+ULST="_DecodeAndIdentify"
+
+# DL sed filters:
+D_EMP='s/ Empty frame request!/EMPTY/'
+D_FAC='s/ Coding a FACCH\/F frame !!/FACCH/'
+D_FST='s/ Coding a RTP SID First frame !!/FIRST/'
+D_UPD='s/ Coding a RTP SID Update frame !!/UPDATE/'
+D_SPE='s/ Coding a RTP Speech frame !!/SPEECH/'
+D_ONS='s/ Coding a Onset frame !!/ONSET/'
+D_FO1='s/ A speech frame is following a NoData or SID First without an Onset./FORCED_FIRST/'
+D_FO2='s/ A speech frame is following a NoData without an Onset./FORCED_NODATA/'
+
+# UL sed filters:
+U_NOD='s/ It is a No Data frame !!/NODATA/'
+U_ONS='s/ It is an ONSET frame !!/ONSET/'
+U_UPD='s/ It is a SID UPDATE frame !!/UPDATE/'
+U_FST='s/ It is a SID FIRST frame !!/FIRST/'
+U_SPE='s/ It is a SPEECH frame !!/SPEECH/'
+
+DL () { # filter downlink-related entries
+ grep $DLST $1 > $1.DL.tmp
+}
+
+UL () { # uplink does not require special fix
+ grep $ULST $1 > $1.UL.tmp.fix
+}
+
+DL $1
+UL $1
+
+FIX() { # add MO/MT marker from preceding line to inserted ONSETs so filtering works as expected
+ cat $1.DL.tmp | awk 'BEGIN{ FS="h="; H="" } { if (NF > 1) { H = $2; print $1 "h=" $2 } else { print $1 ", h=" H } }' > $1.DL.tmp.fix
+}
+
+FIX $1
+
+MO() { # filter MO call DL or UL logs
+ grep "h=$MO" $1.tmp.fix > $1.MO.raw
+}
+
+MT() { # filter MT call DL or UL logs
+ grep -v "h=$MO" $1.tmp.fix > $1.MT.raw
+}
+
+MO $1.DL
+MT $1.DL
+MO $1.UL
+MT $1.UL
+
+PREP() { # prepare logs for reformatting
+ cat $1.raw | cut -f2 -d')' | cut -f1 -d',' | cut -f2 -d'>' | sed 's/\[u32Fn/fn/' | sed 's/fn = /fn=/' | sed 's/fn=//' | sed 's/\[Fn=//' | sed 's/ An Onset will be inserted.//' > $1.tmp1
+}
+
+PREP "$1.DL.MT"
+PREP "$1.DL.MO"
+PREP "$1.UL.MT"
+PREP "$1.UL.MO"
+
+RD() { # reformat DL logs for consistency checks
+ cat $1.tmp1 | sed "$D_FST" | sed "$D_SPE" | sed "$D_UPD" | sed "$D_ONS" | sed "$D_EMP" | sed "$D_FAC" | sed "$D_FO1" | sed "$D_FO2" > $1.tmp2
+}
+
+RU() { # reformat UL logs for consistency checks
+ cat $1.tmp1 | sed "$U_FST" | sed "$U_SPE" | sed "$U_UPD" | sed "$U_ONS" | sed "$U_NOD" > $1.tmp2
+}
+
+RD "$1.DL.MT"
+RD "$1.DL.MO"
+RU "$1.UL.MT"
+RU "$1.UL.MO"
+
+SW() { # swap fields
+ cat $1.tmp2 | awk '{ print $2, $1 }' > $1
+}
+
+SW "$1.DL.MT"
+SW "$1.DL.MO"
+SW "$1.UL.MT"
+SW "$1.UL.MO"
+
+rm $1.*.tmp*