<p>Vadim Yanitskiy has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/11394">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">host/trxcon/scheduler: add PDTCH channel support<br><br>Change-Id: I1176576f54c1d68e79cc6ac37d61a9033f7018dd<br>---<br>M src/host/trxcon/Makefile.am<br>M src/host/trxcon/sched_lchan_desc.c<br>A src/host/trxcon/sched_lchan_pdtch.c<br>M src/host/trxcon/sched_trx.h<br>4 files changed, 214 insertions(+), 4 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/94/11394/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/host/trxcon/Makefile.am b/src/host/trxcon/Makefile.am</span><br><span>index 7095cb5..b51db02 100644</span><br><span>--- a/src/host/trxcon/Makefile.am</span><br><span>+++ b/src/host/trxcon/Makefile.am</span><br><span>@@ -32,6 +32,7 @@</span><br><span> # Scheduler</span><br><span> trxcon_SOURCES += \</span><br><span>      sched_lchan_common.c \</span><br><span style="color: hsl(120, 100%, 40%);">+        sched_lchan_pdtch.c \</span><br><span>        sched_lchan_desc.c \</span><br><span>         sched_lchan_xcch.c \</span><br><span>         sched_lchan_tchf.c \</span><br><span>diff --git a/src/host/trxcon/sched_lchan_desc.c b/src/host/trxcon/sched_lchan_desc.c</span><br><span>index 8b2b5e1..93639a3 100644</span><br><span>--- a/src/host/trxcon/sched_lchan_desc.c</span><br><span>+++ b/src/host/trxcon/sched_lchan_desc.c</span><br><span>@@ -25,10 +25,6 @@</span><br><span> </span><br><span> #include "sched_trx.h"</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* TODO: implement */</span><br><span style="color: hsl(0, 100%, 40%);">-#define tx_pdtch_fn      NULL</span><br><span style="color: hsl(0, 100%, 40%);">-#define rx_pdtch_fn NULL</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* Forward declaration of handlers */</span><br><span> int rx_data_fn(struct trx_instance *trx, struct trx_ts *ts,</span><br><span>         struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid,</span><br><span>@@ -58,6 +54,12 @@</span><br><span> int tx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts,</span><br><span>         struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int rx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,</span><br><span style="color: hsl(120, 100%, 40%);">+   struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid,</span><br><span style="color: hsl(120, 100%, 40%);">+      sbit_t *bits, int8_t rssi, int16_t toa256);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int tx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,</span><br><span style="color: hsl(120, 100%, 40%);">+   struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid);</span><br><span> </span><br><span> const struct trx_lchan_desc trx_lchan_desc[_TRX_CHAN_MAX] = {</span><br><span>       {</span><br><span>diff --git a/src/host/trxcon/sched_lchan_pdtch.c b/src/host/trxcon/sched_lchan_pdtch.c</span><br><span>new file mode 100644</span><br><span>index 0000000..1a8987b</span><br><span>--- /dev/null</span><br><span>+++ b/src/host/trxcon/sched_lchan_pdtch.c</span><br><span>@@ -0,0 +1,204 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * OsmocomBB <-> SDR connection bridge</span><br><span style="color: hsl(120, 100%, 40%);">+ * TDMA scheduler: handlers for DL / UL bursts on logical channels</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2018 by Vadim Yanitskiy <axilirator@gmail.com></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%);">+ * 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%);">+</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%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+</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/bits.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm_utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_04_08.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/coding/gsm0503_coding.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "l1ctl_proto.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "scheduler.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "sched_trx.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "logging.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "trx_if.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "trxcon.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "l1ctl.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int rx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,</span><br><span style="color: hsl(120, 100%, 40%);">+        struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid,</span><br><span style="color: hsl(120, 100%, 40%);">+      sbit_t *bits, int8_t rssi, int16_t toa256)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct trx_lchan_desc *lchan_desc;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t l2[GPRS_L2_MAX_LEN], *mask;</span><br><span style="color: hsl(120, 100%, 40%);">+   int n_errors, n_bits_total, rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       sbit_t *buffer, *offset;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t *first_fn;</span><br><span style="color: hsl(120, 100%, 40%);">+   size_t l2_len;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Set up pointers */</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan_desc = &trx_lchan_desc[lchan->type];</span><br><span style="color: hsl(120, 100%, 40%);">+     first_fn = &lchan->rx_first_fn;</span><br><span style="color: hsl(120, 100%, 40%);">+        mask = &lchan->rx_burst_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+  buffer = lchan->rx_bursts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       LOGP(DSCHD, LOGL_DEBUG, "Packet data received on %s: "</span><br><span style="color: hsl(120, 100%, 40%);">+              "fn=%u ts=%u bid=%u\n", lchan_desc->name, fn, ts->index, bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Reset internal state */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (bid == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Clean up old measurements */</span><br><span style="color: hsl(120, 100%, 40%);">+               memset(&lchan->meas, 0x00, sizeof(lchan->meas));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          *first_fn = fn;</span><br><span style="color: hsl(120, 100%, 40%);">+               *mask = 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%);">+   /* Update mask */</span><br><span style="color: hsl(120, 100%, 40%);">+     *mask |= (1 << bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Update measurements */</span><br><span style="color: hsl(120, 100%, 40%);">+     lchan->meas.toa256_sum += toa256;</span><br><span style="color: hsl(120, 100%, 40%);">+  lchan->meas.rssi_sum += rssi;</span><br><span style="color: hsl(120, 100%, 40%);">+      lchan->meas.toa256_num++;</span><br><span style="color: hsl(120, 100%, 40%);">+  lchan->meas.rssi_num++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Copy burst to buffer of 4 bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+        offset = buffer + bid * 116;</span><br><span style="color: hsl(120, 100%, 40%);">+  memcpy(offset, bits + 3, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(offset + 58, bits + 87, 58);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Wait until complete set of bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (bid != 3)</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%);">+   /* Check for complete set of bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+        if ((*mask & 0xf) != 0xf) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DSCHD, LOGL_ERROR, "Received incomplete data frame at "</span><br><span style="color: hsl(120, 100%, 40%);">+                        "fn=%u (%u/%u) for %s\n", *first_fn,</span><br><span style="color: hsl(120, 100%, 40%);">+                        (*first_fn) % ts->mf_layout->period,</span><br><span style="color: hsl(120, 100%, 40%);">+                    ts->mf_layout->period,</span><br><span style="color: hsl(120, 100%, 40%);">+                  lchan_desc->name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Attempt to decode */</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = gsm0503_pdtch_decode(l2, buffer,</span><br><span style="color: hsl(120, 100%, 40%);">+         NULL, &n_errors, &n_bits_total);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DSCHD, LOGL_ERROR, "Received bad packet data frame "</span><br><span style="color: hsl(120, 100%, 40%);">+                   "at fn=%u (%u/%u) for %s\n", *first_fn,</span><br><span style="color: hsl(120, 100%, 40%);">+                     (*first_fn) % ts->mf_layout->period,</span><br><span style="color: hsl(120, 100%, 40%);">+                    ts->mf_layout->period,</span><br><span style="color: hsl(120, 100%, 40%);">+                  lchan_desc->name);</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%);">+   /* Determine L2 length */</span><br><span style="color: hsl(120, 100%, 40%);">+     l2_len = rc > 0 ? rc : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Send a L2 frame to the higher layers */</span><br><span style="color: hsl(120, 100%, 40%);">+    sched_send_dt_ind(trx, ts, lchan,</span><br><span style="color: hsl(120, 100%, 40%);">+             l2, l2_len, n_errors, rc < 0, true);</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%);">+int tx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts,</span><br><span style="color: hsl(120, 100%, 40%);">+        struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   const struct trx_lchan_desc *lchan_desc;</span><br><span style="color: hsl(120, 100%, 40%);">+      ubit_t burst[GSM_BURST_LEN];</span><br><span style="color: hsl(120, 100%, 40%);">+  ubit_t *buffer, *offset;</span><br><span style="color: hsl(120, 100%, 40%);">+      const uint8_t *tsc;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t *mask;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Set up pointers */</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan_desc = &trx_lchan_desc[lchan->type];</span><br><span style="color: hsl(120, 100%, 40%);">+     mask = &lchan->tx_burst_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+  buffer = lchan->tx_bursts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (bid > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* If we have encoded bursts */</span><br><span style="color: hsl(120, 100%, 40%);">+               if (*mask)</span><br><span style="color: hsl(120, 100%, 40%);">+                    goto send_burst;</span><br><span style="color: hsl(120, 100%, 40%);">+              else</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%);">+   /* Encode payload */</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = gsm0503_pdtch_encode(buffer, lchan->prim->payload,</span><br><span style="color: hsl(120, 100%, 40%);">+         lchan->prim->payload_len);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DSCHD, LOGL_ERROR, "Failed to encode L2 payload\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         /* Forget this primitive */</span><br><span style="color: hsl(120, 100%, 40%);">+           sched_prim_drop(lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EINVAL;</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%);">+send_burst:</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Determine which burst should be sent */</span><br><span style="color: hsl(120, 100%, 40%);">+    offset = buffer + bid * 116;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Update mask */</span><br><span style="color: hsl(120, 100%, 40%);">+     *mask |= (1 << bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Choose proper TSC */</span><br><span style="color: hsl(120, 100%, 40%);">+       tsc = sched_nb_training_bits[trx->tsc];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Compose a new burst */</span><br><span style="color: hsl(120, 100%, 40%);">+     memset(burst, 0, 3); /* TB */</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(burst + 3, offset, 58); /* Payload 1/2 */</span><br><span style="color: hsl(120, 100%, 40%);">+      memcpy(burst + 61, tsc, 26); /* TSC */</span><br><span style="color: hsl(120, 100%, 40%);">+        memcpy(burst + 87, offset + 58, 58); /* Payload 2/2 */</span><br><span style="color: hsl(120, 100%, 40%);">+        memset(burst + 145, 0, 3); /* TB */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DSCHD, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u burst=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           lchan_desc->name, fn, ts->index, bid);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Forward burst to scheduler */</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = sched_trx_handle_tx_burst(trx, ts, lchan, fn, burst);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Forget this primitive */</span><br><span style="color: hsl(120, 100%, 40%);">+           sched_prim_drop(lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Reset mask */</span><br><span style="color: hsl(120, 100%, 40%);">+              *mask = 0x00;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               return rc;</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 we have sent the last (4/4) burst */</span><br><span style="color: hsl(120, 100%, 40%);">+    if ((*mask & 0x0f) == 0x0f) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Confirm data / traffic sending */</span><br><span style="color: hsl(120, 100%, 40%);">+          sched_send_dt_conf(trx, ts, lchan, fn, true);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Forget processed primitive */</span><br><span style="color: hsl(120, 100%, 40%);">+              sched_prim_drop(lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Reset mask */</span><br><span style="color: hsl(120, 100%, 40%);">+              *mask = 0x00;</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>diff --git a/src/host/trxcon/sched_trx.h b/src/host/trxcon/sched_trx.h</span><br><span>index 1f0dbc2..b7236d5 100644</span><br><span>--- a/src/host/trxcon/sched_trx.h</span><br><span>+++ b/src/host/trxcon/sched_trx.h</span><br><span>@@ -17,6 +17,9 @@</span><br><span> #define GPRS_BURST_LEN             GSM_BURST_LEN</span><br><span> #define EDGE_BURST_LEN         444</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define GPRS_L2_MAX_LEN                54</span><br><span style="color: hsl(120, 100%, 40%);">+#define EDGE_L2_MAX_LEN             155</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #define TRX_CH_LID_DEDIC       0x00</span><br><span> #define TRX_CH_LID_SACCH        0x40</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/11394">change 11394</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/11394"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmocom-bb </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I1176576f54c1d68e79cc6ac37d61a9033f7018dd </div>
<div style="display:none"> Gerrit-Change-Number: 11394 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Vadim Yanitskiy <axilirator@gmail.com> </div>