aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac1
-rw-r--r--src/osmo-bts-trx/sched_lchan_tchf.c11
-rw-r--r--src/osmo-bts-trx/sched_lchan_tchh.c17
-rw-r--r--src/osmo-bts-trx/sched_utils.h76
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/amr/Makefile.am11
-rw-r--r--tests/amr/amr_test.c151
-rw-r--r--tests/amr/amr_test.ok152
-rw-r--r--tests/testsuite.at6
9 files changed, 416 insertions, 11 deletions
diff --git a/configure.ac b/configure.ac
index 1b4c6e78..4f2e889f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -411,6 +411,7 @@ AC_OUTPUT(
tests/tx_power/Makefile
tests/power/Makefile
tests/meas/Makefile
+ tests/amr/Makefile
doc/Makefile
doc/examples/Makefile
doc/manuals/Makefile
diff --git a/src/osmo-bts-trx/sched_lchan_tchf.c b/src/osmo-bts-trx/sched_lchan_tchf.c
index 00efcf8a..c5d60e42 100644
--- a/src/osmo-bts-trx/sched_lchan_tchf.c
+++ b/src/osmo-bts-trx/sched_lchan_tchf.c
@@ -65,6 +65,7 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
uint16_t ber10k;
uint8_t is_sub = 0;
uint8_t ft;
+ bool amr_is_cmr;
/* If handover RACH detection is turned on, treat this burst as an Access Burst.
* Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */
@@ -129,6 +130,8 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
* the first FN 4,13,21 defines that CMR is included in frame.
* NOTE: A frame ends 7 FN after start.
*/
+ fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_F);
+ amr_is_cmr = !ul_amr_fn_is_cmi(fn_begin);
/* The AFS_ONSET frame itself does not result into an RTP frame
* since it only contains a recognition pattern that marks the
@@ -144,8 +147,7 @@ int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
* know this before we actually decode the frame) */
amr = 2;
rc = gsm0503_tch_afs_decode_dtx(tch_data + amr, *bursts_p,
- (((bi->fn + 26 - 7) % 26) >> 2) & 1, chan_state->codec,
- chan_state->codecs, &chan_state->ul_ft,
+ amr_is_cmr, chan_state->codec, chan_state->codecs, &chan_state->ul_ft,
&chan_state->ul_cmr, &n_errors, &n_bits_total, &chan_state->amr_last_dtx);
/* Tag all frames that are not regular AMR voice frames as
@@ -419,6 +421,7 @@ inval_mode1:
enum osmo_amr_type ft_codec;
enum osmo_amr_quality bfi;
int8_t sti, cmi;
+ bool amr_is_cmr = !dl_amr_fn_is_cmi(br->fn);
if (rsl_cmode != RSL_CMOD_SPD_SPEECH) {
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Dropping speech frame, "
@@ -463,7 +466,7 @@ inval_mode1:
"Codec (FT = %d) of RTP frame not in list\n", ft_codec);
goto free_bad_msg;
}
- if (fn_is_codec_mode_request(br->fn) && chan_state->dl_ft != ft) {
+ if (amr_is_cmr && chan_state->dl_ft != ft) {
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Codec (FT = %d) "
" of RTP cannot be changed now, but in next frame\n", ft_codec);
goto free_bad_msg;
@@ -552,7 +555,7 @@ int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
* the first FN 0,8,17 defines that CMR is included in frame.
*/
gsm0503_tch_afs_encode(*bursts_p, msg_tch->l2h + 2,
- msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(br->fn),
+ msgb_l2len(msg_tch) - 2, !dl_amr_fn_is_cmi(br->fn),
chan_state->codec, chan_state->codecs,
chan_state->dl_ft,
chan_state->dl_cmr);
diff --git a/src/osmo-bts-trx/sched_lchan_tchh.c b/src/osmo-bts-trx/sched_lchan_tchh.c
index 94022041..2106a676 100644
--- a/src/osmo-bts-trx/sched_lchan_tchh.c
+++ b/src/osmo-bts-trx/sched_lchan_tchh.c
@@ -72,6 +72,7 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
uint8_t is_sub = 0;
uint8_t ft;
bool mask_stolen_tch_block = false;
+ bool fn_is_cmi;
/* If handover RACH detection is turned on, treat this burst as an Access Burst.
* Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */
@@ -164,10 +165,21 @@ int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
break;
}
+ /* Calculate the frame number where the block begins */
+ if (bi->fn % 13 < 4)
+ fn_tch_end = GSM_TDMA_FN_SUB(bi->fn, 5);
+ else
+ fn_tch_end = GSM_TDMA_FN_SUB(bi->fn, 4);
+ if (lchan->nr == 0)
+ fn_begin = gsm0502_fn_remap(fn_tch_end, FN_REMAP_TCH_H0);
+ else
+ fn_begin = gsm0502_fn_remap(fn_tch_end, FN_REMAP_TCH_H1);
+ fn_is_cmi = ul_amr_fn_is_cmi(fn_begin);
+
/* See comment in function rx_tchf_fn() */
amr = 2;
rc = gsm0503_tch_ahs_decode_dtx(tch_data + amr, *bursts_p,
- fn_is_odd, fn_is_odd, chan_state->codec,
+ fn_is_odd, !fn_is_cmi, chan_state->codec,
chan_state->codecs, &chan_state->ul_ft,
&chan_state->ul_cmr, &n_errors, &n_bits_total, &chan_state->amr_last_dtx);
@@ -343,7 +355,6 @@ compose_l1sap:
fn_tch_end = GSM_TDMA_FN_SUB(bi->fn, 5);
else
fn_tch_end = GSM_TDMA_FN_SUB(bi->fn, 4);
-
if (lchan->nr == 0)
fn_begin = gsm0502_fn_remap(fn_tch_end, FN_REMAP_TCH_H0);
else
@@ -441,7 +452,7 @@ int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
* in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is
* included in frame. */
gsm0503_tch_ahs_encode(*bursts_p, msg_tch->l2h + 2,
- msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(br->fn),
+ msgb_l2len(msg_tch) - 2, !dl_amr_fn_is_cmi(br->fn),
chan_state->codec, chan_state->codecs,
chan_state->dl_ft,
chan_state->dl_cmr);
diff --git a/src/osmo-bts-trx/sched_utils.h b/src/osmo-bts-trx/sched_utils.h
index 4a1aaf5f..f76e49bb 100644
--- a/src/osmo-bts-trx/sched_utils.h
+++ b/src/osmo-bts-trx/sched_utils.h
@@ -23,6 +23,8 @@
#include <stdint.h>
#include <errno.h>
+#include <stdbool.h>
+#include <osmo-bts/scheduler.h>
extern void *tall_bts_ctx;
@@ -35,8 +37,76 @@ static inline uint16_t compute_ber10k(int n_bits_total, int n_errors)
return 10000 * n_errors / n_bits_total;
}
-/* determine if the FN is transmitting a CMR (1) or not (0) */
-static inline int fn_is_codec_mode_request(uint32_t fn)
+/*! determine whether an uplink AMR block is CMI according to 3GPP TS 45.009.
+ * \param[in] fn_begin frame number of the beginning of the block.
+ * \returns true in case of CMI; false otherwise. */
+static inline bool ul_amr_fn_is_cmi(uint32_t fn_begin)
{
- return (((fn + 4) % 26) >> 2) & 1;
+ switch (fn_begin % 26) {
+ /*! See also: 3GPP TS 45.009, section 3.2.1.3 Transmitter/Receiver Synchronisation */
+ /* valid for AHS subslot 0 and AFS: */
+ case 0:
+ case 8:
+ case 17:
+ /* valid for AHS subslot 1: */
+ case 1:
+ case 9:
+ case 18:
+ return true;
+ break;
+ /* Complementary values for sanity check */
+ /* valid for AHS subslot 0 and AFS: */
+ case 4:
+ case 13:
+ case 21:
+ /* valid for AHS subslot 1: */
+ case 5:
+ case 14:
+ case 22:
+ return false;
+ break;
+ default:
+ LOGP(DL1P, LOGL_DEBUG,
+ "uplink frame number fn_begin=%u does not mark the beginning of a voice block!\n", fn_begin);
+ OSMO_ASSERT(false);
+ return false;
+ break;
+ }
+}
+
+/*! determine the whether a downlink AMR block is CMI according to 3GPP TS 45.009.
+ * \param[in] fn_begin frame number of the beginning of the block.
+ * \returns true in case of CMI; false otherwise. */
+static inline bool dl_amr_fn_is_cmi(uint32_t fn_begin)
+{
+ switch (fn_begin % 26) {
+ /*! See also: 3GPP TS 45.009, section 3.2.1.3 Transmitter/Receiver Synchronisation */
+ /* valid for AHS subslot 0 and AFS: */
+ case 4:
+ case 13:
+ case 21:
+ /* valid for AHS subslot 1: */
+ case 5:
+ case 14:
+ case 22:
+ return true;
+ break;
+ /* Complementary values for sanity check */
+ /* valid for AHS subslot 0 and AFS: */
+ case 0:
+ case 8:
+ case 17:
+ /* valid for AHS subslot 1: */
+ case 1:
+ case 9:
+ case 18:
+ return false;
+ break;
+ default:
+ LOGP(DL1P, LOGL_DEBUG,
+ "downlink frame number fn_begin=%u does not mark the beginning of a voice block!\n", fn_begin);
+ OSMO_ASSERT(false);
+ return false;
+ break;
+ }
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8d19e6ee..a1d04a77 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = paging cipher agch misc handover tx_power power meas ta_control
+SUBDIRS = paging cipher agch misc handover tx_power power meas ta_control amr
if ENABLE_SYSMOBTS
SUBDIRS += sysmobts
diff --git a/tests/amr/Makefile.am b/tests/amr/Makefile.am
new file mode 100644
index 00000000..dc0f1b81
--- /dev/null
+++ b/tests/amr/Makefile.am
@@ -0,0 +1,11 @@
+AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
+AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOCODEC_CFLAGS) \
+ $(LIBOSMOABIS_CFLAGS) $(LIBOSMOTRAU_CFLAGS)
+LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) \
+ $(LIBOSMOABIS_LIBS) $(LIBOSMOTRAU_LIBS)
+noinst_PROGRAMS = amr_test
+EXTRA_DIST = amr_test.ok
+
+misc_test_SOURCES = amr_test.c
+misc_test_LDADD = $(top_builddir)/src/common/libbts.a \
+ $(LDADD)
diff --git a/tests/amr/amr_test.c b/tests/amr/amr_test.c
new file mode 100644
index 00000000..4efbf402
--- /dev/null
+++ b/tests/amr/amr_test.c
@@ -0,0 +1,151 @@
+/* (C) 2021 by sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Philipp Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmo-bts/logging.h>
+#include <osmocom/core/utils.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "../../src/osmo-bts-trx/sched_utils.h"
+
+struct amr_cmi_test_data {
+ /* Frame number that marks the beginning of the voice block */
+ uint32_t gsm_fn;
+ /* In uplink: True, when the voice block is a CMI block, false otherwise. */
+ /* In downlink: False, when the voice block is a CMI block, true otherwise. */
+ bool is_cmi;
+};
+
+/* The behavior of AHS in subslot 0 and AFS is the same */
+static const struct amr_cmi_test_data testvec_ahs_h0_and_afs[] = {
+ { 0, true },
+ { 4, false },
+ { 8, true },
+ { 13, false },
+ { 17, true },
+ { 21, false },
+ { 26, true },
+ { 30, false },
+ { 34, true },
+ { 39, false },
+ { 43, true },
+ { 47, false },
+ { 52, true },
+ { 56, false },
+ { 60, true },
+ { 65, false },
+ { 69, true },
+ { 73, false },
+ { 78, true },
+ { 82, false },
+ { 86, true },
+ { 91, false },
+ { 95, true },
+ { 99, false },
+};
+
+static const struct amr_cmi_test_data testvec_ahs_h1[] = {
+ { 1, true },
+ { 5, false },
+ { 9, true },
+ { 14, false },
+ { 18, true },
+ { 22, false },
+ { 27, true },
+ { 31, false },
+ { 35, true },
+ { 40, false },
+ { 44, true },
+ { 48, false },
+ { 53, true },
+ { 57, false },
+ { 61, true },
+ { 66, false },
+ { 70, true },
+ { 74, false },
+ { 79, true },
+ { 83, false },
+ { 87, true },
+ { 92, false },
+ { 96, true },
+ { 100, false },
+};
+
+static void test_amr_cmi_sched(void)
+{
+ unsigned int i;
+ bool res;
+
+ printf("AMR transmission phase (CMI) in relation to GSM FN:\n");
+
+ for (i = 0; i < ARRAY_SIZE(testvec_ahs_h0_and_afs); i++) {
+ res = ul_amr_fn_is_cmi(testvec_ahs_h0_and_afs[i].gsm_fn);
+ printf("Uplink, AMR AHS on HR subslot 0: fn_begin=%u, CMI=%u\n", testvec_ahs_h0_and_afs[i].gsm_fn, res);
+ OSMO_ASSERT(res == testvec_ahs_h0_and_afs[i].is_cmi);
+ }
+
+ printf("\n");
+
+ for (i = 0; i < ARRAY_SIZE(testvec_ahs_h0_and_afs); i++) {
+ res = dl_amr_fn_is_cmi(testvec_ahs_h0_and_afs[i].gsm_fn);
+ printf("Downlink, AMR AHS on HR subslot 0: fn_begin=%u, CMI=%u\n", testvec_ahs_h0_and_afs[i].gsm_fn, res);
+ OSMO_ASSERT(res == !testvec_ahs_h0_and_afs[i].is_cmi);
+ }
+
+ printf("\n");
+ printf("\n");
+
+ for (i = 0; i < ARRAY_SIZE(testvec_ahs_h1); i++) {
+ res = ul_amr_fn_is_cmi(testvec_ahs_h1[i].gsm_fn);
+ printf("Uplink, AMR AHS on HR subslot 1: fn_begin=%u, CMI=%u\n", testvec_ahs_h1[i].gsm_fn, res);
+ OSMO_ASSERT(res == testvec_ahs_h1[i].is_cmi);
+ }
+
+ printf("\n");
+
+ for (i = 0; i < ARRAY_SIZE(testvec_ahs_h1); i++) {
+ res = dl_amr_fn_is_cmi(testvec_ahs_h1[i].gsm_fn);
+ printf("Downlink, AMR AHS on HR subslot 1: fn_begin=%u, CMI=%u\n", testvec_ahs_h1[i].gsm_fn, res);
+ OSMO_ASSERT(res == !testvec_ahs_h1[i].is_cmi);
+ }
+
+ printf("\n");
+ printf("\n");
+
+ for (i = 0; i < ARRAY_SIZE(testvec_ahs_h0_and_afs); i++) {
+ res = ul_amr_fn_is_cmi(testvec_ahs_h0_and_afs[i].gsm_fn);
+ printf("Uplink, AMR AFS: fn_begin=%u, CMI=%u\n", testvec_ahs_h0_and_afs[i].gsm_fn, res);
+ OSMO_ASSERT(res == testvec_ahs_h0_and_afs[i].is_cmi);
+ }
+
+ printf("\n");
+
+ for (i = 0; i < ARRAY_SIZE(testvec_ahs_h0_and_afs); i++) {
+ res = dl_amr_fn_is_cmi(testvec_ahs_h0_and_afs[i].gsm_fn);
+ printf("Downlink, AMR AFS: fn_begin=%u, CMI=%u\n", testvec_ahs_h0_and_afs[i].gsm_fn, res);
+ OSMO_ASSERT(res == !testvec_ahs_h0_and_afs[i].is_cmi);
+ }
+}
+
+int main(int argc, char **argv)
+{
+
+ test_amr_cmi_sched();
+ return EXIT_SUCCESS;
+}
diff --git a/tests/amr/amr_test.ok b/tests/amr/amr_test.ok
new file mode 100644
index 00000000..ec1d1a08
--- /dev/null
+++ b/tests/amr/amr_test.ok
@@ -0,0 +1,152 @@
+AMR transmission phase (CMI) in relation to GSM FN:
+Uplink, AMR AHS on HR subslot 0: fn_begin=0, CMI=1
+Uplink, AMR AHS on HR subslot 0: fn_begin=4, CMI=0
+Uplink, AMR AHS on HR subslot 0: fn_begin=8, CMI=1
+Uplink, AMR AHS on HR subslot 0: fn_begin=13, CMI=0
+Uplink, AMR AHS on HR subslot 0: fn_begin=17, CMI=1
+Uplink, AMR AHS on HR subslot 0: fn_begin=21, CMI=0
+Uplink, AMR AHS on HR subslot 0: fn_begin=26, CMI=1
+Uplink, AMR AHS on HR subslot 0: fn_begin=30, CMI=0
+Uplink, AMR AHS on HR subslot 0: fn_begin=34, CMI=1
+Uplink, AMR AHS on HR subslot 0: fn_begin=39, CMI=0
+Uplink, AMR AHS on HR subslot 0: fn_begin=43, CMI=1
+Uplink, AMR AHS on HR subslot 0: fn_begin=47, CMI=0
+Uplink, AMR AHS on HR subslot 0: fn_begin=52, CMI=1
+Uplink, AMR AHS on HR subslot 0: fn_begin=56, CMI=0
+Uplink, AMR AHS on HR subslot 0: fn_begin=60, CMI=1
+Uplink, AMR AHS on HR subslot 0: fn_begin=65, CMI=0
+Uplink, AMR AHS on HR subslot 0: fn_begin=69, CMI=1
+Uplink, AMR AHS on HR subslot 0: fn_begin=73, CMI=0
+Uplink, AMR AHS on HR subslot 0: fn_begin=78, CMI=1
+Uplink, AMR AHS on HR subslot 0: fn_begin=82, CMI=0
+Uplink, AMR AHS on HR subslot 0: fn_begin=86, CMI=1
+Uplink, AMR AHS on HR subslot 0: fn_begin=91, CMI=0
+Uplink, AMR AHS on HR subslot 0: fn_begin=95, CMI=1
+Uplink, AMR AHS on HR subslot 0: fn_begin=99, CMI=0
+
+Downlink, AMR AHS on HR subslot 0: fn_begin=0, CMI=0
+Downlink, AMR AHS on HR subslot 0: fn_begin=4, CMI=1
+Downlink, AMR AHS on HR subslot 0: fn_begin=8, CMI=0
+Downlink, AMR AHS on HR subslot 0: fn_begin=13, CMI=1
+Downlink, AMR AHS on HR subslot 0: fn_begin=17, CMI=0
+Downlink, AMR AHS on HR subslot 0: fn_begin=21, CMI=1
+Downlink, AMR AHS on HR subslot 0: fn_begin=26, CMI=0
+Downlink, AMR AHS on HR subslot 0: fn_begin=30, CMI=1
+Downlink, AMR AHS on HR subslot 0: fn_begin=34, CMI=0
+Downlink, AMR AHS on HR subslot 0: fn_begin=39, CMI=1
+Downlink, AMR AHS on HR subslot 0: fn_begin=43, CMI=0
+Downlink, AMR AHS on HR subslot 0: fn_begin=47, CMI=1
+Downlink, AMR AHS on HR subslot 0: fn_begin=52, CMI=0
+Downlink, AMR AHS on HR subslot 0: fn_begin=56, CMI=1
+Downlink, AMR AHS on HR subslot 0: fn_begin=60, CMI=0
+Downlink, AMR AHS on HR subslot 0: fn_begin=65, CMI=1
+Downlink, AMR AHS on HR subslot 0: fn_begin=69, CMI=0
+Downlink, AMR AHS on HR subslot 0: fn_begin=73, CMI=1
+Downlink, AMR AHS on HR subslot 0: fn_begin=78, CMI=0
+Downlink, AMR AHS on HR subslot 0: fn_begin=82, CMI=1
+Downlink, AMR AHS on HR subslot 0: fn_begin=86, CMI=0
+Downlink, AMR AHS on HR subslot 0: fn_begin=91, CMI=1
+Downlink, AMR AHS on HR subslot 0: fn_begin=95, CMI=0
+Downlink, AMR AHS on HR subslot 0: fn_begin=99, CMI=1
+
+
+Uplink, AMR AHS on HR subslot 1: fn_begin=1, CMI=1
+Uplink, AMR AHS on HR subslot 1: fn_begin=5, CMI=0
+Uplink, AMR AHS on HR subslot 1: fn_begin=9, CMI=1
+Uplink, AMR AHS on HR subslot 1: fn_begin=14, CMI=0
+Uplink, AMR AHS on HR subslot 1: fn_begin=18, CMI=1
+Uplink, AMR AHS on HR subslot 1: fn_begin=22, CMI=0
+Uplink, AMR AHS on HR subslot 1: fn_begin=27, CMI=1
+Uplink, AMR AHS on HR subslot 1: fn_begin=31, CMI=0
+Uplink, AMR AHS on HR subslot 1: fn_begin=35, CMI=1
+Uplink, AMR AHS on HR subslot 1: fn_begin=40, CMI=0
+Uplink, AMR AHS on HR subslot 1: fn_begin=44, CMI=1
+Uplink, AMR AHS on HR subslot 1: fn_begin=48, CMI=0
+Uplink, AMR AHS on HR subslot 1: fn_begin=53, CMI=1
+Uplink, AMR AHS on HR subslot 1: fn_begin=57, CMI=0
+Uplink, AMR AHS on HR subslot 1: fn_begin=61, CMI=1
+Uplink, AMR AHS on HR subslot 1: fn_begin=66, CMI=0
+Uplink, AMR AHS on HR subslot 1: fn_begin=70, CMI=1
+Uplink, AMR AHS on HR subslot 1: fn_begin=74, CMI=0
+Uplink, AMR AHS on HR subslot 1: fn_begin=79, CMI=1
+Uplink, AMR AHS on HR subslot 1: fn_begin=83, CMI=0
+Uplink, AMR AHS on HR subslot 1: fn_begin=87, CMI=1
+Uplink, AMR AHS on HR subslot 1: fn_begin=92, CMI=0
+Uplink, AMR AHS on HR subslot 1: fn_begin=96, CMI=1
+Uplink, AMR AHS on HR subslot 1: fn_begin=100, CMI=0
+
+Downlink, AMR AHS on HR subslot 1: fn_begin=1, CMI=0
+Downlink, AMR AHS on HR subslot 1: fn_begin=5, CMI=1
+Downlink, AMR AHS on HR subslot 1: fn_begin=9, CMI=0
+Downlink, AMR AHS on HR subslot 1: fn_begin=14, CMI=1
+Downlink, AMR AHS on HR subslot 1: fn_begin=18, CMI=0
+Downlink, AMR AHS on HR subslot 1: fn_begin=22, CMI=1
+Downlink, AMR AHS on HR subslot 1: fn_begin=27, CMI=0
+Downlink, AMR AHS on HR subslot 1: fn_begin=31, CMI=1
+Downlink, AMR AHS on HR subslot 1: fn_begin=35, CMI=0
+Downlink, AMR AHS on HR subslot 1: fn_begin=40, CMI=1
+Downlink, AMR AHS on HR subslot 1: fn_begin=44, CMI=0
+Downlink, AMR AHS on HR subslot 1: fn_begin=48, CMI=1
+Downlink, AMR AHS on HR subslot 1: fn_begin=53, CMI=0
+Downlink, AMR AHS on HR subslot 1: fn_begin=57, CMI=1
+Downlink, AMR AHS on HR subslot 1: fn_begin=61, CMI=0
+Downlink, AMR AHS on HR subslot 1: fn_begin=66, CMI=1
+Downlink, AMR AHS on HR subslot 1: fn_begin=70, CMI=0
+Downlink, AMR AHS on HR subslot 1: fn_begin=74, CMI=1
+Downlink, AMR AHS on HR subslot 1: fn_begin=79, CMI=0
+Downlink, AMR AHS on HR subslot 1: fn_begin=83, CMI=1
+Downlink, AMR AHS on HR subslot 1: fn_begin=87, CMI=0
+Downlink, AMR AHS on HR subslot 1: fn_begin=92, CMI=1
+Downlink, AMR AHS on HR subslot 1: fn_begin=96, CMI=0
+Downlink, AMR AHS on HR subslot 1: fn_begin=100, CMI=1
+
+
+Uplink, AMR AFS: fn_begin=0, CMI=1
+Uplink, AMR AFS: fn_begin=4, CMI=0
+Uplink, AMR AFS: fn_begin=8, CMI=1
+Uplink, AMR AFS: fn_begin=13, CMI=0
+Uplink, AMR AFS: fn_begin=17, CMI=1
+Uplink, AMR AFS: fn_begin=21, CMI=0
+Uplink, AMR AFS: fn_begin=26, CMI=1
+Uplink, AMR AFS: fn_begin=30, CMI=0
+Uplink, AMR AFS: fn_begin=34, CMI=1
+Uplink, AMR AFS: fn_begin=39, CMI=0
+Uplink, AMR AFS: fn_begin=43, CMI=1
+Uplink, AMR AFS: fn_begin=47, CMI=0
+Uplink, AMR AFS: fn_begin=52, CMI=1
+Uplink, AMR AFS: fn_begin=56, CMI=0
+Uplink, AMR AFS: fn_begin=60, CMI=1
+Uplink, AMR AFS: fn_begin=65, CMI=0
+Uplink, AMR AFS: fn_begin=69, CMI=1
+Uplink, AMR AFS: fn_begin=73, CMI=0
+Uplink, AMR AFS: fn_begin=78, CMI=1
+Uplink, AMR AFS: fn_begin=82, CMI=0
+Uplink, AMR AFS: fn_begin=86, CMI=1
+Uplink, AMR AFS: fn_begin=91, CMI=0
+Uplink, AMR AFS: fn_begin=95, CMI=1
+Uplink, AMR AFS: fn_begin=99, CMI=0
+
+Downlink, AMR AFS: fn_begin=0, CMI=0
+Downlink, AMR AFS: fn_begin=4, CMI=1
+Downlink, AMR AFS: fn_begin=8, CMI=0
+Downlink, AMR AFS: fn_begin=13, CMI=1
+Downlink, AMR AFS: fn_begin=17, CMI=0
+Downlink, AMR AFS: fn_begin=21, CMI=1
+Downlink, AMR AFS: fn_begin=26, CMI=0
+Downlink, AMR AFS: fn_begin=30, CMI=1
+Downlink, AMR AFS: fn_begin=34, CMI=0
+Downlink, AMR AFS: fn_begin=39, CMI=1
+Downlink, AMR AFS: fn_begin=43, CMI=0
+Downlink, AMR AFS: fn_begin=47, CMI=1
+Downlink, AMR AFS: fn_begin=52, CMI=0
+Downlink, AMR AFS: fn_begin=56, CMI=1
+Downlink, AMR AFS: fn_begin=60, CMI=0
+Downlink, AMR AFS: fn_begin=65, CMI=1
+Downlink, AMR AFS: fn_begin=69, CMI=0
+Downlink, AMR AFS: fn_begin=73, CMI=1
+Downlink, AMR AFS: fn_begin=78, CMI=0
+Downlink, AMR AFS: fn_begin=82, CMI=1
+Downlink, AMR AFS: fn_begin=86, CMI=0
+Downlink, AMR AFS: fn_begin=91, CMI=1
+Downlink, AMR AFS: fn_begin=95, CMI=0
+Downlink, AMR AFS: fn_begin=99, CMI=1
diff --git a/tests/testsuite.at b/tests/testsuite.at
index ba5a409b..f2d17fbf 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -63,3 +63,9 @@ AT_KEYWORDS([ta_control])
cat $abs_srcdir/ta_control/ta_control_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/ta_control/ta_control_test], [], [expout], [ignore])
AT_CLEANUP
+
+AT_SETUP([amr])
+AT_KEYWORDS([amr])
+cat $abs_srcdir/amr/amr_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/amr/amr_test], [], [expout], [ignore])
+AT_CLEANUP