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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Add new "osmo-e1gen" program.<br><br>osmo-e1gen is a program that re-uses large parts of osmo-e1d, but whose<br>main purpose is to generate a variety of error conditions in order to<br>test a remote E1 implementation.<br><br>Instead of using the automatisms of the icE1usb transmit IP core, it<br>switches it to transparent mode and uses a host-software based E1 framer<br>"osmo_e1f", over which we have more control than the firmware.<br><br>Change-Id: I53a86d6730eb76a9cff9eb3f4786139015c91230<br>---<br>M src/Makefile.am<br>M src/e1d.h<br>A src/e1gen/crc4itu.c<br>A src/e1gen/crc4itu.h<br>A src/e1gen/osmo_e1f.c<br>A src/e1gen/osmo_e1f.h<br>A src/osmo-e1gen.c<br>7 files changed, 1,449 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/Makefile.am b/src/Makefile.am</span><br><span>index fd61f5a..d245bc6 100644</span><br><span>--- a/src/Makefile.am</span><br><span>+++ b/src/Makefile.am</span><br><span>@@ -24,6 +24,8 @@</span><br><span>   ice1usb_proto.h \</span><br><span>    log.h \</span><br><span>      usb.h \</span><br><span style="color: hsl(120, 100%, 40%);">+       e1gen/crc4itu.h \</span><br><span style="color: hsl(120, 100%, 40%);">+     e1gen/osmo_e1f.h \</span><br><span>   $(NULL)</span><br><span> </span><br><span> </span><br><span>@@ -32,6 +34,10 @@</span><br><span>         osmo-e1d-pipe \</span><br><span>      $(NULL)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+noinst_PROGRAMS = \</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo-e1gen \</span><br><span style="color: hsl(120, 100%, 40%);">+  $(NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> osmo_e1d_SOURCES = \</span><br><span>    ctl.c \</span><br><span>      intf_line.c \</span><br><span>@@ -51,3 +57,17 @@</span><br><span>   $(NULL)</span><br><span> </span><br><span> osmo_e1d_pipe_LDADD = $(LIBOSMOCORE_LIBS) libosmo-e1d.la</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_e1gen_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+                 $(LIBOSMOUSB_LIBS) $(LIBUSB_LIBS)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_e1gen_SOURCES = \</span><br><span style="color: hsl(120, 100%, 40%);">+        intf_line.c \</span><br><span style="color: hsl(120, 100%, 40%);">+ log.c \</span><br><span style="color: hsl(120, 100%, 40%);">+       e1gen/crc4itu.c \</span><br><span style="color: hsl(120, 100%, 40%);">+     e1gen/osmo_e1f.c \</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo-e1gen.c \</span><br><span style="color: hsl(120, 100%, 40%);">+        usb.c \</span><br><span style="color: hsl(120, 100%, 40%);">+       vty.c \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(NULL)</span><br><span>diff --git a/src/e1d.h b/src/e1d.h</span><br><span>index 7cb5335..70bca38 100644</span><br><span>--- a/src/e1d.h</span><br><span>+++ b/src/e1d.h</span><br><span>@@ -120,6 +120,8 @@</span><br><span>               /*! timer to re-set the rx_crc4_err and rx_alarm above */</span><br><span>            struct osmo_timer_list timer;</span><br><span>        } ts0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      void *e1gen_priv;</span><br><span> };</span><br><span> </span><br><span> enum e1_driver {</span><br><span>diff --git a/src/e1gen/crc4itu.c b/src/e1gen/crc4itu.c</span><br><span>new file mode 100644</span><br><span>index 0000000..f13895a</span><br><span>--- /dev/null</span><br><span>+++ b/src/e1gen/crc4itu.c</span><br><span>@@ -0,0 +1,56 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \file</span><br><span style="color: hsl(120, 100%, 40%);">+ * Functions and types for CRC checks.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Generated on Sat May 12 09:39:22 2018</span><br><span style="color: hsl(120, 100%, 40%);">+ * by pycrc v0.9.1, https://pycrc.org</span><br><span style="color: hsl(120, 100%, 40%);">+ * using the configuration:</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - Width         = 4</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - Poly          = 0x3</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - XorIn         = 0x0</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - ReflectIn     = False</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - XorOut        = 0x0</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - ReflectOut    = False</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - Algorithm     = table-driven</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#include "crc4itu.h"     /* include the header file generated with pycrc */</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></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 table used for the table_driven implementation.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static const crc_t crc_table[256] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x05, 0x06, 0x03, 0x00, 0x09, 0x0a, 0x0f, 0x0c, 0x0e, 0x0d, 0x08, 0x0b, 0x02, 0x01, 0x04, 0x07,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x0a, 0x09, 0x0c, 0x0f, 0x06, 0x05, 0x00, 0x03, 0x01, 0x02, 0x07, 0x04, 0x0d, 0x0e, 0x0b, 0x08,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x0f, 0x0c, 0x09, 0x0a, 0x03, 0x00, 0x05, 0x06, 0x04, 0x07, 0x02, 0x01, 0x08, 0x0b, 0x0e, 0x0d,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x07, 0x04, 0x01, 0x02, 0x0b, 0x08, 0x0d, 0x0e, 0x0c, 0x0f, 0x0a, 0x09, 0x00, 0x03, 0x06, 0x05,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x02, 0x01, 0x04, 0x07, 0x0e, 0x0d, 0x08, 0x0b, 0x09, 0x0a, 0x0f, 0x0c, 0x05, 0x06, 0x03, 0x00,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x0d, 0x0e, 0x0b, 0x08, 0x01, 0x02, 0x07, 0x04, 0x06, 0x05, 0x00, 0x03, 0x0a, 0x09, 0x0c, 0x0f,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x08, 0x0b, 0x0e, 0x0d, 0x04, 0x07, 0x02, 0x01, 0x03, 0x00, 0x05, 0x06, 0x0f, 0x0c, 0x09, 0x0a,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x0e, 0x0d, 0x08, 0x0b, 0x02, 0x01, 0x04, 0x07, 0x05, 0x06, 0x03, 0x00, 0x09, 0x0a, 0x0f, 0x0c,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x04, 0x07, 0x02, 0x01, 0x08, 0x0b, 0x0e, 0x0d, 0x0f, 0x0c, 0x09, 0x0a, 0x03, 0x00, 0x05, 0x06,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x01, 0x02, 0x07, 0x04, 0x0d, 0x0e, 0x0b, 0x08, 0x0a, 0x09, 0x0c, 0x0f, 0x06, 0x05, 0x00, 0x03,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x09, 0x0a, 0x0f, 0x0c, 0x05, 0x06, 0x03, 0x00, 0x02, 0x01, 0x04, 0x07, 0x0e, 0x0d, 0x08, 0x0b,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x0c, 0x0f, 0x0a, 0x09, 0x00, 0x03, 0x06, 0x05, 0x07, 0x04, 0x01, 0x02, 0x0b, 0x08, 0x0d, 0x0e,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x03, 0x00, 0x05, 0x06, 0x0f, 0x0c, 0x09, 0x0a, 0x08, 0x0b, 0x0e, 0x0d, 0x04, 0x07, 0x02, 0x01,</span><br><span style="color: hsl(120, 100%, 40%);">+    0x06, 0x05, 0x00, 0x03, 0x0a, 0x09, 0x0c, 0x0f, 0x0d, 0x0e, 0x0b, 0x08, 0x01, 0x02, 0x07, 0x04</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%);">+crc_t crc4itu_update(crc_t crc, const void *data, size_t data_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    const unsigned char *d = (const unsigned char *)data;</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int tbl_idx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    while (data_len--) {</span><br><span style="color: hsl(120, 100%, 40%);">+        tbl_idx = (crc << 4) ^ *d;</span><br><span style="color: hsl(120, 100%, 40%);">+        crc = crc_table[tbl_idx] & 0xf;</span><br><span style="color: hsl(120, 100%, 40%);">+        d++;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+    return crc & 0xf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/e1gen/crc4itu.h b/src/e1gen/crc4itu.h</span><br><span>new file mode 100644</span><br><span>index 0000000..220b50f</span><br><span>--- /dev/null</span><br><span>+++ b/src/e1gen/crc4itu.h</span><br><span>@@ -0,0 +1,106 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \file</span><br><span style="color: hsl(120, 100%, 40%);">+ * Functions and types for CRC checks.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Generated on Sat May 12 09:41:12 2018</span><br><span style="color: hsl(120, 100%, 40%);">+ * by pycrc v0.9.1, https://pycrc.org</span><br><span style="color: hsl(120, 100%, 40%);">+ * using the configuration:</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - Width         = 4</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - Poly          = 0x3</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - XorIn         = 0x0</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - ReflectIn     = False</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - XorOut        = 0x0</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - ReflectOut    = False</span><br><span style="color: hsl(120, 100%, 40%);">+ *  - Algorithm     = table-driven</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This file defines the functions crc4itu_init(), crc4itu_update() and crc_finalize().</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The crc4itu_init() function returns the inital \c crc value and must be called</span><br><span style="color: hsl(120, 100%, 40%);">+ * before the first call to crc4itu_update().</span><br><span style="color: hsl(120, 100%, 40%);">+ * Similarly, the crc_finalize() function must be called after the last call</span><br><span style="color: hsl(120, 100%, 40%);">+ * to crc4itu_update(), before the \c crc is being used.</span><br><span style="color: hsl(120, 100%, 40%);">+ * is being used.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The crc4itu_update() function can be called any number of times (including zero</span><br><span style="color: hsl(120, 100%, 40%);">+ * times) in between the crc4itu_init() and crc_finalize() calls.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This pseudo-code shows an example usage of the API:</span><br><span style="color: hsl(120, 100%, 40%);">+ * \code{.c}</span><br><span style="color: hsl(120, 100%, 40%);">+ * crc_t crc;</span><br><span style="color: hsl(120, 100%, 40%);">+ * unsigned char data[MAX_DATA_LEN];</span><br><span style="color: hsl(120, 100%, 40%);">+ * size_t data_len;</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * crc = crc4itu_init();</span><br><span style="color: hsl(120, 100%, 40%);">+ * while ((data_len = read_data(data, MAX_DATA_LEN)) > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *     crc = crc4itu_update(crc, data, data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ * }</span><br><span style="color: hsl(120, 100%, 40%);">+ * crc = crc_finalize(crc);</span><br><span style="color: hsl(120, 100%, 40%);">+ * \endcode</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef CRC4ITU_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define CRC4ITU_H</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</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%);">+ * The definition of the used algorithm.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is not used anywhere in the generated code, but it may be used by the</span><br><span style="color: hsl(120, 100%, 40%);">+ * application code to call algorithm-specific code, if desired.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define CRC_ALGO_TABLE_DRIVEN 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%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * The type of the CRC values.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This type must be big enough to contain at least 4 bits.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+typedef uint_fast8_t crc_t;</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%);">+ * Calculate the initial crc value.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return     The initial crc value.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static inline crc_t crc4itu_init(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0x0;</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%);">+ * Update the crc value with new data.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] crc      The current crc value.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] data     Pointer to a buffer of \a data_len bytes.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] data_len Number of bytes in the \a data buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return             The updated crc value.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+crc_t crc4itu_update(crc_t crc, const void *data, size_t 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%);">+ * Calculate the final crc value.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] crc  The current crc value.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return     The final crc value.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static inline crc_t crc_finalize(crc_t crc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return crc;</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%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+}           /* closing brace for extern "C" */</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif      /* CRC4ITU_H */</span><br><span>diff --git a/src/e1gen/osmo_e1f.c b/src/e1gen/osmo_e1f.c</span><br><span>new file mode 100644</span><br><span>index 0000000..fa64e17</span><br><span>--- /dev/null</span><br><span>+++ b/src/e1gen/osmo_e1f.c</span><br><span>@@ -0,0 +1,704 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Osmocom Software Defined E1</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2018 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Implements ITU-T Rec. G.704 Section 2.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%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+</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/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "crc4itu.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "osmo_e1f.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define S(x)      (1 << (x))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Frame Alignment Signal (BIT1 may be overwritten with CRC-4) */</span><br><span style="color: hsl(120, 100%, 40%);">+#define G704_E1_FAS      0x1B</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static inline bool is_correct_fas(uint8_t bt) {</span><br><span style="color: hsl(120, 100%, 40%);">+       if ((bt & 0x7F) == G704_E1_FAS)</span><br><span style="color: hsl(120, 100%, 40%);">+           return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  else</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* are we in SMF II (true) or I (false) */</span><br><span style="color: hsl(120, 100%, 40%);">+static inline bool is_smf_II(const struct osmo_e1f_tx_state *tx) {</span><br><span style="color: hsl(120, 100%, 40%);">+    if (tx->frame_nr >= 8)</span><br><span style="color: hsl(120, 100%, 40%);">+          return true;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm e1_align_fsm;</span><br><span style="color: hsl(120, 100%, 40%);">+static void align_fsm_reset(struct osmo_e1f_instance *e1i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void notify_user(struct osmo_e1f_instance *e1i, enum osmo_e1f_notify_event evt,</span><br><span style="color: hsl(120, 100%, 40%);">+                       bool present, void *priv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!e1i->notify_cb)</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+       e1i->notify_cb(e1i, evt, present, priv);</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 a (caller-allocated) Osmocom E1 Instance</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[inout] e1i E1 Instance to be initialized</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success, negative on error */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_e1f_instance_init(struct osmo_e1f_instance *e1i, const char *name, e1_notify_cb cb,</span><br><span style="color: hsl(120, 100%, 40%);">+                   bool crc4_enabled, void *priv)</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%);">+      e1i->crc4_enabled = crc4_enabled;</span><br><span style="color: hsl(120, 100%, 40%);">+  e1i->notify_cb = cb;</span><br><span style="color: hsl(120, 100%, 40%);">+       e1i->tx.sa4_sa8 = 0x1f;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  e1i->priv = priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 1; i < ARRAY_SIZE(e1i->ts); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             struct osmo_e1f_instance_ts *e1t = &e1i->ts[i];</span><br><span style="color: hsl(120, 100%, 40%);">+                e1t->ts_nr = i;</span><br><span style="color: hsl(120, 100%, 40%);">+            e1t->inst = e1i;</span><br><span style="color: hsl(120, 100%, 40%);">+           INIT_LLIST_HEAD(&e1t->tx.queue);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             e1t->rx.granularity = 256;</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%);">+   e1i->rx.fi = osmo_fsm_inst_alloc(&e1_align_fsm, NULL, e1i, LOGL_DEBUG, name);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!e1i->rx.fi)</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%);">+  osmo_e1f_instance_reset(e1i);</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%);">+/*! stop E1 timeslot; release any pending rx/tx buffers</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] e1t Timeslot which we are to stop, disable and release buffers */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_e1f_ts_reset(struct osmo_e1f_instance_ts *e1t)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        e1t->tx.underruns = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_queue_free(&e1t->tx.queue);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     e1t->rx.enabled = false;</span><br><span style="color: hsl(120, 100%, 40%);">+   msgb_free(e1t->rx.msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    e1t->rx.msg = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_isdnhdlc_rcv_init(&e1t->rx.hdlc, OSMO_HDLC_F_BITREVERSE);</span><br><span style="color: hsl(120, 100%, 40%);">+ //osmo_isdnhdlc_rcv_init(&e1t->rx.hdlc, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_isdnhdlc_out_init(&e1t->tx.hdlc, 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%);">+/*! stop E1 instance; stops all timeslots and releases any pending rx/tx buffers</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] e1t E1 instance which we are to stop */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_e1f_instance_reset(struct osmo_e1f_instance *e1i)</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%);">+      align_fsm_reset(e1i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       e1i->tx.remote_alarm = false;</span><br><span style="color: hsl(120, 100%, 40%);">+      e1i->tx.crc4_error = false;</span><br><span style="color: hsl(120, 100%, 40%);">+        e1i->tx.frame_nr = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      e1i->tx.crc4_last_smf = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ e1i->tx.crc4 = crc4itu_init();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   e1i->rx.frame_nr = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      memset(&e1i->rx.ts0_history, 0, sizeof(e1i->rx.ts0_history));</span><br><span style="color: hsl(120, 100%, 40%);">+       e1i->rx.ts0_hist_len = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  e1i->rx.remote_alarm = false;</span><br><span style="color: hsl(120, 100%, 40%);">+      e1i->rx.remote_crc4_error = false;</span><br><span style="color: hsl(120, 100%, 40%);">+ e1i->rx.num_ts0_in_mframe_search = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    for (i = 1; i < ARRAY_SIZE(e1i->ts); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             struct osmo_e1f_instance_ts *e1t = &e1i->ts[i];</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_e1f_ts_reset(e1t);</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%);">+/*! obtain pointer to TS given by instance + timeslot number</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] e1i E1 intance on which we work</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ts_nr E1 timeslot number (1..31)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns pointer to timeslot; NULL on error */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_e1f_instance_ts *osmo_e1f_instance_ts(struct osmo_e1f_instance *e1i, uint8_t ts_nr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ts_nr == 0 || ts_nr >= ARRAY_SIZE(e1i->ts))</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%);">+        return &e1i->ts[ts_nr];</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%);">+/*! configure an E1 timeslot</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] e1t Timeslot which we are to configure</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] granularity granularity (buffer size) to use on Rx</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] enable enable (true) or disalble (false) receiving on this TS</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] mode the mode for this timeslot (raw or hdlc)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \return 0 on success; negative on error */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_e1f_ts_config(struct osmo_e1f_instance_ts *e1t, e1_data_cb cb, unsigned int granularity,</span><br><span style="color: hsl(120, 100%, 40%);">+                  bool enable, enum osmo_e1f_ts_mode mode)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     e1t->rx.data_cb = cb;</span><br><span style="color: hsl(120, 100%, 40%);">+      e1t->rx.enabled = enable;</span><br><span style="color: hsl(120, 100%, 40%);">+  e1t->rx.granularity = granularity;</span><br><span style="color: hsl(120, 100%, 40%);">+ e1t->mode = mode;</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%);">+const struct value_string osmo_e1f_notifv_evt_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+     { E1_NTFY_EVT_ALIGN_FRAME, "Aligned to Frame" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { E1_NTFY_EVT_ALIGN_CRC_MFRAME, "Aligned to CRC4-Multiframe" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { E1_NTFY_EVT_CRC_ERROR, "CRC Error detected (local)" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { E1_NTFY_EVT_REMOTE_CRC_ERROR, "CRC Error reported (remote)" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { E1_NTFY_EVT_REMOTE_ALARM, "Remote Alarm condition repoorted" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { 0, 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%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * Transmit Side</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 message buffer of to-be-transmitted data for a timeslot</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] e1i E1 instance for which to enqueue</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ts_nr Timeslot number on which data is to be transmitted</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] msg Message buffer storing the to-be-transmitted data</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success; negative in case of error.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  Ownership of \a msg is transferred from caller into this function, but only</span><br><span style="color: hsl(120, 100%, 40%);">+ *  in case of successful execution (return 0)!</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_e1f_ts_enqueue(struct osmo_e1f_instance_ts *e1t, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      msgb_enqueue(&e1t->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%);">+/* obtain a CRC4 bit for the current frame number */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t e1_pull_crc4_bit(struct osmo_e1f_instance *e1i)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       /* If CRC-4 is disabled, all CRC bits shall be '1' */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (e1i->crc4_enabled == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return 0x01;</span><br><span style="color: hsl(120, 100%, 40%);">+  } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* CRC is transmitted MSB first */</span><br><span style="color: hsl(120, 100%, 40%);">+            switch (e1i->tx.frame_nr % 8) {</span><br><span style="color: hsl(120, 100%, 40%);">+            case 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                       return (e1i->tx.crc4_last_smf >> 3) & 1;</span><br><span style="color: hsl(120, 100%, 40%);">+         case 2:</span><br><span style="color: hsl(120, 100%, 40%);">+                       return (e1i->tx.crc4_last_smf >> 2) & 1;</span><br><span style="color: hsl(120, 100%, 40%);">+         case 4:</span><br><span style="color: hsl(120, 100%, 40%);">+                       return (e1i->tx.crc4_last_smf >> 1) & 1;</span><br><span style="color: hsl(120, 100%, 40%);">+         case 6:</span><br><span style="color: hsl(120, 100%, 40%);">+                       return (e1i->tx.crc4_last_smf >> 0) & 1;</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%);">+/* pull a single to-be-transmitted byte for TS0 */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t e1_pull_ts0(struct osmo_e1f_instance *e1i)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t ret = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* re-set CRC4 at start of sub-multiframe */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (e1i->tx.frame_nr == 0 || e1i->tx.frame_nr == 8) {</span><br><span style="color: hsl(120, 100%, 40%);">+           e1i->tx.crc4_last_smf = e1i->tx.crc4;</span><br><span style="color: hsl(120, 100%, 40%);">+           e1i->tx.crc4 = 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%);">+   /* according to Table 5B/G.704 - CRC-4 multiframe structure */</span><br><span style="color: hsl(120, 100%, 40%);">+        if ((e1i->tx.frame_nr % 2) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+         /* FAS */</span><br><span style="color: hsl(120, 100%, 40%);">+             ret = G704_E1_FAS | (e1_pull_crc4_bit(e1i) << 7);</span><br><span style="color: hsl(120, 100%, 40%);">+       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              switch (e1i->tx.frame_nr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                case 1:</span><br><span style="color: hsl(120, 100%, 40%);">+               case 3:</span><br><span style="color: hsl(120, 100%, 40%);">+               case 7:</span><br><span style="color: hsl(120, 100%, 40%);">+                       ret = 0x40;</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 5:</span><br><span style="color: hsl(120, 100%, 40%);">+               case 9:</span><br><span style="color: hsl(120, 100%, 40%);">+               case 11:</span><br><span style="color: hsl(120, 100%, 40%);">+                      ret = 0xC0;</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 13:</span><br><span style="color: hsl(120, 100%, 40%);">+              case 15:</span><br><span style="color: hsl(120, 100%, 40%);">+                      ret = 0x40;</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (!e1i->tx.crc4_error)</span><br><span style="color: hsl(120, 100%, 40%);">+                           ret |= 0x80;</span><br><span style="color: hsl(120, 100%, 40%);">+                  break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             ret |= e1i->tx.sa4_sa8;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (e1i->tx.remote_alarm)</span><br><span style="color: hsl(120, 100%, 40%);">+                  ret |= 0x20;</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%);">+   /* increment frame number modulo 16 */</span><br><span style="color: hsl(120, 100%, 40%);">+        e1i->tx.frame_nr = (e1i->tx.frame_nr + 1) % 16;</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%);">+/* pull a single to-be-transmitted byte for TS1..31 */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t e1_pull_tsN(struct osmo_e1f_instance_ts *e1t)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct msgb *msg = llist_first_entry_or_null(&e1t->tx.queue, struct msgb, list);</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t *cur;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+retry:</span><br><span style="color: hsl(120, 100%, 40%);">+       /* if there's no message to transmit */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           e1t->tx.underruns++;</span><br><span style="color: hsl(120, 100%, 40%);">+               return 0xFF;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</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%);">+         msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+               msg = llist_first_entry_or_null(&e1t->tx.queue, struct msgb, list);</span><br><span style="color: hsl(120, 100%, 40%);">+            goto retry;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     cur = msgb_pull(msg, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+      return *cur;</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%);">+/* update the current in-progress CRC4 value with data from \a out_frame */</span><br><span style="color: hsl(120, 100%, 40%);">+static void e1_tx_update_crc4(struct osmo_e1f_instance *e1i, const uint8_t *out_frame)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t ts0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ts0 = out_frame[0];</span><br><span style="color: hsl(120, 100%, 40%);">+   /* mask off the C bits */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (is_correct_fas(ts0))</span><br><span style="color: hsl(120, 100%, 40%);">+              ts0 &= 0x7F;</span><br><span style="color: hsl(120, 100%, 40%);">+      e1i->tx.crc4 = crc4itu_update(e1i->tx.crc4, &ts0, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+       /* add the remaining bytes/bits */</span><br><span style="color: hsl(120, 100%, 40%);">+    e1i->tx.crc4 = crc4itu_update(e1i->tx.crc4, out_frame+1, ARRAY_SIZE(e1i->ts)-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%);">+/*! Pull one to-be-transmitted E1 frame (256bits) from the E1 instance</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param e1i E1 instance for which the frame shall be generated</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] out_frame callee-allocated buffer to which function stores 32 bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success, negative on error */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_e1f_pull_tx_frame(struct osmo_e1f_instance *e1i, uint8_t *out_frame)</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%);">+      if (e1i->tx.ais) {</span><br><span style="color: hsl(120, 100%, 40%);">+         memset(out_frame, 0xff, 32);</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%);">+   /* generate TS0 */</span><br><span style="color: hsl(120, 100%, 40%);">+    out_frame[0] = e1_pull_ts0(e1i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* generate TS1..31 */</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 1; i < ARRAY_SIZE(e1i->ts); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             struct osmo_e1f_instance_ts *e1t = &e1i->ts[i];</span><br><span style="color: hsl(120, 100%, 40%);">+                /* get next to-be-transmitted byte from the TS */</span><br><span style="color: hsl(120, 100%, 40%);">+             out_frame[i] = e1_pull_tsN(e1t);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* update our CRC4 computation */</span><br><span style="color: hsl(120, 100%, 40%);">+     e1_tx_update_crc4(e1i, out_frame);</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%);">+ * Receiver Side</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%);">+/* According to Figure 2 / ITU-T G.706 */</span><br><span style="color: hsl(120, 100%, 40%);">+enum e1_align_state {</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Frame Alignment Search */</span><br><span style="color: hsl(120, 100%, 40%);">+  E1_AS_SEARCH_FRAME,</span><br><span style="color: hsl(120, 100%, 40%);">+   /* CRC multiframe alignment search */</span><br><span style="color: hsl(120, 100%, 40%);">+ E1_AS_SEARCH_CRC_MFRAME,</span><br><span style="color: hsl(120, 100%, 40%);">+      /* monitoring for incorrect frame alignment and error performance using CRC */</span><br><span style="color: hsl(120, 100%, 40%);">+        E1_AS_ALIGNED_CRC_MFRAME,</span><br><span style="color: hsl(120, 100%, 40%);">+     /* no CRC: just frame alignment loss check */</span><br><span style="color: hsl(120, 100%, 40%);">+ E1_AS_ALIGNED_BASIC,</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%);">+enum e1_align_event {</span><br><span style="color: hsl(120, 100%, 40%);">+     /* received a TS0 octet */</span><br><span style="color: hsl(120, 100%, 40%);">+    E1_AE_RX_TS0,</span><br><span style="color: hsl(120, 100%, 40%);">+ E1_AE_RESET</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 const struct value_string e1_align_evt_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+  { E1_AE_RX_TS0, "E1_AE_RX_TS0" },</span><br><span style="color: hsl(120, 100%, 40%);">+   { E1_AE_RESET, "E1_AE_RESET" },</span><br><span style="color: hsl(120, 100%, 40%);">+     { 0, 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%);">+/* get a TS0 byte from the history. delta 0 == current, delte 1 == previous, ... */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t get_ts0_hist(struct osmo_e1f_instance *e1i, uint8_t delta)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return e1i->rx.ts0_history[((e1i->rx.frame_nr + 16)-delta) % 16];</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%);">+/* ITU-T G.706 Section 4.1.1 */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool frame_alignment_lost(struct osmo_e1f_instance *e1i)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (e1i->rx.frame_nr % 2)</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%);">+       /* Frame alignment will be assumed to have been lost when three consecutive incorrect</span><br><span style="color: hsl(120, 100%, 40%);">+  * frame alignment signals have been received. */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!is_correct_fas(get_ts0_hist(e1i, 0)) &&</span><br><span style="color: hsl(120, 100%, 40%);">+      !is_correct_fas(get_ts0_hist(e1i, 2)) &&</span><br><span style="color: hsl(120, 100%, 40%);">+      !is_correct_fas(get_ts0_hist(e1i, 4)))</span><br><span style="color: hsl(120, 100%, 40%);">+            return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  else</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* ITU-T G.706 Section 4.1.2 */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool frame_alignment_recovered(struct osmo_e1f_instance *e1i)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  /* two consecutive FAS with one non-FAS interspersed */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (is_correct_fas(get_ts0_hist(e1i, 0)) &&</span><br><span style="color: hsl(120, 100%, 40%);">+       !is_correct_fas(get_ts0_hist(e1i, 1)) &&</span><br><span style="color: hsl(120, 100%, 40%);">+      is_correct_fas(get_ts0_hist(e1i, 2)))</span><br><span style="color: hsl(120, 100%, 40%);">+             return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  else</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* ITU-T G.706 Section 4.2 */</span><br><span style="color: hsl(120, 100%, 40%);">+static bool crc_mframe_alignment_achieved(struct osmo_e1f_instance *e1i)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        /* if current TS0 byte is FAS, we cannot detect alignment */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (is_correct_fas(get_ts0_hist(e1i, 0)))</span><br><span style="color: hsl(120, 100%, 40%);">+             return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((get_ts0_hist(e1i, 0) >> 7) == 1 &&</span><br><span style="color: hsl(120, 100%, 40%);">+     (get_ts0_hist(e1i, 2) >> 7) == 1 &&</span><br><span style="color: hsl(120, 100%, 40%);">+     (get_ts0_hist(e1i, 4) >> 7) == 0 &&</span><br><span style="color: hsl(120, 100%, 40%);">+     (get_ts0_hist(e1i, 6) >> 7) == 1 &&</span><br><span style="color: hsl(120, 100%, 40%);">+     (get_ts0_hist(e1i, 8) >> 7) == 0 &&</span><br><span style="color: hsl(120, 100%, 40%);">+     (get_ts0_hist(e1i, 10) >> 7) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  else</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Get the CRC4 that was received from our Rx TS0 history */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t crc4_from_ts0_hist(struct osmo_e1f_instance *e1i, bool smf2)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t crc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t offset = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (smf2)</span><br><span style="color: hsl(120, 100%, 40%);">+             offset = 8;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ crc |= (e1i->rx.ts0_history[0+offset] >> 7) << 3;</span><br><span style="color: hsl(120, 100%, 40%);">+      crc |= (e1i->rx.ts0_history[2+offset] >> 7) << 2;</span><br><span style="color: hsl(120, 100%, 40%);">+      crc |= (e1i->rx.ts0_history[4+offset] >> 7) << 1;</span><br><span style="color: hsl(120, 100%, 40%);">+      crc |= (e1i->rx.ts0_history[6+offset] >> 7) << 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return crc;</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%);">+/* update the current in-progress CRC4 value with data from \a rx_frame */</span><br><span style="color: hsl(120, 100%, 40%);">+static void e1_rx_update_crc4(struct osmo_e1f_instance *e1i, const uint8_t *rx_frame)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t ts0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        ts0 = rx_frame[0];</span><br><span style="color: hsl(120, 100%, 40%);">+    /* mask off the C bits */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (is_correct_fas(ts0))</span><br><span style="color: hsl(120, 100%, 40%);">+              ts0 &= 0x7F;</span><br><span style="color: hsl(120, 100%, 40%);">+      e1i->rx.crc4 = crc4itu_update(e1i->rx.crc4, &ts0, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+       /* add the remaining bytes/bits */</span><br><span style="color: hsl(120, 100%, 40%);">+    e1i->rx.crc4 = crc4itu_update(e1i->rx.crc4, rx_frame+1, ARRAY_SIZE(e1i->ts)-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%);">+/* FSM State handler */</span><br><span style="color: hsl(120, 100%, 40%);">+static void e1_align_search_frame(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_e1f_instance *e1i = (struct osmo_e1f_instance *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (frame_alignment_recovered(e1i)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         /* if we detected the 2nd FAS, we must be in FN 2 (or at least FN%2=0 */</span><br><span style="color: hsl(120, 100%, 40%);">+              e1i->rx.frame_nr = 2;</span><br><span style="color: hsl(120, 100%, 40%);">+              notify_user(e1i, E1_NTFY_EVT_ALIGN_FRAME, true, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_fsm_inst_state_chg(fi, E1_AS_SEARCH_CRC_MFRAME, 0, 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%);">+/* FSM State handler */</span><br><span style="color: hsl(120, 100%, 40%);">+static void e1_align_search_crc_mframe(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_e1f_instance *e1i = (struct osmo_e1f_instance *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (crc_mframe_alignment_achieved(e1i)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* if we detected the 6-bit CRC multiframe signal, we must be in FN 11 */</span><br><span style="color: hsl(120, 100%, 40%);">+             e1i->rx.frame_nr = 11;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* FIXME: "at least two valid CRC multiframe alignment signals can be located within</span><br><span style="color: hsl(120, 100%, 40%);">+              * 8 ms, the time separating two CRC multiframe alignment signals being 2 ms or a</span><br><span style="color: hsl(120, 100%, 40%);">+              * multiple of 2 ms" */</span><br><span style="color: hsl(120, 100%, 40%);">+          notify_user(e1i, E1_NTFY_EVT_ALIGN_CRC_MFRAME, true, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_state_chg(fi, E1_AS_ALIGNED_CRC_MFRAME, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* if no mframe alignment is established within 8ms (64 frames), fall back */</span><br><span style="color: hsl(120, 100%, 40%);">+         if (e1i->rx.num_ts0_in_mframe_search >= 64) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   e1i->rx.num_ts0_in_mframe_search = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_fsm_inst_state_chg(fi, E1_AS_SEARCH_FRAME, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             e1i->rx.num_ts0_in_mframe_search++;</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 e1_aligned_common(struct osmo_e1f_instance *e1i)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t inb = get_ts0_hist(e1i, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* All non-FAS frames contain "A" bit in TS0 */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!is_correct_fas(inb & 0x7F)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                bool old_alarm = e1i->rx.remote_alarm;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* frame not containing the frame alignment signal */</span><br><span style="color: hsl(120, 100%, 40%);">+         if (inb & 0x20)</span><br><span style="color: hsl(120, 100%, 40%);">+                   e1i->rx.remote_alarm = true;</span><br><span style="color: hsl(120, 100%, 40%);">+               else</span><br><span style="color: hsl(120, 100%, 40%);">+                  e1i->rx.remote_alarm = false;</span><br><span style="color: hsl(120, 100%, 40%);">+              if (old_alarm != e1i->rx.remote_alarm)</span><br><span style="color: hsl(120, 100%, 40%);">+                     notify_user(e1i, E1_NTFY_EVT_REMOTE_ALARM, e1i->rx.remote_alarm, 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* FSM State handler */</span><br><span style="color: hsl(120, 100%, 40%);">+static void e1_aligned_crc_mframe(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_e1f_instance *e1i = (struct osmo_e1f_instance *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (frame_alignment_lost(e1i)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_fsm_inst_state_chg(fi, E1_AS_SEARCH_FRAME, 0, 0);</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%);">+   if (e1i->crc4_enabled) {</span><br><span style="color: hsl(120, 100%, 40%);">+           uint8_t crc_rx;</span><br><span style="color: hsl(120, 100%, 40%);">+               bool crc4_error;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            /* check if we just received a complete CRC4 */</span><br><span style="color: hsl(120, 100%, 40%);">+               switch (e1i->rx.frame_nr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                case 7:</span><br><span style="color: hsl(120, 100%, 40%);">+               case 15:</span><br><span style="color: hsl(120, 100%, 40%);">+                      crc_rx = crc4_from_ts0_hist(e1i, e1i->rx.frame_nr == 15 ? true : false);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (crc_rx != e1i->rx.crc4_last_smf)</span><br><span style="color: hsl(120, 100%, 40%);">+                               crc4_error = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                    else</span><br><span style="color: hsl(120, 100%, 40%);">+                          crc4_error = false;</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (crc4_error != e1i->tx.crc4_error) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            notify_user(e1i, E1_NTFY_EVT_CRC_ERROR, crc4_error, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                            e1i->tx.crc4_error = crc4_error;</span><br><span style="color: hsl(120, 100%, 40%);">+                   }</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* rotate computed CRC4 one further */</span><br><span style="color: hsl(120, 100%, 40%);">+                        e1i->rx.crc4_last_smf = e1i->rx.crc4;</span><br><span style="color: hsl(120, 100%, 40%);">+                   e1i->rx.crc4 = crc4itu_init();</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%);">+                      break;</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%);">+           /* check if the remote side reports any CRC errors */</span><br><span style="color: hsl(120, 100%, 40%);">+         switch (e1i->rx.frame_nr) {</span><br><span style="color: hsl(120, 100%, 40%);">+                case 13:</span><br><span style="color: hsl(120, 100%, 40%);">+              case 15:</span><br><span style="color: hsl(120, 100%, 40%);">+                      crc4_error = false;</span><br><span style="color: hsl(120, 100%, 40%);">+                   if ((get_ts0_hist(e1i, 0) >> 7) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                           crc4_error = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (crc4_error != e1i->rx.remote_crc4_error) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             notify_user(e1i, E1_NTFY_EVT_REMOTE_CRC_ERROR, crc4_error, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                             e1i->rx.remote_crc4_error = crc4_error;</span><br><span style="color: hsl(120, 100%, 40%);">+                    }</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</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%);">+   e1_aligned_common(e1i);</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%);">+/* FSM State handler */</span><br><span style="color: hsl(120, 100%, 40%);">+static void e1_aligned_basic(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_e1f_instance *e1i = (struct osmo_e1f_instance *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (frame_alignment_lost(e1i)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_fsm_inst_state_chg(fi, E1_AS_SEARCH_FRAME, 0, 0);</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%);">+   e1_aligned_common(e1i);</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 const struct osmo_fsm_state e1_align_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        [E1_AS_SEARCH_FRAME] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              .name = "SEARCH_FRAME",</span><br><span style="color: hsl(120, 100%, 40%);">+             .in_event_mask = S(E1_AE_RX_TS0),</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = S(E1_AS_SEARCH_FRAME) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(E1_AS_SEARCH_CRC_MFRAME) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                  S(E1_AS_ALIGNED_BASIC),</span><br><span style="color: hsl(120, 100%, 40%);">+             .action = e1_align_search_frame,</span><br><span style="color: hsl(120, 100%, 40%);">+      },</span><br><span style="color: hsl(120, 100%, 40%);">+    [E1_AS_SEARCH_CRC_MFRAME] = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .name = "SEARCH_CRC_MFRAME",</span><br><span style="color: hsl(120, 100%, 40%);">+                .in_event_mask = S(E1_AE_RX_TS0),</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = S(E1_AS_SEARCH_FRAME) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(E1_AS_SEARCH_CRC_MFRAME) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                  S(E1_AS_ALIGNED_CRC_MFRAME),</span><br><span style="color: hsl(120, 100%, 40%);">+                .action = e1_align_search_crc_mframe,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+    [E1_AS_ALIGNED_CRC_MFRAME] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .name = "ALIGNED_CRC_MFRAME",</span><br><span style="color: hsl(120, 100%, 40%);">+               .in_event_mask = S(E1_AE_RX_TS0),</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = S(E1_AS_SEARCH_FRAME) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(E1_AS_SEARCH_CRC_MFRAME) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                  S(E1_AS_ALIGNED_CRC_MFRAME),</span><br><span style="color: hsl(120, 100%, 40%);">+                .action = e1_aligned_crc_mframe,</span><br><span style="color: hsl(120, 100%, 40%);">+      },</span><br><span style="color: hsl(120, 100%, 40%);">+    [E1_AS_ALIGNED_BASIC] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             .name = "ALIGNED_BASIC",</span><br><span style="color: hsl(120, 100%, 40%);">+            .in_event_mask = S(E1_AE_RX_TS0),</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = S(E1_AS_SEARCH_FRAME),</span><br><span style="color: hsl(120, 100%, 40%);">+              .action = e1_aligned_basic,</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 e1_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_e1f_instance *e1i = (struct osmo_e1f_instance *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case E1_AE_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+             e1i->rx.num_ts0_in_mframe_search = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_fsm_inst_state_chg(fi, E1_AS_SEARCH_FRAME, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</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 struct osmo_fsm e1_align_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+       .name = "e1-align",</span><br><span style="color: hsl(120, 100%, 40%);">+ .states = e1_align_states,</span><br><span style="color: hsl(120, 100%, 40%);">+    .num_states = ARRAY_SIZE(e1_align_states),</span><br><span style="color: hsl(120, 100%, 40%);">+    .allstate_event_mask = S(E1_AE_RESET),</span><br><span style="color: hsl(120, 100%, 40%);">+        .allstate_action = e1_allstate,</span><br><span style="color: hsl(120, 100%, 40%);">+       .log_subsys = DLGLOBAL,</span><br><span style="color: hsl(120, 100%, 40%);">+       .event_names = e1_align_evt_names,</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 align_fsm_reset(struct osmo_e1f_instance *e1i)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_fsm_inst_dispatch(e1i->rx.fi, E1_AE_RESET, 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%);">+static void e1_rx_hist_add(struct osmo_e1f_instance *e1i, uint8_t inb)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     e1i->rx.ts0_history[e1i->rx.frame_nr] = inb;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (e1i->rx.ts0_hist_len < 16)</span><br><span style="color: hsl(120, 100%, 40%);">+          e1i->rx.ts0_hist_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%);">+static void e1_rx_ts0(struct osmo_e1f_instance *e1i, uint8_t inb)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* append just-received byte to the TS0 receive history buffer */</span><br><span style="color: hsl(120, 100%, 40%);">+     e1_rx_hist_add(e1i, inb);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* notify the FSM that a new TS0 byte was received */</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_dispatch(e1i->rx.fi, E1_AE_RX_TS0, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  e1i->rx.frame_nr = (e1i->rx.frame_nr + 1) % 16;</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 e1_rx_tsN(struct osmo_e1f_instance_ts *e1t, uint8_t inb)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+     int count, rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!e1t->rx.enabled)</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%);">+     if (!e1t->rx.msg)</span><br><span style="color: hsl(120, 100%, 40%);">+          e1t->rx.msg = msgb_alloc(e1t->rx.granularity, "E1 Rx");</span><br><span style="color: hsl(120, 100%, 40%);">+       msg = e1t->rx.msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (e1t->mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+       case OSMO_E1F_TS_RAW:</span><br><span style="color: hsl(120, 100%, 40%);">+         /* append byte at end of msgb */</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_put_u8(msg, inb);</span><br><span style="color: hsl(120, 100%, 40%);">+                /* flush msgb, if full */</span><br><span style="color: hsl(120, 100%, 40%);">+             if (msgb_tailroom(msg) <= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     goto flush;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case OSMO_E1F_TS_HDLC_CRC:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = osmo_isdnhdlc_decode(&e1t->rx.hdlc, &inb, 1, &count,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        msgb_data(msg), msgb_tailroom(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+                switch (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+         case -OSMO_HDLC_FRAMING_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+                        fprintf(stdout, "Framing Error\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                 break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case -OSMO_HDLC_CRC_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+                    fprintf(stdout, "CRC Error\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case -OSMO_HDLC_LENGTH_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+                 fprintf(stdout, "Length Error\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                  break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* no output yet */</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%);">+                      msgb_put(msg, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+                    goto flush;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</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;</span><br><span style="color: hsl(120, 100%, 40%);">+flush:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!e1t->rx.data_cb)</span><br><span style="color: hsl(120, 100%, 40%);">+              msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       else</span><br><span style="color: hsl(120, 100%, 40%);">+          e1t->rx.data_cb(e1t, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+ e1t->rx.msg = 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%);">+/*! Receive a single E1 frame of 32x8 (=256) bits</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param e1i E1 instance for which the frame was received</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] in_frame caller-provided buffer of 32 octets</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  The idea is that whoever calls us will already have done the bit-alignment,</span><br><span style="color: hsl(120, 100%, 40%);">+ *  i.e. the first bit of TS0 of the frame will be octet-aligned and hence the</span><br><span style="color: hsl(120, 100%, 40%);">+ *  entire 256bit buffer is provided as octet-aligned 32bytes in \a in_frame.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_e1f_rx_frame(struct osmo_e1f_instance *e1i, const uint8_t *in_frame)</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%);">+      e1_rx_update_crc4(e1i, in_frame);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   e1_rx_ts0(e1i, in_frame[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        for (i = 1; i < ARRAY_SIZE(e1i->ts); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             struct osmo_e1f_instance_ts *e1t = &e1i->ts[i];</span><br><span style="color: hsl(120, 100%, 40%);">+                e1_rx_tsN(e1t, in_frame[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%);">+   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%);">+int osmo_e1f_init(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return osmo_fsm_register(&e1_align_fsm);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/e1gen/osmo_e1f.h b/src/e1gen/osmo_e1f.h</span><br><span>new file mode 100644</span><br><span>index 0000000..0b423d9</span><br><span>--- /dev/null</span><br><span>+++ b/src/e1gen/osmo_e1f.h</span><br><span>@@ -0,0 +1,123 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.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/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/isdnhdlc.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_e1f_tx_state {</span><br><span style="color: hsl(120, 100%, 40%);">+      bool remote_alarm;</span><br><span style="color: hsl(120, 100%, 40%);">+    bool crc4_error;</span><br><span style="color: hsl(120, 100%, 40%);">+      bool ais;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* lower 5 bits: Sa4..Sa8 */</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t sa4_sa8;</span><br><span style="color: hsl(120, 100%, 40%);">+      /* frame number 0..15 */</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t frame_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t crc4_last_smf;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t crc4;</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_e1f_rx_state {</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t frame_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* history of rceived TS0 octets */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t ts0_history[16];</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t ts0_hist_len;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* was a remote alarm received? */</span><br><span style="color: hsl(120, 100%, 40%);">+    bool remote_alarm;</span><br><span style="color: hsl(120, 100%, 40%);">+    bool remote_crc4_error;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* number of TS0 bytes received since entering CRC mframe search */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t num_ts0_in_mframe_search;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* computed CRC4 */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t crc4_last_smf;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t crc4;</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%);">+enum osmo_e1f_notify_event {</span><br><span style="color: hsl(120, 100%, 40%);">+     E1_NTFY_EVT_ALIGN_FRAME,</span><br><span style="color: hsl(120, 100%, 40%);">+      E1_NTFY_EVT_ALIGN_CRC_MFRAME,</span><br><span style="color: hsl(120, 100%, 40%);">+ E1_NTFY_EVT_CRC_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+        E1_NTFY_EVT_REMOTE_CRC_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+ E1_NTFY_EVT_REMOTE_ALARM,</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%);">+enum osmo_e1f_ts_mode {</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_E1F_TS_RAW,</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_E1F_TS_HDLC_CRC,</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_e1f_instance_ts;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_e1f_instance;</span><br><span style="color: hsl(120, 100%, 40%);">+typedef void (*e1_data_cb)(struct osmo_e1f_instance_ts *ts, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+typedef void (*e1_notify_cb)(struct osmo_e1f_instance *e1i, enum osmo_e1f_notify_event evt,</span><br><span style="color: hsl(120, 100%, 40%);">+                        bool present, void *data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_e1f_instance_ts {</span><br><span style="color: hsl(120, 100%, 40%);">+      /* timeslot number */</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t ts_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+        /* mode in which we operate (RAW/HDLC) */</span><br><span style="color: hsl(120, 100%, 40%);">+     enum osmo_e1f_ts_mode mode;</span><br><span style="color: hsl(120, 100%, 40%);">+   /* back-pointer to e1 instance */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_e1f_instance *inst;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* optional HDLC encoder state */</span><br><span style="color: hsl(120, 100%, 40%);">+             struct osmo_isdnhdlc_vars hdlc;</span><br><span style="color: hsl(120, 100%, 40%);">+               /* queue of pending to-be-transmitted messages */</span><br><span style="color: hsl(120, 100%, 40%);">+             struct llist_head queue;</span><br><span style="color: hsl(120, 100%, 40%);">+              unsigned long underruns;</span><br><span style="color: hsl(120, 100%, 40%);">+      } tx;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* optional HDLC decoder state */</span><br><span style="color: hsl(120, 100%, 40%);">+             struct osmo_isdnhdlc_vars hdlc;</span><br><span style="color: hsl(120, 100%, 40%);">+               bool enabled;</span><br><span style="color: hsl(120, 100%, 40%);">+         /* how many bytes to buffer before calling call-back */</span><br><span style="color: hsl(120, 100%, 40%);">+               unsigned int granularity;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* current receive buffer */</span><br><span style="color: hsl(120, 100%, 40%);">+          struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+             e1_data_cb data_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+           /* private data, relevant to user */</span><br><span style="color: hsl(120, 100%, 40%);">+          void *priv;</span><br><span style="color: hsl(120, 100%, 40%);">+   } rx;</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_e1f_instance {</span><br><span style="color: hsl(120, 100%, 40%);">+       /* list; currently not used yet */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* is CRC4 generation + parsing enabled? */</span><br><span style="color: hsl(120, 100%, 40%);">+   bool crc4_enabled;</span><br><span style="color: hsl(120, 100%, 40%);">+    /* notification call-back function */</span><br><span style="color: hsl(120, 100%, 40%);">+ e1_notify_cb notify_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Rx + Tx related state */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_e1f_tx_state tx;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_e1f_rx_state rx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* our 32 timeslots (only 1..32 are used) */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_e1f_instance_ts ts[32];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* private data, relevant to user */</span><br><span style="color: hsl(120, 100%, 40%);">+  void *priv;</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%);">+extern const struct value_string osmo_e1f_notifv_evt_names[];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static inline const char *osmo_e1f_notify_event_name(enum osmo_e1f_notify_event evt) {</span><br><span style="color: hsl(120, 100%, 40%);">+    return get_value_string(osmo_e1f_notifv_evt_names, evt);</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 osmo_e1f_init(void);</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_e1f_instance_ts *osmo_e1f_instance_ts(struct osmo_e1f_instance *e1i, uint8_t ts_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_e1f_instance_init(struct osmo_e1f_instance *e1i, const char *name, e1_notify_cb cb,</span><br><span style="color: hsl(120, 100%, 40%);">+                         bool crc4_enabled, void *priv);</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_e1f_instance_reset(struct osmo_e1f_instance *e1i);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_e1f_ts_config(struct osmo_e1f_instance_ts *e1t, e1_data_cb cb, unsigned int granularity,</span><br><span style="color: hsl(120, 100%, 40%);">+                  bool enable, enum osmo_e1f_ts_mode mode);</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_e1f_ts_reset(struct osmo_e1f_instance_ts *e1t);</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_e1f_ts_enqueue(struct osmo_e1f_instance_ts *e1t, struct msgb *msg);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_e1f_pull_tx_frame(struct osmo_e1f_instance *e1i, uint8_t *out_frame);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_e1f_rx_frame(struct osmo_e1f_instance *e1i, const uint8_t *in_frame);</span><br><span>diff --git a/src/osmo-e1gen.c b/src/osmo-e1gen.c</span><br><span>new file mode 100644</span><br><span>index 0000000..15d677a</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-e1gen.c</span><br><span>@@ -0,0 +1,438 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * osmo-e1gen.c</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%);">+ * All Rights Reserved</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 along</span><br><span style="color: hsl(120, 100%, 40%);">+ * with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(120, 100%, 40%);">+ * 51 Franklin Street, Fifth Floor, Boston, 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%);">+#include <sched.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <signal.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define _GNU_SOURCE</span><br><span style="color: hsl(120, 100%, 40%);">+#include <getopt.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/application.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/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/telnet_interface.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/vty.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/command.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "e1d.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "usb.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "log.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "e1gen/osmo_e1f.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef OSMO_VTY_PORT_E1D</span><br><span style="color: hsl(120, 100%, 40%);">+#define OSMO_VTY_PORT_E1D 4269</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</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%);">+ * global variables</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%);">+extern struct e1_daemon *vty_e1d;</span><br><span style="color: hsl(120, 100%, 40%);">+static const char *g_config_file = "osmo-e1d.cfg";</span><br><span style="color: hsl(120, 100%, 40%);">+static void *g_e1d_ctx = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+static int g_shutdown = 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%);">+ * stubs for external linkage of normal osmo-e1d</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 e1_ts_stop(struct e1_ts *ts) {}</span><br><span style="color: hsl(120, 100%, 40%);">+int e1d_vpair_create(struct e1_daemon *e1d, unsigned int num_lines) { return -1; }</span><br><span style="color: hsl(120, 100%, 40%);">+struct e1_intf *e1d_vpair_intf_peer(struct e1_intf *intf) { 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct e1gen_line_data {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ice1usb_tx_config tx_config;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ice1usb_rx_config rx_config;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_e1f_instance e1f;</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 e1f_notify_cb(struct osmo_e1f_instance *e1f, enum osmo_e1f_notify_event evt,</span><br><span style="color: hsl(120, 100%, 40%);">+                   bool present, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct e1_line *line = e1f->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  LOGPLI(line, DE1D, LOGL_NOTICE, "NOTIFY: %s %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_e1f_notify_event_name(evt), present ? "PRESENT" : "ABSENT");</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 const struct e1gen_line_data default_ld = {</span><br><span style="color: hsl(120, 100%, 40%);">+        .tx_config = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .mode = ICE1USB_TX_MODE_TRANSP,</span><br><span style="color: hsl(120, 100%, 40%);">+               .timing = ICE1USB_TX_TIME_SRC_LOCAL,</span><br><span style="color: hsl(120, 100%, 40%);">+          .ext_loopback = ICE1USB_TX_EXT_LOOPBACK_OFF,</span><br><span style="color: hsl(120, 100%, 40%);">+          .alarm = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+   },</span><br><span style="color: hsl(120, 100%, 40%);">+    .rx_config = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .mode = ICE1USB_RX_MODE_MULTIFRAME,</span><br><span style="color: hsl(120, 100%, 40%);">+           //.mode = ICE1USB_RX_MODE_TRANSP,</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%);">+struct e1gen_line_data *ensure_gld(struct e1_line *line)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct e1gen_line_data *gld = (struct e1gen_line_data *) line->e1gen_priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (gld)</span><br><span style="color: hsl(120, 100%, 40%);">+              return gld;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPLI(line, DE1D, LOGL_INFO, "Creating e1gen structures\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     line->e1gen_priv = gld = talloc_zero(line, struct e1gen_line_data);</span><br><span style="color: hsl(120, 100%, 40%);">+        gld->tx_config = default_ld.tx_config;</span><br><span style="color: hsl(120, 100%, 40%);">+     gld->rx_config = default_ld.rx_config;</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_e1f_instance_init(&gld->e1f, "LINE", e1f_notify_cb, true, line);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* set the default configuration */</span><br><span style="color: hsl(120, 100%, 40%);">+   e1_usb_ctrl_set_tx_cfg(line, gld->tx_config.mode, gld->tx_config.timing,</span><br><span style="color: hsl(120, 100%, 40%);">+                                gld->tx_config.ext_loopback, gld->tx_config.alarm);</span><br><span style="color: hsl(120, 100%, 40%);">+     e1_usb_ctrl_set_rx_cfg(line, gld->rx_config.mode);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return gld;</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%);">+/*! process (demultiplex) input data for the specified e1_line.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] line E1 line for which to genrate output data</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] buf input buffer of multiplexed data received on line</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] size size of buf in octets */</span><br><span style="color: hsl(120, 100%, 40%);">+int e1_line_demux_in(struct e1_line *line, const uint8_t *buf, int size,  int frame_base)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct e1gen_line_data *gld = ensure_gld(line);</span><br><span style="color: hsl(120, 100%, 40%);">+       int offs;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (offs = 0; offs + 32 <= size; offs += 32) {</span><br><span style="color: hsl(120, 100%, 40%);">+            //printf("Rx "OSMO_BIT_SPEC"\n", OSMO_BIT_PRINT(buf[offs]));</span><br><span style="color: hsl(120, 100%, 40%);">+              //printf("Rx %s\n", osmo_hexdump(buf + offs, 32));</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_e1f_rx_frame(&gld->e1f, buf + offs);</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%);">+/*! generate (multiplex) output data for the specified e1_line</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] line E1 line for which to genrate output data</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] buf caller-allocated output buffer for multiplexed data</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] fts number of E1 frames (32 bytes each) to generate</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \return number of bytes written to buf */</span><br><span style="color: hsl(120, 100%, 40%);">+int e1_line_mux_out(struct e1_line *line, uint8_t *buf, int fts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct e1gen_line_data *gld = ensure_gld(line);</span><br><span style="color: hsl(120, 100%, 40%);">+       int f;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      //printf("FRAME:\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       for (f = 0; f < fts; f++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_e1f_pull_tx_frame(&gld->e1f, buf + f*32);</span><br><span style="color: hsl(120, 100%, 40%);">+         //printf("Tx "OSMO_BIT_SPEC"\n", OSMO_BIT_PRINT(buf[f*32]));</span><br><span style="color: hsl(120, 100%, 40%);">+              //printf("Tx %s\n", osmo_hexdump(buf + f*32, 32));</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 32*fts;</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 cmd_node line_node = {</span><br><span style="color: hsl(120, 100%, 40%);">+     (enum node_type) LINE_NODE,</span><br><span style="color: hsl(120, 100%, 40%);">+   "%s(line)# ",</span><br><span style="color: hsl(120, 100%, 40%);">+       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%);">+#define TX_STR "Transmitter\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#define OFF_ON_STR "Off\n" "On\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(line_tx_alarm, line_tx_alarm_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+  "tx report-alarm (0|1)",</span><br><span style="color: hsl(120, 100%, 40%);">+    TX_STR "Report Alarm (A-Bits)\n" OFF_ON_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct e1_line *line = vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct e1gen_line_data *gld = ensure_gld(line);</span><br><span style="color: hsl(120, 100%, 40%);">+       int on = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     gld->e1f.tx.remote_alarm = on ? true : false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return CMD_SUCCESS;</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%);">+DEFUN(line_tx_crc4, line_tx_crc4_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+       "tx generate-crc4 (0|1)",</span><br><span style="color: hsl(120, 100%, 40%);">+   TX_STR "Generate CRC4\n" OFF_ON_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct e1_line *line = vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct e1gen_line_data *gld = ensure_gld(line);</span><br><span style="color: hsl(120, 100%, 40%);">+       int on = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     gld->e1f.crc4_enabled = on ? true : false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return CMD_SUCCESS;</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%);">+DEFUN(line_tx_report_crc4, line_tx_report_crc4_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ "tx report-crc4-error (0|1)",</span><br><span style="color: hsl(120, 100%, 40%);">+       TX_STR "Report a CRC4 Error\n" OFF_ON_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct e1_line *line = vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct e1gen_line_data *gld = ensure_gld(line);</span><br><span style="color: hsl(120, 100%, 40%);">+       int on = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     gld->e1f.tx.crc4_error = on ? true : false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return CMD_SUCCESS;</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%);">+DEFUN(line_tx_sa48, line_tx_sa48_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+       "tx sa4 <0-31>",</span><br><span style="color: hsl(120, 100%, 40%);">+      TX_STR "Set the SA4..SA8 bit content\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct e1_line *line = vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct e1gen_line_data *gld = ensure_gld(line);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     gld->e1f.tx.sa4_sa8 = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</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%);">+DEFUN(line_tx_ais, line_tx_ais_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ "tx ais (0|1)",</span><br><span style="color: hsl(120, 100%, 40%);">+     TX_STR "Transmit AIS (All-1)\n" OFF_ON_STR)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct e1_line *line = vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct e1gen_line_data *gld = ensure_gld(line);</span><br><span style="color: hsl(120, 100%, 40%);">+       int on = atoi(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     gld->e1f.tx.ais = on ? true : false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</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%);">+DEFUN(line_show, line_show_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+     "show", "Show Line status\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct e1_line *line = vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct e1gen_line_data *gld = ensure_gld(line);</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_e1f_instance *e1f = &gld->e1f;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   vty_out(vty, "Rx RemoteAlarm=%u, RemoteCrcErr=%u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                e1f->rx.remote_alarm, e1f->rx.remote_crc4_error, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+  vty_out(vty, "Tx RemoteAlarm=%u, CrcErr=%u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+              e1f->tx.remote_alarm, e1f->tx.crc4_error, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return CMD_SUCCESS;</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%);">+DEFUN(line, line_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+       "interface <0-255> line <0-225>",</span><br><span style="color: hsl(120, 100%, 40%);">+       "E1 Interface\n" "E1 Interface\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ "E1 Line number\n" "E1 Line number\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct e1_intf *intf;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct e1_line *line;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       intf = e1d_find_intf(vty_e1d, atoi(argv[0]));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!intf) {</span><br><span style="color: hsl(120, 100%, 40%);">+          vty_out(vty, "No such interface %s%s", argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+               return CMD_WARNING;</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%);">+   line = e1_intf_find_line(intf, atoi(argv[1]));</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!line) {</span><br><span style="color: hsl(120, 100%, 40%);">+          vty_out(vty, "No such line %s in interface %s%s", argv[1], argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+           return CMD_WARNING;</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%);">+   vty->node = LINE_NODE;</span><br><span style="color: hsl(120, 100%, 40%);">+     vty->index = line;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return CMD_SUCCESS;</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 e1gen_init(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     install_element(ENABLE_NODE, &line_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+  install_node(&line_node, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_element(LINE_NODE, &line_tx_alarm_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_element(LINE_NODE, &line_tx_crc4_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+    install_element(LINE_NODE, &line_tx_report_crc4_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+     install_element(LINE_NODE, &line_tx_sa48_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+    install_element(LINE_NODE, &line_tx_ais_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+     install_element(LINE_NODE, &line_show_cmd);</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 (mostly shared with osmo-e1d.c</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 vty_app_info vty_info = {</span><br><span style="color: hsl(120, 100%, 40%);">+        .name = "osmo-e1gen",</span><br><span style="color: hsl(120, 100%, 40%);">+       .version = PACKAGE_VERSION,</span><br><span style="color: hsl(120, 100%, 40%);">+   .copyright =</span><br><span style="color: hsl(120, 100%, 40%);">+  "(C) 2019-2020 by Sylvain Munaut and Harald Welte\r\n",</span><br><span style="color: hsl(120, 100%, 40%);">+     "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl-2.0.html>\r\n"</span><br><span style="color: hsl(120, 100%, 40%);">+       "This is free software: you are free to change and redistribute it.\r\n"</span><br><span style="color: hsl(120, 100%, 40%);">+    "There is NO WARRANTY, to the extent permitted by law.\r\n",</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 sig_handler(int signo)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   fprintf(stdout, "signal %d received\n", signo);</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (signo) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case SIGINT:</span><br><span style="color: hsl(120, 100%, 40%);">+  case SIGTERM:</span><br><span style="color: hsl(120, 100%, 40%);">+         fprintf(stdout, "shutting down\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         g_shutdown = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SIGABRT:</span><br><span style="color: hsl(120, 100%, 40%);">+ case SIGUSR1:</span><br><span style="color: hsl(120, 100%, 40%);">+         talloc_report(g_e1d_ctx, stderr);</span><br><span style="color: hsl(120, 100%, 40%);">+             talloc_report_full(g_e1d_ctx, stderr);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SIGUSR2:</span><br><span style="color: hsl(120, 100%, 40%);">+         talloc_report_full(g_e1d_ctx, stderr);</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%);">+              break;</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 print_help(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       printf("  Some useful help...\n");</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("  -h --help                        This text.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("  -d --debug option                --debug=DE1D:DXFR enable debugging.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("  -c --config-file filename        The config file to use.\n");</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 handle_options(int argc, char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  while (1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           int option_index = 0, c;</span><br><span style="color: hsl(120, 100%, 40%);">+              static const struct option long_options[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                 {"help", 0, 0, 'h'},</span><br><span style="color: hsl(120, 100%, 40%);">+                        {"debug", 1, 0, 'd'},</span><br><span style="color: hsl(120, 100%, 40%);">+                       {"config-file", 1, 0, 'c'},</span><br><span style="color: hsl(120, 100%, 40%);">+                 {0, 0, 0, 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%);">+          c = getopt_long(argc, argv, "hd:c:", long_options, &option_index);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (c == -1)</span><br><span style="color: hsl(120, 100%, 40%);">+                  break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              switch (c) {</span><br><span style="color: hsl(120, 100%, 40%);">+          case 'h':</span><br><span style="color: hsl(120, 100%, 40%);">+                     print_help();</span><br><span style="color: hsl(120, 100%, 40%);">+                 exit(0);</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'd':</span><br><span style="color: hsl(120, 100%, 40%);">+                     log_parse_category_mask(osmo_stderr_target, optarg);</span><br><span style="color: hsl(120, 100%, 40%);">+                  break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'c':</span><br><span style="color: hsl(120, 100%, 40%);">+                     g_config_file = optarg;</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%);">+                      fprintf(stderr, "Error in command line options. Exiting.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                       exit(-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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (argc > optind) {</span><br><span style="color: hsl(120, 100%, 40%);">+               fprintf(stderr, "Unsupported positional arguments on command line\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              exit(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%);">+</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%);">+    struct e1_daemon *e1d = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sched_param sp;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* talloc init */</span><br><span style="color: hsl(120, 100%, 40%);">+     g_e1d_ctx = talloc_named_const(NULL, 0, "osmo-e1d");</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_talloc_ctx_init(g_e1d_ctx, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* logging init */</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_init_logging2(g_e1d_ctx, &log_info);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* signals init */</span><br><span style="color: hsl(120, 100%, 40%);">+    signal(SIGINT, &sig_handler);</span><br><span style="color: hsl(120, 100%, 40%);">+     signal(SIGTERM, &sig_handler);</span><br><span style="color: hsl(120, 100%, 40%);">+    signal(SIGABRT, &sig_handler);</span><br><span style="color: hsl(120, 100%, 40%);">+    signal(SIGUSR1, &sig_handler);</span><br><span style="color: hsl(120, 100%, 40%);">+    signal(SIGUSR2, &sig_handler);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_init_ignore_signals();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* rt prio */</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(&sp, 0x00, sizeof(sp));</span><br><span style="color: hsl(120, 100%, 40%);">+        sp.sched_priority = 50;</span><br><span style="color: hsl(120, 100%, 40%);">+        rv = sched_setscheduler(0, SCHED_RR, &sp);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rv != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DE1D, LOGL_ERROR, "Failed to set Real-Time priority. USB comms might be unstable.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         perror("sched_setscheduler");</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%);">+   /* main state */</span><br><span style="color: hsl(120, 100%, 40%);">+      e1d = talloc_zero(g_e1d_ctx, struct e1_daemon);</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(e1d);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   INIT_LLIST_HEAD(&e1d->interfaces);</span><br><span style="color: hsl(120, 100%, 40%);">+     vty_init(&vty_info);</span><br><span style="color: hsl(120, 100%, 40%);">+      logging_vty_add_cmds();</span><br><span style="color: hsl(120, 100%, 40%);">+       e1d_vty_init(e1d);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  handle_options(argc, argv);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rv = vty_read_config_file(g_config_file, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (rv < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DE1D, LOGL_FATAL, "Failed to parse the config file '%s'\n", g_config_file);</span><br><span style="color: hsl(120, 100%, 40%);">+            exit(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%);">+   rv = telnet_init_dynif(g_e1d_ctx, e1d, vty_get_bind_addr(), OSMO_VTY_PORT_E1D);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (rv != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DE1D, LOGL_FATAL, "Failed to bind VTY interface to %s:%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   vty_get_bind_addr(), OSMO_VTY_PORT_E1D);</span><br><span style="color: hsl(120, 100%, 40%);">+              exit(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%);">+   osmo_e1f_init();</span><br><span style="color: hsl(120, 100%, 40%);">+      e1gen_init();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* probe devices */</span><br><span style="color: hsl(120, 100%, 40%);">+   rv = e1_usb_probe(e1d);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (rv != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DE1D, LOGL_ERROR, "Failed to prove usb devices\n");</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%);">+   /* main loop */</span><br><span style="color: hsl(120, 100%, 40%);">+       while (!g_shutdown) {</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_select_main(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%);">+   talloc_free(e1d);</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></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-e1d/+/21805">change 21805</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/osmo-e1d/+/21805"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-e1d </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I53a86d6730eb76a9cff9eb3f4786139015c91230 </div>
<div style="display:none"> Gerrit-Change-Number: 21805 </div>
<div style="display:none"> Gerrit-PatchSet: 6 </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>