<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/18247">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  laforge: Looks good to me, approved
  tnt: Looks good to me, but someone else must approve
  Jenkins Builder: Verified

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Implement ITU-T I.460 multiplex / demultiplex<br><br>This implements a multiplexer and de-multiplexer for the ITU-T I.460<br>standard.  The latter covers the transmission of sub-slots of 32/16/8k<br>inside 64k timeslots.<br><br>Change-Id: Id522f06e73b77332b437b7a27e4966872da70eda<br>---<br>M include/Makefile.am<br>A include/osmocom/gsm/i460_mux.h<br>M src/gsm/Makefile.am<br>A src/gsm/i460_mux.c<br>M src/gsm/libosmogsm.map<br>M tests/Makefile.am<br>A tests/i460_mux/i460_mux_test.c<br>A tests/i460_mux/i460_mux_test.ok<br>M tests/testsuite.at<br>9 files changed, 999 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/Makefile.am b/include/Makefile.am</span><br><span>index 572c880..456b8ef 100644</span><br><span>--- a/include/Makefile.am</span><br><span>+++ b/include/Makefile.am</span><br><span>@@ -103,6 +103,7 @@</span><br><span>                        osmocom/gsm/gsm_utils.h \</span><br><span>                        osmocom/gsm/gsup.h \</span><br><span>                        osmocom/gsm/gsup_sms.h \</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmocom/gsm/i460_mux.h \</span><br><span>                        osmocom/gsm/ipa.h \</span><br><span>                        osmocom/gsm/lapd_core.h \</span><br><span>                        osmocom/gsm/lapdm.h \</span><br><span>diff --git a/include/osmocom/gsm/i460_mux.h b/include/osmocom/gsm/i460_mux.h</span><br><span>new file mode 100644</span><br><span>index 0000000..2e33b37</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/gsm/i460_mux.h</span><br><span>@@ -0,0 +1,104 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file i460_mux.h</span><br><span style="color: hsl(120, 100%, 40%);">+ * ITU-T I.460 sub-channel multiplexer + demultiplexer */</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2020 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ *  it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ *  the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ *  (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ *  GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ *  along with this program; if not, write to the Free Software</span><br><span style="color: hsl(120, 100%, 40%);">+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,</span><br><span style="color: hsl(120, 100%, 40%);">+ *  MA  02110-1301, USA.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/bits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* I.460 sub-slot rate */</span><br><span style="color: hsl(120, 100%, 40%);">+enum osmo_i460_rate {</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_I460_RATE_NONE,            /* disabled */</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_I460_RATE_64k,</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_I460_RATE_32k,</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_I460_RATE_16k,</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_I460_RATE_8k,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+typedef void (*out_cb_bits_t)(void *user_data, const ubit_t *bits, unsigned int num_bits);</span><br><span style="color: hsl(120, 100%, 40%);">+typedef void (*out_cb_bytes_t)(void *user_data, const uint8_t *bytes, unsigned int num_bytes);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_i460_subchan_demux {</span><br><span style="color: hsl(120, 100%, 40%);">+      /*! bit-buffer for output bits */</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t *out_bitbuf;</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! size of out_bitbuf in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int out_bitbuf_size;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! offset of next bit to be written in out_bitbuf */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int out_idx;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! callback to be called once we have received out_bitbuf_size bits */</span><br><span style="color: hsl(120, 100%, 40%);">+       out_cb_bits_t out_cb_bits;</span><br><span style="color: hsl(120, 100%, 40%);">+    out_cb_bytes_t out_cb_bytes;</span><br><span style="color: hsl(120, 100%, 40%);">+  void *user_data;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_i460_subchan_mux {</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! list of to-be-transmitted message buffers */</span><br><span style="color: hsl(120, 100%, 40%);">+      struct llist_head tx_queue;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_i460_subchan {</span><br><span style="color: hsl(120, 100%, 40%);">+ enum osmo_i460_rate rate;               /* 8/16/32/64k */</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t bit_offset;             /* bit offset inside each byte of the B-channel */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_i460_subchan_demux demux;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_i460_subchan_mux mux;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_i460_timeslot {</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_i460_subchan schan[8];</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! description of a sub-channel; passed by caller */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_i460_schan_desc {</span><br><span style="color: hsl(120, 100%, 40%);">+        enum osmo_i460_rate rate;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t bit_offset;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* size (in bits) of the internal buffer; determines granularity */</span><br><span style="color: hsl(120, 100%, 40%);">+           size_t num_bits;</span><br><span style="color: hsl(120, 100%, 40%);">+              /*! call-back function called whenever we received num_bits */</span><br><span style="color: hsl(120, 100%, 40%);">+                out_cb_bits_t out_cb_bits;</span><br><span style="color: hsl(120, 100%, 40%);">+            /*! out_cb_bytes call-back function called whenever we received num_bits.</span><br><span style="color: hsl(120, 100%, 40%);">+              * The user is usually expected to provide either out_cb_bits or out_cb_bytes.  If only</span><br><span style="color: hsl(120, 100%, 40%);">+                * out_cb_bits is provided, output data will always be provided as unpacked bits;  if only</span><br><span style="color: hsl(120, 100%, 40%);">+             * out_cb_bytes is provided, output data will always be provided as packet bits (bytes).  If</span><br><span style="color: hsl(120, 100%, 40%);">+           * both are provided, it is up to the I.460 multiplex to decide if it calls either of the two,</span><br><span style="color: hsl(120, 100%, 40%);">+                 * depending on what can be provided without extra conversion. */</span><br><span style="color: hsl(120, 100%, 40%);">+             out_cb_bytes_t out_cb_bytes;</span><br><span style="color: hsl(120, 100%, 40%);">+          /* opaque user data pointer to pass to out_cb */</span><br><span style="color: hsl(120, 100%, 40%);">+              void *user_data;</span><br><span style="color: hsl(120, 100%, 40%);">+      } demux;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_i460_demux_in(struct osmo_i460_timeslot *ts, const uint8_t *data, size_t data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_i460_mux_enqueue(struct osmo_i460_subchan *schan, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_i460_mux_out(struct osmo_i460_timeslot *ts, uint8_t *out, size_t out_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_i460_ts_init(struct osmo_i460_timeslot *ts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_i460_subchan *</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_i460_subchan_add(void *ctx, struct osmo_i460_timeslot *ts, const struct osmo_i460_schan_desc *chd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_i460_subchan_del(struct osmo_i460_subchan *schan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! @} */</span><br><span>diff --git a/src/gsm/Makefile.am b/src/gsm/Makefile.am</span><br><span>index 6935eab..eeb1164 100644</span><br><span>--- a/src/gsm/Makefile.am</span><br><span>+++ b/src/gsm/Makefile.am</span><br><span>@@ -32,7 +32,7 @@</span><br><span>                     milenage/milenage.c gan.c ipa.c gsm0341.c apn.c \</span><br><span>                    gsup.c gsup_sms.c gprs_gea.c gsm0503_conv.c oap.c gsm0808_utils.c \</span><br><span>                  gsm23003.c mncc.c bts_features.c oap_client.c \</span><br><span style="color: hsl(0, 100%, 40%);">-                 gsm29118.c gsm48_rest_octets.c cbsp.c gsm48049.c</span><br><span style="color: hsl(120, 100%, 40%);">+                      gsm29118.c gsm48_rest_octets.c cbsp.c gsm48049.c i460_mux.c</span><br><span> libgsmint_la_LDFLAGS = -no-undefined</span><br><span> libgsmint_la_LIBADD = $(top_builddir)/src/libosmocore.la</span><br><span> </span><br><span>diff --git a/src/gsm/i460_mux.c b/src/gsm/i460_mux.c</span><br><span>new file mode 100644</span><br><span>index 0000000..3fb63ec</span><br><span>--- /dev/null</span><br><span>+++ b/src/gsm/i460_mux.c</span><br><span>@@ -0,0 +1,363 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \file i460_mux.c</span><br><span style="color: hsl(120, 100%, 40%);">+ * ITU-T I.460 sub-channel multiplexer + demultiplexer */</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2020 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ *  it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ *  the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ *  (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ *  GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  You should have received a copy of the GNU General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ *  along with this program; if not, write to the Free Software</span><br><span style="color: hsl(120, 100%, 40%);">+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,</span><br><span style="color: hsl(120, 100%, 40%);">+ *  MA  02110-1301, USA.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/bits.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/i460_mux.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* count the number of sub-channels in this I460 slot */</span><br><span style="color: hsl(120, 100%, 40%);">+static int osmo_i460_subchan_count(struct osmo_i460_timeslot *ts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int i, num_used = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < ARRAY_SIZE(ts->schan); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (ts->schan[i].rate != OSMO_I460_RATE_NONE)</span><br><span style="color: hsl(120, 100%, 40%);">+                      num_used++;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return num_used;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* does this channel have no sub-streams (single 64k subchannel)? */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool osmo_i460_has_single_64k_schan(struct osmo_i460_timeslot *ts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (osmo_i460_subchan_count(ts) != 1)</span><br><span style="color: hsl(120, 100%, 40%);">+         return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ts->schan[0].rate != OSMO_I460_RATE_64k)</span><br><span style="color: hsl(120, 100%, 40%);">+               return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * Demultiplexer</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* append a single bit to a sub-channel */</span><br><span style="color: hsl(120, 100%, 40%);">+static void demux_subchan_append_bit(struct osmo_i460_subchan *schan, uint8_t bit)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_i460_subchan_demux *demux = &schan->demux;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(demux->out_bitbuf);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(demux->out_idx < demux->out_bitbuf_size);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      demux->out_bitbuf[demux->out_idx++] = bit ? 1 : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (demux->out_idx >= demux->out_bitbuf_size) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (demux->out_cb_bits)</span><br><span style="color: hsl(120, 100%, 40%);">+                    demux->out_cb_bits(demux->user_data, demux->out_bitbuf, demux->out_idx);</span><br><span style="color: hsl(120, 100%, 40%);">+          else {</span><br><span style="color: hsl(120, 100%, 40%);">+                        /* pack bits into bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+                    OSMO_ASSERT((demux->out_idx % 8) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                    unsigned int num_bytes = demux->out_idx / 8;</span><br><span style="color: hsl(120, 100%, 40%);">+                       uint8_t bytes[num_bytes];</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_ubit2pbit(bytes, demux->out_bitbuf, demux->out_idx);</span><br><span style="color: hsl(120, 100%, 40%);">+                       demux->out_cb_bytes(demux->user_data, bytes, num_bytes);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             demux->out_idx = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* extract those bits relevant to this schan of each byte in 'data' */</span><br><span style="color: hsl(120, 100%, 40%);">+static void demux_subchan_extract_bits(struct osmo_i460_subchan *schan, const uint8_t *data, size_t data_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < data_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           uint8_t inbyte = data[i];</span><br><span style="color: hsl(120, 100%, 40%);">+             uint8_t inbits = inbyte >> schan->bit_offset;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              /* extract the bits relevant to the given schan */</span><br><span style="color: hsl(120, 100%, 40%);">+            switch (schan->rate) {</span><br><span style="color: hsl(120, 100%, 40%);">+             case OSMO_I460_RATE_8k:</span><br><span style="color: hsl(120, 100%, 40%);">+                       demux_subchan_append_bit(schan, inbits & 0x01);</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case OSMO_I460_RATE_16k:</span><br><span style="color: hsl(120, 100%, 40%);">+                      demux_subchan_append_bit(schan, inbits & 0x01);</span><br><span style="color: hsl(120, 100%, 40%);">+                   demux_subchan_append_bit(schan, inbits & 0x02);</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case OSMO_I460_RATE_32k:</span><br><span style="color: hsl(120, 100%, 40%);">+                      demux_subchan_append_bit(schan, inbits & 0x01);</span><br><span style="color: hsl(120, 100%, 40%);">+                   demux_subchan_append_bit(schan, inbits & 0x02);</span><br><span style="color: hsl(120, 100%, 40%);">+                   demux_subchan_append_bit(schan, inbits & 0x04);</span><br><span style="color: hsl(120, 100%, 40%);">+                   demux_subchan_append_bit(schan, inbits & 0x08);</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case OSMO_I460_RATE_64k:</span><br><span style="color: hsl(120, 100%, 40%);">+                      demux_subchan_append_bit(schan, inbits & 0x01);</span><br><span style="color: hsl(120, 100%, 40%);">+                   demux_subchan_append_bit(schan, inbits & 0x02);</span><br><span style="color: hsl(120, 100%, 40%);">+                   demux_subchan_append_bit(schan, inbits & 0x04);</span><br><span style="color: hsl(120, 100%, 40%);">+                   demux_subchan_append_bit(schan, inbits & 0x08);</span><br><span style="color: hsl(120, 100%, 40%);">+                   demux_subchan_append_bit(schan, inbits & 0x10);</span><br><span style="color: hsl(120, 100%, 40%);">+                   demux_subchan_append_bit(schan, inbits & 0x20);</span><br><span style="color: hsl(120, 100%, 40%);">+                   demux_subchan_append_bit(schan, inbits & 0x40);</span><br><span style="color: hsl(120, 100%, 40%);">+                   demux_subchan_append_bit(schan, inbits & 0x80);</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Data from E1 timeslot into de-multiplexer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ts timeslot state</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] data input data bytes as received from E1/T1</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] data_len length of data in bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_i460_demux_in(struct osmo_i460_timeslot *ts, const uint8_t *data, size_t data_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_i460_subchan *schan;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_i460_subchan_demux *demux;</span><br><span style="color: hsl(120, 100%, 40%);">+        int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* fast path if entire 64k slot is used */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (osmo_i460_has_single_64k_schan(ts)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             schan = &ts->schan[0];</span><br><span style="color: hsl(120, 100%, 40%);">+         demux = &schan->demux;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (demux->out_cb_bytes)</span><br><span style="color: hsl(120, 100%, 40%);">+                   demux->out_cb_bytes(demux->user_data, data, data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+          else {</span><br><span style="color: hsl(120, 100%, 40%);">+                        ubit_t bits[data_len*8];</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_pbit2ubit(bits, data, data_len*8);</span><br><span style="color: hsl(120, 100%, 40%);">+                       demux->out_cb_bits(demux->user_data, bits, data_len*8);</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Slow path iterating over all lchans */</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < ARRAY_SIZE(ts->schan); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           schan = &ts->schan[i];</span><br><span style="color: hsl(120, 100%, 40%);">+         if (schan->rate == OSMO_I460_RATE_NONE)</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             demux_subchan_extract_bits(schan, data, data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * Multiplexer</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! enqueue a to-be-transmitted message buffer containing unpacked bits */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_i460_mux_enqueue(struct osmo_i460_subchan *schan, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(msgb_length(msg) > 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_enqueue(&schan->mux.tx_queue, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* mux: pull the next bit out of the given sub-channel */</span><br><span style="color: hsl(120, 100%, 40%);">+static ubit_t mux_schan_provide_bit(struct osmo_i460_subchan *schan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_i460_subchan_mux *mux = &schan->mux;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     ubit_t bit;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* if we don't have anything to transmit, return '1' bits */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (llist_empty(&mux->tx_queue))</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0x01;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        msg = llist_entry(mux->tx_queue.next, struct msgb, list);</span><br><span style="color: hsl(120, 100%, 40%);">+  bit = msgb_pull_u8(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* free msgb if we have pulled the last bit */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (msgb_length(msg) <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               llist_del(&msg->list);</span><br><span style="color: hsl(120, 100%, 40%);">+         talloc_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return bit;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! provide one byte with the subchan-specific bits of given sub-channel.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] schan sub-channel that is to provide bits</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \parma[out] mask bitmask of those bits filled in</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns bits of given sub-channel */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t mux_subchan_provide_bits(struct osmo_i460_subchan *schan, uint8_t *mask)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t outbits = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t outmask;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (schan->rate) {</span><br><span style="color: hsl(120, 100%, 40%);">+     case OSMO_I460_RATE_8k:</span><br><span style="color: hsl(120, 100%, 40%);">+               outbits = mux_schan_provide_bit(schan);</span><br><span style="color: hsl(120, 100%, 40%);">+               outmask = 0x01;</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OSMO_I460_RATE_16k:</span><br><span style="color: hsl(120, 100%, 40%);">+              outbits |= mux_schan_provide_bit(schan) << 1;</span><br><span style="color: hsl(120, 100%, 40%);">+           outbits |= mux_schan_provide_bit(schan) << 0;</span><br><span style="color: hsl(120, 100%, 40%);">+           outmask = 0x03;</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OSMO_I460_RATE_32k:</span><br><span style="color: hsl(120, 100%, 40%);">+              outbits |= mux_schan_provide_bit(schan) << 3;</span><br><span style="color: hsl(120, 100%, 40%);">+           outbits |= mux_schan_provide_bit(schan) << 2;</span><br><span style="color: hsl(120, 100%, 40%);">+           outbits |= mux_schan_provide_bit(schan) << 1;</span><br><span style="color: hsl(120, 100%, 40%);">+           outbits |= mux_schan_provide_bit(schan) << 0;</span><br><span style="color: hsl(120, 100%, 40%);">+           outmask = 0x0F;</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OSMO_I460_RATE_64k:</span><br><span style="color: hsl(120, 100%, 40%);">+              outbits |= mux_schan_provide_bit(schan) << 7;</span><br><span style="color: hsl(120, 100%, 40%);">+           outbits |= mux_schan_provide_bit(schan) << 6;</span><br><span style="color: hsl(120, 100%, 40%);">+           outbits |= mux_schan_provide_bit(schan) << 5;</span><br><span style="color: hsl(120, 100%, 40%);">+           outbits |= mux_schan_provide_bit(schan) << 4;</span><br><span style="color: hsl(120, 100%, 40%);">+           outbits |= mux_schan_provide_bit(schan) << 3;</span><br><span style="color: hsl(120, 100%, 40%);">+           outbits |= mux_schan_provide_bit(schan) << 2;</span><br><span style="color: hsl(120, 100%, 40%);">+           outbits |= mux_schan_provide_bit(schan) << 1;</span><br><span style="color: hsl(120, 100%, 40%);">+           outbits |= mux_schan_provide_bit(schan) << 0;</span><br><span style="color: hsl(120, 100%, 40%);">+           outmask = 0xFF;</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     *mask = outmask << schan->bit_offset;</span><br><span style="color: hsl(120, 100%, 40%);">+        return outbits << schan->bit_offset;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* provide one byte of multiplexed I.460 bits */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t mux_timeslot_provide_bits(struct osmo_i460_timeslot *ts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int i, count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t ret = 0xff; /* unused bits must be '1' as per I.460 */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < ARRAY_SIZE(ts->schan); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           struct osmo_i460_subchan *schan = &ts->schan[i];</span><br><span style="color: hsl(120, 100%, 40%);">+               uint8_t bits, mask;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (schan->rate == OSMO_I460_RATE_NONE)</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             count++;</span><br><span style="color: hsl(120, 100%, 40%);">+              bits = mux_subchan_provide_bits(schan, &mask);</span><br><span style="color: hsl(120, 100%, 40%);">+            ret &= ~mask;</span><br><span style="color: hsl(120, 100%, 40%);">+             ret |= bits;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return ret;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Data from E1 timeslot into de-multiplexer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ts timeslot state</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] out caller-provided buffer where to store generated output bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] out_len number of bytes to be stored at out</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_i460_mux_out(struct osmo_i460_timeslot *ts, uint8_t *out, size_t out_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* fast path if entire 64k slot is used */</span><br><span style="color: hsl(120, 100%, 40%);">+    //if (osmo_i460_has_single_64k_schan(ts)) { }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i < out_len; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+              out[i] = mux_timeslot_provide_bits(ts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return out_len;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * Initialization / Control</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int alloc_bitbuf(void *ctx, struct osmo_i460_subchan *schan, size_t num_bits)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_i460_subchan_demux *demux = &schan->demux;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       talloc_free(demux->out_bitbuf);</span><br><span style="color: hsl(120, 100%, 40%);">+    demux->out_bitbuf = talloc_zero_size(ctx, num_bits);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!demux->out_bitbuf)</span><br><span style="color: hsl(120, 100%, 40%);">+            return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       demux->out_bitbuf_size = num_bits;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int find_unused_subchan_idx(const struct osmo_i460_timeslot *ts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < ARRAY_SIZE(ts->schan); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           const struct osmo_i460_subchan *schan = &ts->schan[i];</span><br><span style="color: hsl(120, 100%, 40%);">+         if (schan->rate == OSMO_I460_RATE_NONE)</span><br><span style="color: hsl(120, 100%, 40%);">+                    return i;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! initialize an I.460 timeslot */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_i460_ts_init(struct osmo_i460_timeslot *ts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < ARRAY_SIZE(ts->schan); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           struct osmo_i460_subchan *schan = &ts->schan[i];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             memset(schan, 0, sizeof(*schan));</span><br><span style="color: hsl(120, 100%, 40%);">+             schan->rate = OSMO_I460_RATE_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+         INIT_LLIST_HEAD(&schan->mux.tx_queue);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! add a new sub-channel to the given timeslot</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ctx talloc context from where to allocate the internal buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ts timeslot to which to add a sub-channel</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] chd description of the sub-channel to be added</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \return pointer to sub-channel on success, NULL on error */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_i460_subchan *</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_i460_subchan_add(void *ctx, struct osmo_i460_timeslot *ts, const struct osmo_i460_schan_desc *chd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_i460_subchan *schan;</span><br><span style="color: hsl(120, 100%, 40%);">+      int idx, rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        idx = find_unused_subchan_idx(ts);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (idx < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        schan = &ts->schan[idx];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     schan->rate = chd->rate;</span><br><span style="color: hsl(120, 100%, 40%);">+        schan->bit_offset = chd->bit_offset;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  schan->demux.out_cb_bits = chd->demux.out_cb_bits;</span><br><span style="color: hsl(120, 100%, 40%);">+      schan->demux.out_cb_bytes = chd->demux.out_cb_bytes;</span><br><span style="color: hsl(120, 100%, 40%);">+    schan->demux.user_data = chd->demux.user_data;</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = alloc_bitbuf(ctx, schan, chd->demux.num_bits);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              memset(schan, 0, sizeof(*schan));</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* return number of schan in use */</span><br><span style="color: hsl(120, 100%, 40%);">+   return schan;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* remove a su-channel from the multiplex */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_i460_subchan_del(struct osmo_i460_subchan *schan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      talloc_free(schan->demux.out_bitbuf);</span><br><span style="color: hsl(120, 100%, 40%);">+      memset(schan, 0, sizeof(*schan));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! @} */</span><br><span>diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map</span><br><span>index 70b3916..2000e6c 100644</span><br><span>--- a/src/gsm/libosmogsm.map</span><br><span>+++ b/src/gsm/libosmogsm.map</span><br><span>@@ -667,5 +667,12 @@</span><br><span> osmo_cbsp_recv_buffered;</span><br><span> osmo_cbsp_errstr;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+osmo_i460_demux_in;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_i460_mux_enqueue;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_i460_mux_out;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_i460_subchan_add;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_i460_subchan_del;</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_i460_ts_init;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> local: *;</span><br><span> };</span><br><span>diff --git a/tests/Makefile.am b/tests/Makefile.am</span><br><span>index 0d0327a..5e810e6 100644</span><br><span>--- a/tests/Makefile.am</span><br><span>+++ b/tests/Makefile.am</span><br><span>@@ -35,6 +35,7 @@</span><br><span>             context/context_test                                   \</span><br><span>                  gsm0502/gsm0502_test                                      \</span><br><span>                  dtx/dtx_gsm0503_test                                      \</span><br><span style="color: hsl(120, 100%, 40%);">+                 i460_mux/i460_mux_test                                      \</span><br><span>             $(NULL)</span><br><span> </span><br><span> if ENABLE_MSGFILE</span><br><span>@@ -269,6 +270,9 @@</span><br><span> exec_exec_test_SOURCES = exec/exec_test.c</span><br><span> exec_exec_test_LDADD = $(LDADD)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+i460_mux_i460_mux_test_SOURCES = i460_mux/i460_mux_test.c</span><br><span style="color: hsl(120, 100%, 40%);">+i460_mux_i460_mux_test_LDADD = $(LDADD) $(top_builddir)/src/gsm/libosmogsm.la</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> # The `:;' works around a Bash 3.2 bug when the output is not writeable.</span><br><span> $(srcdir)/package.m4: $(top_srcdir)/configure.ac</span><br><span>  :;{ \</span><br><span>@@ -346,6 +350,7 @@</span><br><span>       gsm0502/gsm0502_test.ok \</span><br><span>            dtx/dtx_gsm0503_test.ok \</span><br><span>            exec/exec_test.ok exec/exec_test.err \</span><br><span style="color: hsl(120, 100%, 40%);">+        i460_mux/i460_mux_test.ok \</span><br><span>          $(NULL)</span><br><span> </span><br><span> DISTCLEANFILES = atconfig atlocal conv/gsm0503_test_vectors.c</span><br><span>diff --git a/tests/i460_mux/i460_mux_test.c b/tests/i460_mux/i460_mux_test.c</span><br><span>new file mode 100644</span><br><span>index 0000000..53144fd</span><br><span>--- /dev/null</span><br><span>+++ b/tests/i460_mux/i460_mux_test.c</span><br><span>@@ -0,0 +1,397 @@</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/i460_mux.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void bits_cb(void *user_data, const ubit_t *bits, unsigned int num_bits)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ char *str = user_data;</span><br><span style="color: hsl(120, 100%, 40%);">+        printf("demux_bits_cb '%s': %s\n", str, osmo_ubit_dump(bits, num_bits));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd64 = {</span><br><span style="color: hsl(120, 100%, 40%);">+        .rate = OSMO_I460_RATE_64k,</span><br><span style="color: hsl(120, 100%, 40%);">+   .bit_offset = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "64k",</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd32_0 = {</span><br><span style="color: hsl(120, 100%, 40%);">+       .rate = OSMO_I460_RATE_32k,</span><br><span style="color: hsl(120, 100%, 40%);">+   .bit_offset = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "32k_0",</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd32_4 = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .rate = OSMO_I460_RATE_32k,</span><br><span style="color: hsl(120, 100%, 40%);">+   .bit_offset = 4,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "32k_4",</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd16_0 = {</span><br><span style="color: hsl(120, 100%, 40%);">+       .rate = OSMO_I460_RATE_16k,</span><br><span style="color: hsl(120, 100%, 40%);">+   .bit_offset = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "16k_0",</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd16_2 = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .rate = OSMO_I460_RATE_16k,</span><br><span style="color: hsl(120, 100%, 40%);">+   .bit_offset = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "16k_2",</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd16_4 = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .rate = OSMO_I460_RATE_16k,</span><br><span style="color: hsl(120, 100%, 40%);">+   .bit_offset = 4,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "16k_4",</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd16_6 = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .rate = OSMO_I460_RATE_16k,</span><br><span style="color: hsl(120, 100%, 40%);">+   .bit_offset = 6,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "16k_6",</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd8_0 = {</span><br><span style="color: hsl(120, 100%, 40%);">+        .rate = OSMO_I460_RATE_8k,</span><br><span style="color: hsl(120, 100%, 40%);">+    .bit_offset = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "8k_0",</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd8_1 = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .rate = OSMO_I460_RATE_8k,</span><br><span style="color: hsl(120, 100%, 40%);">+    .bit_offset = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "8k_1",</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd8_2 = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .rate = OSMO_I460_RATE_8k,</span><br><span style="color: hsl(120, 100%, 40%);">+    .bit_offset = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "8k_2",</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd8_3 = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .rate = OSMO_I460_RATE_8k,</span><br><span style="color: hsl(120, 100%, 40%);">+    .bit_offset = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "8k_3",</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd8_4 = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .rate = OSMO_I460_RATE_8k,</span><br><span style="color: hsl(120, 100%, 40%);">+    .bit_offset = 4,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "8k_4",</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd8_5 = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .rate = OSMO_I460_RATE_8k,</span><br><span style="color: hsl(120, 100%, 40%);">+    .bit_offset = 5,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "8k_5",</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd8_6 = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .rate = OSMO_I460_RATE_8k,</span><br><span style="color: hsl(120, 100%, 40%);">+    .bit_offset = 6,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "8k_6",</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+const struct osmo_i460_schan_desc scd8_7 = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .rate = OSMO_I460_RATE_8k,</span><br><span style="color: hsl(120, 100%, 40%);">+    .bit_offset = 7,</span><br><span style="color: hsl(120, 100%, 40%);">+      .demux = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .num_bits = 40,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bits = bits_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_cb_bytes = NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+         .user_data = "8k_7",</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void test_no_subchan(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_i460_timeslot _ts, *ts = &_ts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Initialization */</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("\n==> %s\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_i460_ts_init(ts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* feed in some data; expect nothing to happen */</span><br><span style="color: hsl(120, 100%, 40%);">+     const uint8_t nothing[128] = { 0, };</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_i460_demux_in(ts, nothing, sizeof(nothing));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* pull bytes out of mux (should be all 0xff) */</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t buf[128];</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_i460_mux_out(ts, buf, sizeof(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+      printf("out: %s\n", osmo_hexdump(buf, sizeof(buf)));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct msgb *gen_alternating_bitmsg(unsigned int num_bits)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg = msgb_alloc(num_bits, "mux-in");</span><br><span style="color: hsl(120, 100%, 40%);">+  int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < num_bits; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+             msgb_put_u8(msg, i & 1);</span><br><span style="color: hsl(120, 100%, 40%);">+  return msg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void test_64k_subchan(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_i460_timeslot _ts, *ts = &_ts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Initialization */</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("\n==> %s\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_i460_ts_init(ts);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_i460_subchan_add(NULL, ts, &scd64);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* demux */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t sequence[128];</span><br><span style="color: hsl(120, 100%, 40%);">+        int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < sizeof(sequence); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+             sequence[i] = i;</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_i460_demux_in(ts, sequence, sizeof(sequence));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* mux */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg = gen_alternating_bitmsg(128);</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_i460_mux_enqueue(&ts->schan[0], msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t buf[16];</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_i460_mux_out(ts, buf, sizeof(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+      printf("mux_out: %s\n", osmo_hexdump(buf, sizeof(buf)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_i460_subchan_del(&ts->schan[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void test_32k_subchan(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_i460_timeslot _ts, *ts = &_ts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Initialization */</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("\n==> %s\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_i460_ts_init(ts);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_i460_subchan_add(NULL, ts, &scd32_0);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_i460_subchan_add(NULL, ts, &scd32_4);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* demux */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t sequence[10];</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < sizeof(sequence); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+             sequence[i] = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      sequence[0] = 0x0f;</span><br><span style="color: hsl(120, 100%, 40%);">+   sequence[1] = 0xf0;</span><br><span style="color: hsl(120, 100%, 40%);">+   sequence[2] = 0xff;</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_i460_demux_in(ts, sequence, sizeof(sequence));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* mux */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* test with only a single channel active */</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < 2; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct msgb *msg = gen_alternating_bitmsg(128);</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_i460_mux_enqueue(&ts->schan[i], msg);</span><br><span style="color: hsl(120, 100%, 40%);">+             printf("%s-single-%u\n", __func__, i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            uint8_t buf[16];</span><br><span style="color: hsl(120, 100%, 40%);">+              int j;</span><br><span style="color: hsl(120, 100%, 40%);">+                for (j = 0; j < 3; j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_i460_mux_out(ts, buf, sizeof(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+                      printf("mux_out: %s\n", osmo_hexdump(buf, sizeof(buf)));</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < 4; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_i460_subchan_del(&ts->schan[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void test_16k_subchan(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_i460_timeslot _ts, *ts = &_ts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Initialization */</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("\n==> %s\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_i460_ts_init(ts);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_i460_subchan_add(NULL, ts, &scd16_0);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_i460_subchan_add(NULL, ts, &scd16_2);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_i460_subchan_add(NULL, ts, &scd16_4);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_i460_subchan_add(NULL, ts, &scd16_6);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* demux */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t sequence[20];</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < sizeof(sequence); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+             sequence[i] = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      sequence[0] = 0x03;</span><br><span style="color: hsl(120, 100%, 40%);">+   sequence[1] = 0x0c;</span><br><span style="color: hsl(120, 100%, 40%);">+   sequence[2] = 0x30;</span><br><span style="color: hsl(120, 100%, 40%);">+   sequence[3] = 0xc0;</span><br><span style="color: hsl(120, 100%, 40%);">+   sequence[4] = 0xff;</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_i460_demux_in(ts, sequence, sizeof(sequence));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* mux */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* test with only a single channel active */</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < 4; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct msgb *msg = gen_alternating_bitmsg(128);</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_i460_mux_enqueue(&ts->schan[i], msg);</span><br><span style="color: hsl(120, 100%, 40%);">+             printf("%s-single-%u\n", __func__, i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            uint8_t buf[16];</span><br><span style="color: hsl(120, 100%, 40%);">+              int j;</span><br><span style="color: hsl(120, 100%, 40%);">+                for (j = 0; j < 5; j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_i460_mux_out(ts, buf, sizeof(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+                      printf("mux_out: %s\n", osmo_hexdump(buf, sizeof(buf)));</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < 4; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_i460_subchan_del(&ts->schan[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void test_8k_subchan(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_i460_timeslot _ts, *ts = &_ts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Initialization */</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("\n==> %s\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_i460_ts_init(ts);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_i460_subchan_add(NULL, ts, &scd8_0);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_i460_subchan_add(NULL, ts, &scd8_1);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_i460_subchan_add(NULL, ts, &scd8_2);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_i460_subchan_add(NULL, ts, &scd8_3);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_i460_subchan_add(NULL, ts, &scd8_4);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_i460_subchan_add(NULL, ts, &scd8_5);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_i460_subchan_add(NULL, ts, &scd8_6);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_i460_subchan_add(NULL, ts, &scd8_7);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* demux */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t sequence[40];</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 0; i < sizeof(sequence); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+             sequence[i] = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      i = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        sequence[i++] = 0x01;</span><br><span style="color: hsl(120, 100%, 40%);">+ sequence[i++] = 0x02;</span><br><span style="color: hsl(120, 100%, 40%);">+ sequence[i++] = 0x04;</span><br><span style="color: hsl(120, 100%, 40%);">+ sequence[i++] = 0x08;</span><br><span style="color: hsl(120, 100%, 40%);">+ sequence[i++] = 0x0f;</span><br><span style="color: hsl(120, 100%, 40%);">+ sequence[i++] = 0x10;</span><br><span style="color: hsl(120, 100%, 40%);">+ sequence[i++] = 0x20;</span><br><span style="color: hsl(120, 100%, 40%);">+ sequence[i++] = 0x40;</span><br><span style="color: hsl(120, 100%, 40%);">+ sequence[i++] = 0x80;</span><br><span style="color: hsl(120, 100%, 40%);">+ sequence[i++] = 0xf0;</span><br><span style="color: hsl(120, 100%, 40%);">+ sequence[i++] = 0xff;</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_i460_demux_in(ts, sequence, sizeof(sequence));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* mux */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* test with only a single channel active */</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < 8; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct msgb *msg = gen_alternating_bitmsg(64);</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_i460_mux_enqueue(&ts->schan[i], msg);</span><br><span style="color: hsl(120, 100%, 40%);">+             printf("%s-single-%u\n", __func__, i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            uint8_t buf[16];</span><br><span style="color: hsl(120, 100%, 40%);">+              int j;</span><br><span style="color: hsl(120, 100%, 40%);">+                for (j = 0; j < 5; j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_i460_mux_out(ts, buf, sizeof(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+                      printf("mux_out: %s\n", osmo_hexdump(buf, sizeof(buf)));</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < 8; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_i460_subchan_del(&ts->schan[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* activate only one sub-channel; expect unused bits to be '1' */</span><br><span style="color: hsl(120, 100%, 40%);">+static void test_unused_subchan(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_i460_timeslot _ts, *ts = &_ts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Initialization */</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("\n==> %s\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_i460_ts_init(ts);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_i460_subchan_add(NULL, ts, &scd16_0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* mux */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg = gen_alternating_bitmsg(128);</span><br><span style="color: hsl(120, 100%, 40%);">+       memset(msgb_data(msg), 0, msgb_length(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_i460_mux_enqueue(&ts->schan[0], msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("%s-single\n", __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t buf[16];</span><br><span style="color: hsl(120, 100%, 40%);">+      int j;</span><br><span style="color: hsl(120, 100%, 40%);">+        for (j = 0; j < 5; j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_i460_mux_out(ts, buf, sizeof(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+              printf("mux_out: %s\n", osmo_hexdump(buf, sizeof(buf)));</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_i460_subchan_del(&ts->schan[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int main(int argc, char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ test_no_subchan();</span><br><span style="color: hsl(120, 100%, 40%);">+    test_64k_subchan();</span><br><span style="color: hsl(120, 100%, 40%);">+   test_32k_subchan();</span><br><span style="color: hsl(120, 100%, 40%);">+   test_16k_subchan();</span><br><span style="color: hsl(120, 100%, 40%);">+   test_8k_subchan();</span><br><span style="color: hsl(120, 100%, 40%);">+    test_unused_subchan();</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/tests/i460_mux/i460_mux_test.ok b/tests/i460_mux/i460_mux_test.ok</span><br><span>new file mode 100644</span><br><span>index 0000000..b94fb7b</span><br><span>--- /dev/null</span><br><span>+++ b/tests/i460_mux/i460_mux_test.ok</span><br><span>@@ -0,0 +1,115 @@</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+==> test_no_subchan</span><br><span style="color: hsl(120, 100%, 40%);">+out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+==> test_64k_subchan</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '64k': 0000000000000001000000100000001100000100000001010000011000000111000010000000100100001010000010110000110000001101000011100000111100010000000100010001001000010011000101000001010100010110000101110001100000011001000110100001101100011100000111010001111000011111001000000010000100100010001000110010010000100101001001100010011100101000001010010010101000101011001011000010110100101110001011110011000000110001001100100011001100110100001101010011011000110111001110000011100100111010001110110011110000111101001111100011111101000000010000010100001001000011010001000100010101000110010001110100100001001001010010100100101101001100010011010100111001001111010100000101000101010010010100110101010001010101010101100101011101011000010110010101101001011011010111000101110101011110010111110110000001100001011000100110001101100100011001010110011001100111011010000110100101101010011010110110110001101101011011100110111101110000011100010111001001110011011101000111010101110110011101110111100001111001011110100111101101111100011111010111111001111111</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+==> test_32k_subchan</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '32k_0': 1111000011110000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '32k_4': 0000111111110000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+test_32k_subchan-single-0</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+test_32k_subchan-single-1</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f 5f </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+==> test_16k_subchan</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '16k_0': 1100000011000000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '16k_2': 0011000011000000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '16k_4': 0000110011000000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '16k_6': 0000001111000000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+test_16k_subchan-single-0</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+test_16k_subchan-single-1</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+test_16k_subchan-single-2</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: df df df df df df df df df df df df df df df df </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: df df df df df df df df df df df df df df df df </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: df df df df df df df df df df df df df df df df </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: df df df df df df df df df df df df df df df df </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+test_16k_subchan-single-3</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f 7f </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+==> test_8k_subchan</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '8k_0': 1000100000100000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '8k_1': 0100100000100000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '8k_2': 0010100000100000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '8k_3': 0001100000100000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '8k_4': 0000010001100000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '8k_5': 0000001001100000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '8k_6': 0000000101100000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+demux_bits_cb '8k_7': 0000000011100000000000000000000000000000</span><br><span style="color: hsl(120, 100%, 40%);">+test_8k_subchan-single-0</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fe ff fe ff fe ff fe ff fe ff fe ff fe ff fe ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fe ff fe ff fe ff fe ff fe ff fe ff fe ff fe ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fe ff fe ff fe ff fe ff fe ff fe ff fe ff fe ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fe ff fe ff fe ff fe ff fe ff fe ff fe ff fe ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+test_8k_subchan-single-1</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fd ff fd ff fd ff fd ff fd ff fd ff fd ff fd ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fd ff fd ff fd ff fd ff fd ff fd ff fd ff fd ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fd ff fd ff fd ff fd ff fd ff fd ff fd ff fd ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fd ff fd ff fd ff fd ff fd ff fd ff fd ff fd ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+test_8k_subchan-single-2</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fb ff fb ff fb ff fb ff fb ff fb ff fb ff fb ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fb ff fb ff fb ff fb ff fb ff fb ff fb ff fb ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fb ff fb ff fb ff fb ff fb ff fb ff fb ff fb ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fb ff fb ff fb ff fb ff fb ff fb ff fb ff fb ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+test_8k_subchan-single-3</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: f7 ff f7 ff f7 ff f7 ff f7 ff f7 ff f7 ff f7 ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: f7 ff f7 ff f7 ff f7 ff f7 ff f7 ff f7 ff f7 ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: f7 ff f7 ff f7 ff f7 ff f7 ff f7 ff f7 ff f7 ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: f7 ff f7 ff f7 ff f7 ff f7 ff f7 ff f7 ff f7 ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+test_8k_subchan-single-4</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ef ff ef ff ef ff ef ff ef ff ef ff ef ff ef ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ef ff ef ff ef ff ef ff ef ff ef ff ef ff ef ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ef ff ef ff ef ff ef ff ef ff ef ff ef ff ef ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ef ff ef ff ef ff ef ff ef ff ef ff ef ff ef ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+test_8k_subchan-single-5</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: df ff df ff df ff df ff df ff df ff df ff df ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: df ff df ff df ff df ff df ff df ff df ff df ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: df ff df ff df ff df ff df ff df ff df ff df ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: df ff df ff df ff df ff df ff df ff df ff df ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+test_8k_subchan-single-6</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: bf ff bf ff bf ff bf ff bf ff bf ff bf ff bf ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: bf ff bf ff bf ff bf ff bf ff bf ff bf ff bf ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: bf ff bf ff bf ff bf ff bf ff bf ff bf ff bf ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: bf ff bf ff bf ff bf ff bf ff bf ff bf ff bf ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+test_8k_subchan-single-7</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: 7f ff 7f ff 7f ff 7f ff 7f ff 7f ff 7f ff 7f ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: 7f ff 7f ff 7f ff 7f ff 7f ff 7f ff 7f ff 7f ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: 7f ff 7f ff 7f ff 7f ff 7f ff 7f ff 7f ff 7f ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: 7f ff 7f ff 7f ff 7f ff 7f ff 7f ff 7f ff 7f ff </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+==> test_unused_subchan</span><br><span style="color: hsl(120, 100%, 40%);">+test_unused_subchan-single</span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc </span><br><span style="color: hsl(120, 100%, 40%);">+mux_out: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff </span><br><span>diff --git a/tests/testsuite.at b/tests/testsuite.at</span><br><span>index bab5730..4ff6671 100644</span><br><span>--- a/tests/testsuite.at</span><br><span>+++ b/tests/testsuite.at</span><br><span>@@ -375,3 +375,9 @@</span><br><span> cat $abs_srcdir/exec/exec_test.err > experr</span><br><span> AT_CHECK([$abs_top_builddir/tests/exec/exec_test], [0], [expout], [experr])</span><br><span> AT_CLEANUP</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AT_SETUP([i460_mux])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_KEYWORDS([i460_mux])</span><br><span style="color: hsl(120, 100%, 40%);">+cat $abs_srcdir/i460_mux/i460_mux_test.ok > expout</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CHECK([$abs_top_builddir/tests/i460_mux/i460_mux_test], [0], [expout], [ignore])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CLEANUP</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/18247">change 18247</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/libosmocore/+/18247"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Id522f06e73b77332b437b7a27e4966872da70eda </div>
<div style="display:none"> Gerrit-Change-Number: 18247 </div>
<div style="display:none"> Gerrit-PatchSet: 11 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: tnt <tnt@246tNt.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>