falconia has uploaded this change for review.

View Change

tests: add unit test for osmo_hr_sid_classify()

The bit patterns used to construct this unit test originate
from an experiment involving a Calypso GSM MS and a CMU200 test
instrument configured to simulate radio conditions ranging from good
to bad, as documented here:

https://osmocom.org/projects/retro-gsm/wiki/HRv1_error_flags

The resulting unit test proves correctness of osmo_hr_sid_classify()
implementation not only "against itself" and against theoretical
understanding of ETSI reference logic, but also by confirming a match
between our computed classification and that produced by TI's DSP.

Related: OS#6036
Change-Id: I9944bb7d49b6fe004d4bfc7a3f70cfdb03d62614
---
M tests/Makefile.am
A tests/codec/codec_hr_sid_test.c
A tests/codec/codec_hr_sid_test.in
A tests/codec/codec_hr_sid_test.ok
M tests/testsuite.at
5 files changed, 258 insertions(+), 1 deletion(-)

git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/97/37797/1
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 1e8997c..a222e75 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -26,7 +26,8 @@
abis/abis_test endian/endian_test sercomm/sercomm_test \
prbs/prbs_test gsm23003/gsm23003_test \
gsm23236/gsm23236_test \
- codec/codec_ecu_fr_test timer/clk_override_test \
+ codec/codec_ecu_fr_test codec/codec_hr_sid_test \
+ timer/clk_override_test \
oap/oap_client_test gsm29205/gsm29205_test \
logging/logging_vty_test \
vty/vty_transcript_test \
@@ -265,6 +266,9 @@
codec_codec_ecu_fr_test_SOURCES = codec/codec_ecu_fr_test.c
codec_codec_ecu_fr_test_LDADD = $(top_builddir)/src/codec/libosmocodec.la $(LDADD)

+codec_codec_hr_sid_test_SOURCES = codec/codec_hr_sid_test.c
+codec_codec_hr_sid_test_LDADD = $(top_builddir)/src/codec/libosmocodec.la $(LDADD)
+
loggingrb_loggingrb_test_SOURCES = loggingrb/loggingrb_test.c
loggingrb_loggingrb_test_LDADD = $(LDADD)

