This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
dexter gerrit-no-reply at lists.osmocom.org
Review at https://gerrit.osmocom.org/644
V42BIS integration
The previously committed SPANDSP v42bis implementation has been edited
to fit our needs. There was not much to change, other than removing
some clutter and merging private_v42bis.h and v42bis.h into one file.
The debug printf statements were converted into LOGP statements.
Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d
---
M openbsc/include/openbsc/Makefile.am
M openbsc/include/openbsc/debug.h
D openbsc/include/openbsc/private_v42bis.h
M openbsc/include/openbsc/v42bis.h
M openbsc/src/gprs/Makefile.am
M openbsc/src/gprs/v42bis.c
6 files changed, 162 insertions(+), 198 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/openbsc refs/changes/44/644/1
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index e159db5..bec9e4f 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -19,7 +19,7 @@
gprs_gsup_client.h bsc_msg_filter.h \
oap.h oap_messages.h \
gtphub.h gprs_sndcp.h slhc.h gprs_llc_xid.h gprs_sndcp_xid.h \
- gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h
+ gprs_sndcp_comp_entity.h gprs_sndcp_hdrcomp.h v42bis.h
openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
openbscdir = $(includedir)/openbsc
diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h
index 90ddca5..f98439f 100644
--- a/openbsc/include/openbsc/debug.h
+++ b/openbsc/include/openbsc/debug.h
@@ -28,7 +28,6 @@
DNS,
DBSSGP,
DLLC,
- DSNDCP,
DSLHC,
DNAT,
DCTRL,
@@ -37,6 +36,8 @@
DGTPHUB,
DRANAP,
DSUA,
+ DSNDCP,
+ DV42BIS,
Debug_LastEntry,
};
diff --git a/openbsc/include/openbsc/private_v42bis.h b/openbsc/include/openbsc/private_v42bis.h
deleted file mode 100644
index 96538f2..0000000
--- a/openbsc/include/openbsc/private_v42bis.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * SpanDSP - a series of DSP components for telephony
- *
- * private/v42bis.h
- *
- * Written by Steve Underwood <steveu at coppice.org>
- *
- * Copyright (C) 2005 Steve Underwood
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version 2.1,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: v42bis.h,v 1.1 2008/11/15 14:43:08 steveu Exp $
- */
-
-#if !defined(_SPANDSP_PRIVATE_V42BIS_H_)
-#define _SPANDSP_PRIVATE_V42BIS_H_
-
-/*!
- V.42bis dictionary node.
-*/
-typedef struct
-{
- /*! \brief The prior code for each defined code. */
- uint16_t parent_code;
- /*! \brief The number of leaf nodes this node has */
- int16_t leaves;
- /*! \brief This leaf octet for each defined code. */
- uint8_t node_octet;
- /*! \brief Bit map of the children which exist */
- uint32_t children[8];
-} v42bis_dict_node_t;
-
-/*!
- V.42bis compression. This defines the working state for a single instance
- of V.42bis compression.
-*/
-typedef struct
-{
- /*! \brief Compression mode. */
- int compression_mode;
- /*! \brief Callback function to handle received frames. */
- v42bis_frame_handler_t handler;
- /*! \brief An opaque pointer passed in calls to frame_handler. */
- void *user_data;
- /*! \brief The maximum frame length allowed */
- int max_len;
-
- uint32_t string_code;
- uint32_t latest_code;
- int string_length;
- uint32_t output_bit_buffer;
- int output_bit_count;
- int output_octet_count;
- uint8_t output_buf[1024];
- v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS];
- /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */
- int transparent;
- int change_transparency;
- /*! \brief IIR filter state, used in assessing compressibility. */
- int compressibility_filter;
- int compressibility_persistence;
-
- /*! \brief Next empty dictionary entry */
- uint32_t v42bis_parm_c1;
- /*! \brief Current codeword size */
- int v42bis_parm_c2;
- /*! \brief Threshold for codeword size change */
- uint32_t v42bis_parm_c3;
-
- /*! \brief Mark that this is the first octet/code to be processed */
- int first;
- uint8_t escape_code;
-} v42bis_compress_state_t;
-
-/*!
- V.42bis decompression. This defines the working state for a single instance
- of V.42bis decompression.
-*/
-typedef struct
-{
- /*! \brief Callback function to handle decompressed data. */
- v42bis_data_handler_t handler;
- /*! \brief An opaque pointer passed in calls to data_handler. */
- void *user_data;
- /*! \brief The maximum decompressed data block length allowed */
- int max_len;
-
- uint32_t old_code;
- uint32_t last_old_code;
- uint32_t input_bit_buffer;
- int input_bit_count;
- int octet;
- int last_length;
- int output_octet_count;
- uint8_t output_buf[1024];
- v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS];
- /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */
- int transparent;
-
- int last_extra_octet;
-
- /*! \brief Next empty dictionary entry */
- uint32_t v42bis_parm_c1;
- /*! \brief Current codeword size */
- int v42bis_parm_c2;
- /*! \brief Threshold for codeword size change */
- uint32_t v42bis_parm_c3;
-
- /*! \brief Mark that this is the first octet/code to be processed */
- int first;
- uint8_t escape_code;
- int escaped;
-} v42bis_decompress_state_t;
-
-/*!
- V.42bis compression/decompression descriptor. This defines the working state for a
- single instance of V.42bis compress/decompression.
-*/
-struct v42bis_state_s
-{
- /*! \brief V.42bis data compression directions. */
- int v42bis_parm_p0;
-
- /*! \brief Compression state. */
- v42bis_compress_state_t compress;
- /*! \brief Decompression state. */
- v42bis_decompress_state_t decompress;
-
- /*! \brief Maximum codeword size (bits) */
- int v42bis_parm_n1;
- /*! \brief Total number of codewords */
- uint32_t v42bis_parm_n2;
- /*! \brief Maximum string length */
- int v42bis_parm_n7;
-};
-
-#endif
-/*- End of file ------------------------------------------------------------*/
diff --git a/openbsc/include/openbsc/v42bis.h b/openbsc/include/openbsc/v42bis.h
index f13e5c5..a05a169 100644
--- a/openbsc/include/openbsc/v42bis.h
+++ b/openbsc/include/openbsc/v42bis.h
@@ -33,13 +33,16 @@
\section v42bis_page_sec_2 How does it work?
*/
-#if !defined(_SPANDSP_V42BIS_H_)
-#define _SPANDSP_V42BIS_H_
+#ifndef V42BIS_H
+#define V42BIS_H
#define V42BIS_MAX_BITS 12
#define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */
#define V42BIS_TABLE_SIZE 5021 /* This should be a prime >(2^V42BIS_MAX_BITS) */
#define V42BIS_MAX_STRING_SIZE 250
+
+#define TRUE 1
+#define FALSE 0
enum
{
@@ -60,39 +63,156 @@
typedef void (*v42bis_data_handler_t)(void *user_data, const uint8_t *buf, int len);
/*!
+ V.42bis dictionary node.
+*/
+typedef struct
+{
+ /*! \brief The prior code for each defined code. */
+ uint16_t parent_code;
+ /*! \brief The number of leaf nodes this node has */
+ int16_t leaves;
+ /*! \brief This leaf octet for each defined code. */
+ uint8_t node_octet;
+ /*! \brief Bit map of the children which exist */
+ uint32_t children[8];
+} v42bis_dict_node_t;
+
+/*!
+ V.42bis compression. This defines the working state for a single instance
+ of V.42bis compression.
+*/
+typedef struct
+{
+ /*! \brief Compression mode. */
+ int compression_mode;
+ /*! \brief Callback function to handle received frames. */
+ v42bis_frame_handler_t handler;
+ /*! \brief An opaque pointer passed in calls to frame_handler. */
+ void *user_data;
+ /*! \brief The maximum frame length allowed */
+ int max_len;
+
+ uint32_t string_code;
+ uint32_t latest_code;
+ int string_length;
+ uint32_t output_bit_buffer;
+ int output_bit_count;
+ int output_octet_count;
+ uint8_t output_buf[1024];
+ v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS];
+ /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */
+ int transparent;
+ int change_transparency;
+ /*! \brief IIR filter state, used in assessing compressibility. */
+ int compressibility_filter;
+ int compressibility_persistence;
+
+ /*! \brief Next empty dictionary entry */
+ uint32_t v42bis_parm_c1;
+ /*! \brief Current codeword size */
+ int v42bis_parm_c2;
+ /*! \brief Threshold for codeword size change */
+ uint32_t v42bis_parm_c3;
+
+ /*! \brief Mark that this is the first octet/code to be processed */
+ int first;
+ uint8_t escape_code;
+} v42bis_compress_state_t;
+
+/*!
+ V.42bis decompression. This defines the working state for a single instance
+ of V.42bis decompression.
+*/
+typedef struct
+{
+ /*! \brief Callback function to handle decompressed data. */
+ v42bis_data_handler_t handler;
+ /*! \brief An opaque pointer passed in calls to data_handler. */
+ void *user_data;
+ /*! \brief The maximum decompressed data block length allowed */
+ int max_len;
+
+ uint32_t old_code;
+ uint32_t last_old_code;
+ uint32_t input_bit_buffer;
+ int input_bit_count;
+ int octet;
+ int last_length;
+ int output_octet_count;
+ uint8_t output_buf[1024];
+ v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS];
+ /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */
+ int transparent;
+
+ int last_extra_octet;
+
+ /*! \brief Next empty dictionary entry */
+ uint32_t v42bis_parm_c1;
+ /*! \brief Current codeword size */
+ int v42bis_parm_c2;
+ /*! \brief Threshold for codeword size change */
+ uint32_t v42bis_parm_c3;
+
+ /*! \brief Mark that this is the first octet/code to be processed */
+ int first;
+ uint8_t escape_code;
+ int escaped;
+} v42bis_decompress_state_t;
+
+/*!
+ V.42bis compression/decompression descriptor. This defines the working state for a
+ single instance of V.42bis compress/decompression.
+*/
+struct v42bis_state_s
+{
+ /*! \brief V.42bis data compression directions. */
+ int v42bis_parm_p0;
+
+ /*! \brief Compression state. */
+ v42bis_compress_state_t compress;
+ /*! \brief Decompression state. */
+ v42bis_decompress_state_t decompress;
+
+ /*! \brief Maximum codeword size (bits) */
+ int v42bis_parm_n1;
+ /*! \brief Total number of codewords */
+ uint32_t v42bis_parm_n2;
+ /*! \brief Maximum string length */
+ int v42bis_parm_n7;
+};
+
+
+/*!
V.42bis compression/decompression descriptor. This defines the working state for a
single instance of V.42bis compress/decompression.
*/
typedef struct v42bis_state_s v42bis_state_t;
-#if defined(__cplusplus)
-extern "C"
-{
-#endif
+
/*! Compress a block of octets.
\param s The V.42bis context.
\param buf The data to be compressed.
\param len The length of the data buffer.
\return 0 */
-SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len);
+int v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len);
/*! Flush out any data remaining in a compression buffer.
\param s The V.42bis context.
\return 0 */
-SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s);
+int v42bis_compress_flush(v42bis_state_t *s);
/*! Decompress a block of octets.
\param s The V.42bis context.
\param buf The data to be decompressed.
\param len The length of the data buffer.
\return 0 */
-SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len);
+int v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len);
/*! Flush out any data remaining in the decompression buffer.
\param s The V.42bis context.
\return 0 */
-SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s);
+int v42bis_decompress_flush(v42bis_state_t *s);
/*! Set the compression mode.
\param s The V.42bis context.
@@ -100,7 +220,7 @@
V42BIS_COMPRESSION_MODE_DYNAMIC,
V42BIS_COMPRESSION_MODE_ALWAYS,
V42BIS_COMPRESSION_MODE_NEVER */
-SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode);
+void v42bis_compression_control(v42bis_state_t *s, int mode);
/*! Initialise a V.42bis context.
\param s The V.42bis context.
@@ -114,7 +234,7 @@
\param data_user_data An opaque pointer passed to the data callback handler.
\param max_data_len The maximum length that should be passed to the data handler.
\return The V.42bis context. */
-SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s,
+v42bis_state_t *v42bis_init(v42bis_state_t *s,
int negotiated_p0,
int negotiated_p1,
int negotiated_p2,
@@ -128,16 +248,12 @@
/*! Release a V.42bis context.
\param s The V.42bis context.
\return 0 if OK */
-SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s);
+int v42bis_release(v42bis_state_t *s);
/*! Free a V.42bis context.
\param s The V.42bis context.
\return 0 if OK */
-SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s);
-
-#if defined(__cplusplus)
-}
-#endif
+int v42bis_free(v42bis_state_t *s);
#endif
/*- End of file ------------------------------------------------------------*/
diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am
index 3d6c82a..2c03a45 100644
--- a/openbsc/src/gprs/Makefile.am
+++ b/openbsc/src/gprs/Makefile.am
@@ -22,7 +22,7 @@
osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \
slhc.c gprs_sndcp_xid.c gprs_sndcp_comp_entity.c \
- gprs_sndcp_hdrcomp.c \
+ gprs_sndcp_hdrcomp.c v42bis.c \
sgsn_main.c sgsn_vty.c sgsn_libgtp.c \
gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c \
gprs_llc_xid.c crc24.c \
diff --git a/openbsc/src/gprs/v42bis.c b/openbsc/src/gprs/v42bis.c
index d8d3f3f..049a8ac 100644
--- a/openbsc/src/gprs/v42bis.c
+++ b/openbsc/src/gprs/v42bis.c
@@ -31,10 +31,6 @@
/*! \file */
-#if defined(HAVE_CONFIG_H)
-#include "config.h"
-#endif
-
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
@@ -43,6 +39,7 @@
#include <fcntl.h>
#include <ctype.h>
#include <assert.h>
+#include <openbsc/debug.h>
#include "spandsp/telephony.h"
#include "spandsp/logging.h"
@@ -51,6 +48,7 @@
#include "spandsp/private/logging.h"
#include "spandsp/private/v42bis.h"
+
/* Fixed parameters from the spec. */
#define V42BIS_N3 8 /* Character size (bits) */
@@ -111,7 +109,7 @@
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len)
+int v42bis_compress(v42bis_state_t *s, const uint8_t *buf, int len)
{
int ptr;
int i;
@@ -270,7 +268,7 @@
{
if (ss->transparent)
{
- printf("Going compressed\n");
+ LOGP(DV42BIS, LOGL_DEBUG, "Going compressed\n");
/* 7.8.1 Transition to compressed mode */
/* Switch out of transparent now, between codes. We need to send the octet which did not
match, just before switching. */
@@ -292,7 +290,7 @@
{
if (!ss->transparent)
{
- printf("Going transparent\n");
+ LOGP(DV42BIS, LOGL_DEBUG, "Going transparent\n");
/* 7.8.2 Transition to transparent mode */
/* Switch into transparent now, between codes, and the unmatched octet should
go out in transparent mode, just below */
@@ -323,7 +321,7 @@
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s)
+int v42bis_compress_flush(v42bis_state_t *s)
{
v42bis_compress_state_t *ss;
@@ -353,7 +351,7 @@
/*- End of function --------------------------------------------------------*/
#if 0
-SPAN_DECLARE(int) v42bis_compress_dump(v42bis_state_t *s)
+int v42bis_compress_dump(v42bis_state_t *s)
{
int i;
@@ -361,7 +359,7 @@
{
if (s->compress.dict[i].parent_code != 0xFFFF)
{
- printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet);
+ LOGP(DV42BIS, LOGL_DEBUG, "Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->compress.dict[i].parent_code, s->compress.dict[i].leaves, s->compress.dict[i].node_octet);
}
}
return 0;
@@ -369,7 +367,7 @@
/*- End of function --------------------------------------------------------*/
#endif
-SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len)
+int v42bis_decompress(v42bis_state_t *s, const uint8_t *buf, int len)
{
int ptr;
int i;
@@ -414,13 +412,13 @@
ss->escaped = FALSE;
if (code == V42BIS_ECM)
{
- printf("Hit V42BIS_ECM\n");
+ LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_ECM\n");
ss->transparent = FALSE;
code_len = ss->v42bis_parm_c2;
}
else if (code == V42BIS_EID)
{
- printf("Hit V42BIS_EID\n");
+ LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_EID\n");
ss->output_buf[ss->output_octet_count++] = ss->escape_code - 1;
if (ss->output_octet_count >= ss->max_len - s->v42bis_parm_n7)
{
@@ -430,11 +428,11 @@
}
else if (code == V42BIS_RESET)
{
- printf("Hit V42BIS_RESET\n");
+ LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_RESET\n");
}
else
{
- printf("Hit V42BIS_???? - %" PRIu32 "\n", code);
+ LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_???? - %" PRIu32 "\n", code);
}
}
else if (code == ss->escape_code)
@@ -460,17 +458,17 @@
switch (new_code)
{
case V42BIS_ETM:
- printf("Hit V42BIS_ETM\n");
+ LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_ETM\n");
ss->transparent = TRUE;
code_len = 8;
break;
case V42BIS_FLUSH:
- printf("Hit V42BIS_FLUSH\n");
+ LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_FLUSH\n");
v42bis_decompress_flush(s);
break;
case V42BIS_STEPUP:
/* We need to increase the codeword size */
- printf("Hit V42BIS_STEPUP\n");
+ LOGP(DV42BIS, LOGL_DEBUG, "Hit V42BIS_STEPUP\n");
if (ss->v42bis_parm_c3 >= s->v42bis_parm_n2)
{
/* Invalid condition */
@@ -507,7 +505,7 @@
/* Trace back through the octets which form the string, and output them. */
while (code >= V42BIS_N5)
{
-if (code > 4095) {printf("Code is 0x%" PRIu32 "\n", code); exit(2);}
+if (code > 4095) {LOGP(DV42BIS, LOGL_DEBUG, "Code is 0x%" PRIu32 "\n", code); exit(2);}
*string-- = ss->dict[code].node_octet;
code = ss->dict[code].parent_code;
}
@@ -567,7 +565,7 @@
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s)
+int v42bis_decompress_flush(v42bis_state_t *s)
{
v42bis_decompress_state_t *ss;
@@ -583,7 +581,7 @@
/*- End of function --------------------------------------------------------*/
#if 0
-SPAN_DECLARE(int) v42bis_decompress_dump(v42bis_state_t *s)
+int v42bis_decompress_dump(v42bis_state_t *s)
{
int i;
@@ -591,7 +589,7 @@
{
if (s->decompress.dict[i].parent_code != 0xFFFF)
{
- printf("Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet);
+ LOGP(DV42BIS, LOGL_DEBUG, "Entry %4x, prior %4x, leaves %d, octet %2x\n", i, s->decompress.dict[i].parent_code, s->decompress.dict[i].leaves, s->decompress.dict[i].node_octet);
}
}
return 0;
@@ -599,7 +597,7 @@
/*- End of function --------------------------------------------------------*/
#endif
-SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode)
+void v42bis_compression_control(v42bis_state_t *s, int mode)
{
s->compress.compression_mode = mode;
switch (mode)
@@ -614,7 +612,7 @@
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE(v42bis_state_t *) v42bis_init(v42bis_state_t *s,
+v42bis_state_t *v42bis_init(v42bis_state_t *s,
int negotiated_p0,
int negotiated_p1,
int negotiated_p2,
@@ -687,13 +685,13 @@
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s)
+int v42bis_release(v42bis_state_t *s)
{
return 0;
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s)
+int v42bis_free(v42bis_state_t *s)
{
free(s);
return 0;
--
To view, visit https://gerrit.osmocom.org/644
To unsubscribe, visit https://gerrit.osmocom.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I689413f2541b6def0625ce6bd96f1f488f05f99d
Gerrit-PatchSet: 1
Gerrit-Project: openbsc
Gerrit-Branch: master
Gerrit-Owner: dexter <pmaier at sysmocom.de>