diff options
-rwxr-xr-x | contrib/dtx_check.gawk | 77 | ||||
-rwxr-xr-x | contrib/superfemto.sh | 99 |
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* |