@@ -438,6 +442,7 @@
loggingrb/logging_test.err strrb/strrb_test.ok \
codec/codec_test.ok \
codec/codec_ecu_fr_test.ok \
+ codec/codec_hr_sid_test.ok \
vty/vty_test.ok vty/vty_test.err \
vty/fail_not_de-indented.cfg \
vty/fail_tabs_and_spaces.cfg \
@@ -598,6 +603,8 @@
>$(srcdir)/codec/codec_test.ok
codec/codec_ecu_fr_test \
>$(srcdir)/codec/codec_ecu_fr_test.ok
+ codec/codec_hr_sid_test $(srcdir)/codec/codec_hr_sid_test.in \
+ >$(srcdir)/codec/codec_hr_sid_test.ok
if ENABLE_GB
fr/fr_test \
>$(srcdir)/fr/fr_test.ok
diff --git a/tests/codec/codec_hr_sid_test.c b/tests/codec/codec_hr_sid_test.c
new file mode 100644
index 0000000..e6cdd7a
--- /dev/null
+++ b/tests/codec/codec_hr_sid_test.c
@@ -0,0 +1,143 @@
+/*
+ * This program is a test for osmo_hr_sid_classify(). It reads a set of
+ * TCH/HS Rx bit patterns in TI DSP format (originally captured from a
+ * Calypso MS under conditions of induced radio errors), converts each
+ * bit pattern to TS 101 318 format (using same bit reordering function
+ * as libosmocoding gsm0503 implementation), and feeds each test line
+ * to osmo_hr_sid_classify(). It then prints the output next to each input.
+ *
+ * Author: Mychaela N. Falconia <falcon@freecalypso.org>, 2024 - however,
+ * Mother Mychaela's contributions are NOT subject to copyright.
+ * No rights reserved, all rights relinquished.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/codec/codec.h>
+
+#define HR_CODEC_BITS (GSM_HR_BYTES * 8)
+#define HR_BYTES_TIDSP (GSM_HR_BYTES + 1)
+
+/* re-arrange according to TS 05.03 Table 3a (receiver) */
+/* function copied from src/coding/gsm0503_coding.c */
+static void tch_hr_d_to_b(ubit_t *b_bits, const ubit_t *d_bits)
+{
+ int i;
+
+ const uint16_t *map;
+
+ if (!d_bits[93] && !d_bits[94])
+ map = gsm620_unvoiced_bitorder;
+ else
+ map = gsm620_voiced_bitorder;
+
+ for (i = 0; i < 112; i++)
+ b_bits[map[i]] = d_bits[i];
+}
+
+static void process_record(const char *hex_str, bool bci_flag)
+{
+ uint8_t dsp_rx_bytes[HR_BYTES_TIDSP];
+ ubit_t bits_transmission_order[HR_BYTES_TIDSP * 8];
+ ubit_t bits_codec_order[HR_CODEC_BITS];
+ uint8_t hr_bytes_ts101318[GSM_HR_BYTES];
+ bool bfi_flag = false;
+ enum osmo_gsm631_sid_class sidc;
+
+ osmo_hexparse(hex_str, dsp_rx_bytes, HR_BYTES_TIDSP);
+ osmo_pbit2ubit(bits_transmission_order, dsp_rx_bytes,
+ HR_BYTES_TIDSP * 8);
+ /* TI DSP format has a gap of 4 bits between class 1 and class 2
+ * portions - get rid of it. 95 is the number of class 1 bits,
+ * 17 is the number of class 2 bits. */
+ memmove(bits_transmission_order + 95,
+ bits_transmission_order + 95 + 4, 17);
+ tch_hr_d_to_b(bits_codec_order, bits_transmission_order);
+ osmo_ubit2pbit(hr_bytes_ts101318, bits_codec_order, HR_CODEC_BITS);
+
+ sidc = osmo_hr_sid_classify(hr_bytes_ts101318, bci_flag, &bfi_flag);
+ printf("%s %d ==> %d %d\n", hex_str, (int) bci_flag,
+ (int) sidc, (int) bfi_flag);
+}
+
+static void process_line(char *linebuf, const char *infname, int lineno)
+{
+ char *cp = linebuf, *hex_str;
+ int ndig;
+ bool bci_flag;
+
+ while (isspace(*cp))
+ cp++;
+ if (*cp == '\0' || *cp == '#')
+ return;
+ /* expect string of 30 hex digits */
+ hex_str = cp;
+ for (ndig = 0; ndig < HR_BYTES_TIDSP * 2; ndig++) {
+ if (!isxdigit(*cp)) {
+inv: fprintf(stderr, "%s line %d: invalid syntax\n",
+ infname, lineno);
+ exit(1);
+ }
+ cp++;
+ }
+ if (!isspace(*cp))
+ goto inv;
+ *cp++ = '\0';
+ while (isspace(*cp))
+ cp++;
+ /* 0 or 1 must follow, giving BCI flag */
+ if (*cp == '0')
+ bci_flag = false;
+ else if (*cp == '1')
+ bci_flag = true;
+ else
+ goto inv;
+ cp++;
+ /* must be end of non-comment line */
+ while (isspace(*cp))
+ cp++;
+ if (*cp != '\0' && *cp != '#')
+ goto inv;
+
+ process_record(hex_str, bci_flag);
+}
+
+int main(int argc, char **argv)
+{
+ const char *infname;
+ FILE *inf;
+ char linebuf[128];
+ int lineno;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s input-file\n", argv[0]);
+ exit(1);
+ }
+ infname = argv[1];
+ inf = fopen(infname, "r");
+ if (!inf) {
+ perror(infname);
+ exit(1);
+ }
+ for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++)
+ process_line(linebuf, infname, lineno);
+ fclose(inf);
+ exit(0);
+}
diff --git a/tests/codec/codec_hr_sid_test.in b/tests/codec/codec_hr_sid_test.in
new file mode 100644
index 0000000..e8ad966
--- /dev/null
+++ b/tests/codec/codec_hr_sid_test.in
@@ -0,0 +1,61 @@
+# This file is input for the HR SID classifier test program. All TCH/HS
+# Rx bit strings contained in this file have been taken from hr-test1.dl
+# or hr-test2.dl, attached to this wiki page:
+#
+# https://osmocom.org/projects/retro-gsm/wiki/HRv1_error_flags
+#
+# Each Rx bit string (15 hex bytes) is from TI DSP; the 0 or 1 that follows
+# is the BCI flag to be fed to the SID classifier. The original DSP status
+# word is noted in the comments; running the unit test program will show
+# whether or not our SID classification agrees with that produced by
+# TI Calypso DSP.
+
+# perfect, error-free SID: hr-test2.dl line 171, C010
+FFFFFFFFFFFFFFFFFFFFFFFE1FFFF0 0
+
+# mode bits cleared to 0, all other bits still 1s
+FFFFFFFFFFFFFFFFFFFFFFF81FFFF0 0
+
+# selected error lines
+FFFFFFFFFFFFFFFFFFFFFFFE0FFF70 0 # hr-test2.dl line 4226, C010
+FFFFFFFFFFFFFFFFFFFFFFFE13FFF0 1 # hr-test2.dl line 4256, C012
+FFFFFFFFFFFFFFFFFFFFFFFE17FFF0 1 # hr-test2.dl line 4258, C012
+FFFD01FFFFFFFFFFFFFFFFFE0FFFF0 1 # hr-test2.dl line 4598, C00A
+FFFFFFFFFFFCC296452940FE1FFEF0 1 # hr-test2.dl line 5141, C00F
+FFFFFFFFFFFCC296452940FE1FFEF0 0 # same bits without BCI
+FF6E76F40C276FFFFFFFFFFE0FFFF0 1 # hr-test2.dl line 5173, C003
+FF6E76F40C276FFFFFFFFFFE0FFFF0 0 # same bits without BCI
+FFFFFFFFFDFFFFFFFFFFFFFE0FFFF0 1 # hr-test2.dl line 5206, C012
+FFFFFFFFFDFFFFFFFFFFFFFE0FFFF0 0 # same bits without BCI
+FFFFFFFFFFD0DFFFFFFFFFFE07FEF0 1 # hr-test2.dl line 5261, C00A
+FFFFFFFFFFD0DFFFFFFFFFFE07FEF0 0 # same bits without BCI
+FFFFFFFFFFFF41EAC9676FFE1F7DF0 1 # hr-test2.dl line 5738, C00F
+FFFFFFFFFFFF41EAC9676FFE1F7DF0 0 # same bits without BCI
+
+FFFFFFFFFFFF847D5B9DBFFE1937B0 1 # hr-test2.dl line 6175, C00F
+FFFFFFFFFFFF847D5B9DBFFE1937B0 0 # same bits without BCI
+FFFFFFFFFFFFFFFFFFFFFFD01FFEB0 1 # hr-test2.dl line 6188, C017
+FFFFFFFFFFFFFFFFFFFFFFD01FFEB0 0 # same bits without BCI
+FDBD7D552CB25FFFFFFFFFFE1DFBB0 1 # hr-test2.dl line 6191, C002
+FDBD7D552CB25FFFFFFFFFFE1DFBB0 0 # same bits without BCI
+FFD2F0A52B8FFFFFFFFEDE600FFDF0 1 # hr-test2.dl line 6195, C007
+FFD2F0A52B8FFFFFFFFEDE600FFDF0 0 # same bits without BCI
+FFFFFFFFCC7FFFFFFFF4EE601C31D0 1 # hr-test2.dl line 6318, C007
+FFFFFFFFCC7FFFFFFFF4EE601C31D0 0 # same bits without BCI
+FFFFFFFFFFFFFFFFFFFFA5901BEFD0 1 # hr-test2.dl line 6545, C00F
+FFFFFFFFFFFFFFFFFFFFA5901BEFD0 0 # same bits without BCI
+FFFFFFFFEA97FFFFFFE765901FFFB0 1 # hr-test2.dl line 6973, C00F
+FFFFFFFFEA97FFFFFFE765901FFFB0 0 # same bits without BCI
+
+FFFFFFFFF8C8A5E29DA0DFFE07FFF0 1 # hr-test2.dl line 7158, C00F
+FFFFFFFFF8C8A5E29DA0DFFE07FFF0 0 # same bits without BCI
+FFFD01853B7206E63FFFFFFE1FBFD0 1 # hr-test2.dl line 7175, C003
+FFFD01853B7206E63FFFFFFE1FBFD0 0 # same bits without BCI
+E6ACC7FFFF40FFFFFFFFFFFE1FF770 1 # hr-test2.dl line 7195, C00B
+E6ACC7FFFF40FFFFFFFFFFFE1FF770 0 # same bits without BCI
+
+# hr-test1.dl, PRBS without major errors
+55A5404BFAED58A3BE33A978092A40 0 # hr-test1.dl line 1051, C000
+CFE44B516ED5D1F54E4615AA101260 0 # hr-test1.dl line 2710, C000
+D7881D40AA0F68106195DCD41568C0 0 # hr-test1.dl line 4306, C000
+D4CFB4961F8F9F11313454560690E0 1 # hr-test1.dl line 4631, C002
diff --git a/tests/codec/codec_hr_sid_test.ok b/tests/codec/codec_hr_sid_test.ok
new file mode 100644
index 0000000..3ea1fed
--- /dev/null
+++ b/tests/codec/codec_hr_sid_test.ok
@@ -0,0 +1,40 @@
+FFFFFFFFFFFFFFFFFFFFFFFE1FFFF0 0 ==> 2 0
+FFFFFFFFFFFFFFFFFFFFFFF81FFFF0 0 ==> 1 0
+FFFFFFFFFFFFFFFFFFFFFFFE0FFF70 0 ==> 2 0
+FFFFFFFFFFFFFFFFFFFFFFFE13FFF0 1 ==> 2 0
+FFFFFFFFFFFFFFFFFFFFFFFE17FFF0 1 ==> 2 0
+FFFD01FFFFFFFFFFFFFFFFFE0FFFF0 1 ==> 1 0
+FFFFFFFFFFFCC296452940FE1FFEF0 1 ==> 1 0
+FFFFFFFFFFFCC296452940FE1FFEF0 0 ==> 0 0
+FF6E76F40C276FFFFFFFFFFE0FFFF0 1 ==> 0 1
+FF6E76F40C276FFFFFFFFFFE0FFFF0 0 ==> 0 0
+FFFFFFFFFDFFFFFFFFFFFFFE0FFFF0 1 ==> 2 0
+FFFFFFFFFDFFFFFFFFFFFFFE0FFFF0 0 ==> 2 0
+FFFFFFFFFFD0DFFFFFFFFFFE07FEF0 1 ==> 1 0
+FFFFFFFFFFD0DFFFFFFFFFFE07FEF0 0 ==> 1 0
+FFFFFFFFFFFF41EAC9676FFE1F7DF0 1 ==> 1 0
+FFFFFFFFFFFF41EAC9676FFE1F7DF0 0 ==> 0 0
+FFFFFFFFFFFF847D5B9DBFFE1937B0 1 ==> 1 0
+FFFFFFFFFFFF847D5B9DBFFE1937B0 0 ==> 0 0
+FFFFFFFFFFFFFFFFFFFFFFD01FFEB0 1 ==> 1 0
+FFFFFFFFFFFFFFFFFFFFFFD01FFEB0 0 ==> 1 0
+FDBD7D552CB25FFFFFFFFFFE1DFBB0 1 ==> 0 1
+FDBD7D552CB25FFFFFFFFFFE1DFBB0 0 ==> 0 0
+FFD2F0A52B8FFFFFFFFEDE600FFDF0 1 ==> 0 1
+FFD2F0A52B8FFFFFFFFEDE600FFDF0 0 ==> 0 0
+FFFFFFFFCC7FFFFFFFF4EE601C31D0 1 ==> 0 1
+FFFFFFFFCC7FFFFFFFF4EE601C31D0 0 ==> 0 0
+FFFFFFFFFFFFFFFFFFFFA5901BEFD0 1 ==> 1 0
+FFFFFFFFFFFFFFFFFFFFA5901BEFD0 0 ==> 1 0
+FFFFFFFFEA97FFFFFFE765901FFFB0 1 ==> 1 0
+FFFFFFFFEA97FFFFFFE765901FFFB0 0 ==> 0 0
+FFFFFFFFF8C8A5E29DA0DFFE07FFF0 1 ==> 1 0
+FFFFFFFFF8C8A5E29DA0DFFE07FFF0 0 ==> 0 0
+FFFD01853B7206E63FFFFFFE1FBFD0 1 ==> 0 1
+FFFD01853B7206E63FFFFFFE1FBFD0 0 ==> 0 0
+E6ACC7FFFF40FFFFFFFFFFFE1FF770 1 ==> 1 0
+E6ACC7FFFF40FFFFFFFFFFFE1FF770 0 ==> 0 0
+55A5404BFAED58A3BE33A978092A40 0 ==> 0 0
+CFE44B516ED5D1F54E4615AA101260 0 ==> 0 0
+D7881D40AA0F68106195DCD41568C0 0 ==> 0 0
+D4CFB4961F8F9F11313454560690E0 1 ==> 0 0
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 3433fb0..dbf3925 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -218,6 +218,12 @@
AT_CHECK([$abs_top_builddir/tests/codec/codec_ecu_fr_test], [0], [expout], [ignore])
AT_CLEANUP

+AT_SETUP([codec_hr_sid])
+AT_KEYWORDS([codec_hr_sid])
+cat $abs_srcdir/codec/codec_hr_sid_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/codec/codec_hr_sid_test $abs_srcdir/codec/codec_hr_sid_test.in], [0], [expout], [ignore])
+AT_CLEANUP
+
AT_SETUP([fr])
AT_KEYWORDS([fr])
cat $abs_srcdir/fr/fr_test.ok > expout

To view, visit change 37797. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: newchange
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: I9944bb7d49b6fe004d4bfc7a3f70cfdb03d62614
Gerrit-Change-Number: 37797
Gerrit-PatchSet: 1
Gerrit-Owner: falconia <falcon@freecalypso.org>