<p>tsaitgaist has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/simtrace2/+/16558">View Change</a></p><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;">git pull ssh://gerrit.osmocom.org:29418/simtrace2 refs/changes/58/16558/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/firmware/Makefile b/firmware/Makefile</span><br><span>index bd634aa..24e80be 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 3fe3270..26a45d2 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>@@ -1163,12 +1163,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: 1 </div>
<div style="display:none"> Gerrit-Owner: tsaitgaist <kredon@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>