falconia has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmocore/+/37797?usp=email )
Change subject: tests: add unit test for osmo_hr_sid_classify() ......................................................................
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