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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">DFU: add DFU application<br><br>this adds the DFU as application, allowing to flash the bootloader.<br>a USB DFU alternative is added to flash the bootloader partition.<br><br>when the DFU is started as bootloader, the partition/alternative<br>to flash the bootloader is marked as "not available", and<br>ineffective.<br>the same happens for the application partition when DFU is started<br>as application.<br><br>this distinction is make at compile time, not at runtime, because<br>of size restrictions (the bootloader was already close to the<br>16 kB limit).<br>*_dfu_flash.bin should not be mixed with *_dfu_dfu.bin.<br>*_dfu_dfu.bin should be flashed as application using the already<br>existing DFU bootloader.<br>once this images is started (as application), the *_dfu_flash.bin<br>should be flashed as bootloader using the DFU application.<br><br>once the DFU bootloader has been flashed, soft resetting<br>(not re-powering) will cause the bootloader to start, allowing to<br>flash the application with a normal image (e.g. not DFU),<br>replacing the DFU application.<br>this switch to DFU only happens after downloading (e.g. flashing).<br><br>it is planned to have the DFU application erase itself after<br>flashing, but this is currently not implemented.<br><br>Change-Id: Ic273bb593a7669111b0219fe301d7897419167c8<br>---<br>M firmware/Makefile<br>M firmware/apps/dfu/main.c<br>M firmware/apps/dfu/usb_strings.txt<br>M firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c<br>M firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h<br>M firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c<br>M firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c<br>M firmware/libboard/common/include/board_common.h<br>M firmware/libboard/common/source/board_cstartup_gnu.c<br>9 files changed, 92 insertions(+), 20 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/firmware/Makefile b/firmware/Makefile</span><br><span>index 5c7aa92..bdca6e5 100644</span><br><span>--- a/firmware/Makefile</span><br><span>+++ b/firmware/Makefile</span><br><span>@@ -41,7 +41,7 @@</span><br><span> </span><br><span> # Defines which are the available memory targets for the SAM3S-EK board.</span><br><span> ifeq ($(APP), dfu)</span><br><span style="color: hsl(0, 100%, 40%);">-MEMORIES ?= flash</span><br><span style="color: hsl(120, 100%, 40%);">+MEMORIES ?= flash dfu</span><br><span> else</span><br><span> MEMORIES ?= dfu</span><br><span> endif</span><br><span>diff --git a/firmware/apps/dfu/main.c b/firmware/apps/dfu/main.c</span><br><span>index 5aafc7c..2e80884 100644</span><br><span>--- a/firmware/apps/dfu/main.c</span><br><span>+++ b/firmware/apps/dfu/main.c</span><br><span>@@ -26,8 +26,15 @@</span><br><span> </span><br><span> #include <osmocom/core/timer.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* USB alternate interface index used to identify which partition to flash */</span><br><span style="color: hsl(120, 100%, 40%);">+/** USB alternate interface index indicating RAM partition */</span><br><span> #define ALTIF_RAM 0</span><br><span style="color: hsl(120, 100%, 40%);">+/** USB alternate interface index indicating flash partition */</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(ENVIRONMENT_flash)</span><br><span> #define ALTIF_FLASH 1</span><br><span style="color: hsl(120, 100%, 40%);">+#elif defined(ENVIRONMENT_dfu)</span><br><span style="color: hsl(120, 100%, 40%);">+#define ALTIF_FLASH 2</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> </span><br><span> unsigned int g_unique_id[4];</span><br><span> /* remember if the watchdog has been configured in the main loop so we can kick it in the ISR */</span><br><span>@@ -44,10 +51,18 @@</span><br><span>  *----------------------------------------------------------------------------*/</span><br><span> </span><br><span> #define RAM_ADDR(offset) (IRAM_ADDR + BOARD_DFU_RAM_SIZE + offset)</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(ENVIRONMENT_flash)</span><br><span> #define FLASH_ADDR(offset) (IFLASH_ADDR + BOARD_DFU_BOOT_SIZE + offset)</span><br><span style="color: hsl(120, 100%, 40%);">+#elif defined(ENVIRONMENT_dfu)</span><br><span style="color: hsl(120, 100%, 40%);">+#define FLASH_ADDR(offset) (IFLASH_ADDR + offset)</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#define IFLASH_END ((uint8_t *)IFLASH_ADDR + IFLASH_SIZE)</span><br><span style="color: hsl(0, 100%, 40%);">-#define IRAM_END  ((uint8_t *)IRAM_ADDR + IRAM_SIZE)</span><br><span style="color: hsl(120, 100%, 40%);">+#define IRAM_END ((uint8_t *)IRAM_ADDR + IRAM_SIZE)</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(ENVIRONMENT_flash)</span><br><span style="color: hsl(120, 100%, 40%);">+#define IFLASH_END ((uint8_t *)IFLASH_ADDR + IFLASH_SIZE)</span><br><span style="color: hsl(120, 100%, 40%);">+#elif defined(ENVIRONMENT_dfu)</span><br><span style="color: hsl(120, 100%, 40%);">+#define IFLASH_END ((uint8_t *)IFLASH_ADDR + BOARD_DFU_BOOT_SIZE)</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span> </span><br><span> /* incoming call-back: Host has transferred 'len' bytes (stored at</span><br><span>  * 'data'), which we shall write to 'offset' into the partition</span><br><span>@@ -90,7 +105,11 @@</span><br><span>             break;</span><br><span>       case ALTIF_FLASH:</span><br><span>            addr = FLASH_ADDR(offset);</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(ENVIRONMENT_flash)</span><br><span>           if (addr < IFLASH_ADDR || addr + len >= IFLASH_ADDR + IFLASH_SIZE) {</span><br><span style="color: hsl(120, 100%, 40%);">+#elif defined(ENVIRONMENT_dfu)</span><br><span style="color: hsl(120, 100%, 40%);">+            if (addr < IFLASH_ADDR || addr + len >= IFLASH_ADDR + BOARD_DFU_BOOT_SIZE) {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>                   g_dfu->state = DFU_STATE_dfuERROR;</span><br><span>                        g_dfu->status = DFU_STATUS_errADDRESS;</span><br><span>                    rc = DFU_RET_STALL;</span><br><span>@@ -281,12 +300,12 @@</span><br><span>  TRACE_INFO("DFU bootloader start reason: ");</span><br><span>       switch (USBDFU_OverrideEnterDFU()) {</span><br><span>         case 0:</span><br><span style="color: hsl(0, 100%, 40%);">-         /* 0 normally means that there is no override, but we are in the bootloader,</span><br><span style="color: hsl(0, 100%, 40%);">-             * thus the first check in board_cstartup_gnu did return something else than 0.</span><br><span style="color: hsl(0, 100%, 40%);">-          * this can only be g_dfu->magic which is erased when the segment are</span><br><span style="color: hsl(0, 100%, 40%);">-                 * relocated, which happens in board_cstartup_gnu just after USBDFU_OverrideEnterDFU.</span><br><span style="color: hsl(0, 100%, 40%);">-            * no static variable can be used to store this case since this will also be overwritten</span><br><span style="color: hsl(0, 100%, 40%);">-                 */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (SCB->VTOR < IFLASH_ADDR + BOARD_DFU_BOOT_SIZE) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    TRACE_INFO_WP("unknown\n\r");</span><br><span style="color: hsl(120, 100%, 40%);">+               } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      TRACE_INFO_WP("DFU is the main application\n\r");</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span>       case 1:</span><br><span>              TRACE_INFO_WP("DFU switch requested by main application\n\r");</span><br><span>             break;</span><br><span>diff --git a/firmware/apps/dfu/usb_strings.txt b/firmware/apps/dfu/usb_strings.txt</span><br><span>index f1c79bc..4a58cb8 100644</span><br><span>--- a/firmware/apps/dfu/usb_strings.txt</span><br><span>+++ b/firmware/apps/dfu/usb_strings.txt</span><br><span>@@ -3,3 +3,4 @@</span><br><span> DFU (Device Firmware Upgrade)</span><br><span> RAM</span><br><span> Flash (Application Partition)</span><br><span style="color: hsl(120, 100%, 40%);">+Flash (Bootloader Partition)</span><br><span>diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c</span><br><span>index ac2595c..1ebab5b 100644</span><br><span>--- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c</span><br><span>+++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c</span><br><span>@@ -1171,12 +1171,19 @@</span><br><span>  /* if we are currently in the DFU bootloader, and we are beyond</span><br><span>       * the MANIFEST stage, we shall switch to the normal</span><br><span>          * application */</span><br><span style="color: hsl(0, 100%, 40%);">-       if (g_dfu->past_manifest)</span><br><span style="color: hsl(120, 100%, 40%);">+  if (g_dfu->past_manifest) {</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(ENVIRONMENT_flash)</span><br><span>               USBDFU_SwitchToApp();</span><br><span style="color: hsl(120, 100%, 40%);">+#elif defined(ENVIRONMENT_dfu)</span><br><span style="color: hsl(120, 100%, 40%);">+         USBDFU_SwitchToDFU();</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> #else</span><br><span>         /* if we are currently in the main application, and we are in</span><br><span style="color: hsl(0, 100%, 40%);">-    * appDETACH state, switch into the DFU bootloader */</span><br><span style="color: hsl(0, 100%, 40%);">-   if (g_dfu->state == DFU_STATE_appDETACH)</span><br><span style="color: hsl(120, 100%, 40%);">+    * appDETACH state or past downloading, switch into the DFU bootloader.</span><br><span style="color: hsl(120, 100%, 40%);">+        */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (g_dfu->state == DFU_STATE_appDETACH || g_dfu->state == DFU_STATE_dfuMANIFEST)</span><br><span>              DFURT_SwitchToDFU();</span><br><span> #endif /* APPLICATION_dfu */</span><br><span> #endif /* BOARD_USB_DFU */</span><br><span>diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h</span><br><span>index 7354696..5bd8684 100644</span><br><span>--- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h</span><br><span>+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h</span><br><span>@@ -124,6 +124,9 @@</span><br><span> /* USBD tells us to switch from DFU mode to application mode */</span><br><span> void USBDFU_SwitchToApp(void);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* USBD tells us to switch from to DFU mode */</span><br><span style="color: hsl(120, 100%, 40%);">+void USBDFU_SwitchToDFU(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Return values to be used by USBDFU_handle_{dn,up}load */</span><br><span> #define DFU_RET_NOTHING      0</span><br><span> #define DFU_RET_ZLP        1</span><br><span>diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c</span><br><span>index ebbe070..faebc13 100644</span><br><span>--- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c</span><br><span>+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c</span><br><span>@@ -19,9 +19,10 @@</span><br><span>      STR_MANUF       = 1,</span><br><span>         STR_PROD,</span><br><span>    STR_CONFIG,</span><br><span style="color: hsl(120, 100%, 40%);">+   // strings for the first alternate interface (e.g. DFU)</span><br><span>      _STR_FIRST_ALT,</span><br><span>      // serial string</span><br><span style="color: hsl(0, 100%, 40%);">-        STR_SERIAL      = (_STR_FIRST_ALT+BOARD_DFU_NUM_IF),</span><br><span style="color: hsl(120, 100%, 40%);">+  STR_SERIAL      = (_STR_FIRST_ALT + BOARD_DFU_NUM_IF),</span><br><span>       // version string (on additional interface)</span><br><span>  VERSION_CONF_STR,</span><br><span>    VERSION_STR,</span><br><span>@@ -29,6 +30,25 @@</span><br><span>    STRING_DESC_CNT,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* string used to replace one of both DFU flash partition atlsettings */</span><br><span style="color: hsl(120, 100%, 40%);">+static const unsigned char usb_string_notavailable[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        USBStringDescriptor_LENGTH(13),</span><br><span style="color: hsl(120, 100%, 40%);">+       USBGenericDescriptor_STRING,</span><br><span style="color: hsl(120, 100%, 40%);">+  USBStringDescriptor_UNICODE('n'),</span><br><span style="color: hsl(120, 100%, 40%);">+     USBStringDescriptor_UNICODE('o'),</span><br><span style="color: hsl(120, 100%, 40%);">+     USBStringDescriptor_UNICODE('t'),</span><br><span style="color: hsl(120, 100%, 40%);">+     USBStringDescriptor_UNICODE(' '),</span><br><span style="color: hsl(120, 100%, 40%);">+     USBStringDescriptor_UNICODE('a'),</span><br><span style="color: hsl(120, 100%, 40%);">+     USBStringDescriptor_UNICODE('v'),</span><br><span style="color: hsl(120, 100%, 40%);">+     USBStringDescriptor_UNICODE('a'),</span><br><span style="color: hsl(120, 100%, 40%);">+     USBStringDescriptor_UNICODE('i'),</span><br><span style="color: hsl(120, 100%, 40%);">+     USBStringDescriptor_UNICODE('l'),</span><br><span style="color: hsl(120, 100%, 40%);">+     USBStringDescriptor_UNICODE('a'),</span><br><span style="color: hsl(120, 100%, 40%);">+     USBStringDescriptor_UNICODE('b'),</span><br><span style="color: hsl(120, 100%, 40%);">+     USBStringDescriptor_UNICODE('l'),</span><br><span style="color: hsl(120, 100%, 40%);">+     USBStringDescriptor_UNICODE('e'),</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* USB string for the serial (using 128-bit device ID) */</span><br><span> static unsigned char usb_string_serial[] = {</span><br><span>         USBStringDescriptor_LENGTH(32),</span><br><span>@@ -121,7 +141,7 @@</span><br><span>                .bNumEndpoints =        0,                                      \</span><br><span>            .bInterfaceClass =      0xfe,                                   \</span><br><span>            .bInterfaceSubClass =   1,                                      \</span><br><span style="color: hsl(0, 100%, 40%);">-               .iInterface =           (_STR_FIRST_ALT+ALT),                   \</span><br><span style="color: hsl(120, 100%, 40%);">+             .iInterface =           (_STR_FIRST_ALT + ALT),                 \</span><br><span>            .bInterfaceProtocol =   2,                                      \</span><br><span>    }</span><br><span> </span><br><span>@@ -180,6 +200,11 @@</span><br><span>         for (i = 0; i < ARRAY_SIZE(usb_strings) && i < ARRAY_SIZE(usb_strings_extended); i++) {</span><br><span>                usb_strings_extended[i] = usb_strings[i];</span><br><span>    }</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(ENVIRONMENT_dfu)</span><br><span style="color: hsl(120, 100%, 40%);">+       usb_strings_extended[_STR_FIRST_ALT + 1] = usb_string_notavailable;</span><br><span style="color: hsl(120, 100%, 40%);">+#elif defined(ENVIRONMENT_flash)</span><br><span style="color: hsl(120, 100%, 40%);">+ usb_strings_extended[_STR_FIRST_ALT + 2] = usb_string_notavailable;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>  usb_strings_extended[STR_SERIAL] = usb_string_serial;</span><br><span>        usb_strings_extended[VERSION_CONF_STR] = usb_string_version_conf;</span><br><span>    usb_strings_extended[VERSION_STR] = usb_string_version;</span><br><span>diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c</span><br><span>index 1cca7ab..cfb9f63 100644</span><br><span>--- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c</span><br><span>+++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c</span><br><span>@@ -43,7 +43,7 @@</span><br><span> </span><br><span> /** structure containing the DFU state and magic value to know if DFU or application should be started */</span><br><span> __dfudata struct dfudata _g_dfu = {</span><br><span style="color: hsl(0, 100%, 40%);">-    .state = DFU_STATE_appIDLE,</span><br><span style="color: hsl(120, 100%, 40%);">+   .state = DFU_STATE_dfuIDLE,</span><br><span>  .past_manifest = 0,</span><br><span>  .total_bytes = 0,</span><br><span> };</span><br><span>@@ -463,7 +463,20 @@</span><br><span>       /* make sure the MAGIC is not set to enter DFU again */</span><br><span>      g_dfu->magic = 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        printf("switching to app\r\n");</span><br><span style="color: hsl(120, 100%, 40%);">+     /* disconnect from USB to ensure re-enumeration */</span><br><span style="color: hsl(120, 100%, 40%);">+    USBD_Disconnect();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* disable any interrupts during transition */</span><br><span style="color: hsl(120, 100%, 40%);">+        __disable_irq();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Tell the hybrid to execute FTL JUMP! */</span><br><span style="color: hsl(120, 100%, 40%);">+    NVIC_SystemReset();</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 USBDFU_SwitchToDFU(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    /* make sure the MAGIC is not set to enter DFU again */</span><br><span style="color: hsl(120, 100%, 40%);">+       g_dfu->magic = USB_DFU_MAGIC;</span><br><span> </span><br><span>         /* disconnect from USB to ensure re-enumeration */</span><br><span>   USBD_Disconnect();</span><br><span>diff --git a/firmware/libboard/common/include/board_common.h b/firmware/libboard/common/include/board_common.h</span><br><span>index dd21e4b..7c4b908 100644</span><br><span>--- a/firmware/libboard/common/include/board_common.h</span><br><span>+++ b/firmware/libboard/common/include/board_common.h</span><br><span>@@ -112,10 +112,13 @@</span><br><span> #define BOARD_USB_UDP</span><br><span> </span><br><span> #define BOARD_USB_DFU</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #define BOARD_DFU_BOOT_SIZE    (16 * 1024)</span><br><span> #define BOARD_DFU_RAM_SIZE       (2 * 1024)</span><br><span> #define BOARD_DFU_PAGE_SIZE       512</span><br><span style="color: hsl(0, 100%, 40%);">-#define BOARD_DFU_NUM_IF     2</span><br><span style="color: hsl(120, 100%, 40%);">+/** number of DFU interfaces (used to flash specific partitions) */</span><br><span style="color: hsl(120, 100%, 40%);">+#define BOARD_DFU_NUM_IF        3</span><br><span> </span><br><span> extern void board_exec_dbg_cmd(int ch);</span><br><span> extern void board_main_top(void);</span><br><span>diff --git a/firmware/libboard/common/source/board_cstartup_gnu.c b/firmware/libboard/common/source/board_cstartup_gnu.c</span><br><span>index e82a2fb..d548a30 100644</span><br><span>--- a/firmware/libboard/common/source/board_cstartup_gnu.c</span><br><span>+++ b/firmware/libboard/common/source/board_cstartup_gnu.c</span><br><span>@@ -126,7 +126,7 @@</span><br><span>     IrqHandlerNotUsed   /* 35 not used */</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu)</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) && defined(ENVIRONMENT_flash)</span><br><span> #include "usb/device/dfu/dfu.h"</span><br><span> static void BootIntoApp(void)</span><br><span> {</span><br><span>@@ -159,8 +159,9 @@</span><br><span>         LowLevelInit() ;</span><br><span> </span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu)</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!USBDFU_OverrideEnterDFU()) {</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) && defined(ENVIRONMENT_flash)</span><br><span style="color: hsl(120, 100%, 40%);">+       // boot application if there is not DFU override</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!USBDFU_OverrideEnterDFU() && SCB->VTOR < IFLASH_ADDR + BOARD_DFU_BOOT_SIZE) {</span><br><span>             UART_Exit();</span><br><span>                 __disable_irq();</span><br><span>             BootIntoApp();</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/simtrace2/+/16558">change 16558</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/simtrace2/+/16558"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: simtrace2 </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ic273bb593a7669111b0219fe301d7897419167c8 </div>
<div style="display:none"> Gerrit-Change-Number: 16558 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: tsaitgaist <kredon@sysmocom.de> </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: tsaitgaist <kredon@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>