isdn: Add V.110 encoder/decoder

V.110 defines a B-channel protocol for transmission of synchronous and
asynchronous serial data of V-series interfaces via terminal adapters
over ISDN.

Let's add (unoptimized but easy to debug) functions for encoding and
decoding of V.110 frames for various bit-rates.

Related: OS#1572
Change-Id: I1b5fd3847d3bfb0a0f763e0574893962ec699680
diff --git a/tests/Makefile.am b/tests/Makefile.am
index eeefd3e..f0c80d5 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -50,6 +50,8 @@
 		 smscb/gsm0341_test                                     \
 		 smscb/cbsp_test                                        \
 		 auth/xor2g_test                                        \
+		 v110/test_frame                                        \
+		 v110/test_ra1                                          \
 		 $(NULL)
 
 if ENABLE_MSGFILE
@@ -339,6 +341,12 @@
 iuup_iuup_test_SOURCES = iuup/iuup_test.c
 iuup_iuup_test_LDADD = $(LDADD) $(top_builddir)/src/gsm/libosmogsm.la
 
+v110_test_frame_SOURCES = v110/test_frame.c
+v110_test_frame_LDADD = $(LDADD) $(top_builddir)/src/isdn/libosmoisdn.la
+
+v110_test_ra1_SOURCES = v110/test_ra1.c
+v110_test_ra1_LDADD = $(LDADD) $(top_builddir)/src/isdn/libosmoisdn.la
+
 # The `:;' works around a Bash 3.2 bug when the output is not writeable.
 $(srcdir)/package.m4: $(top_srcdir)/configure.ac
 	:;{ \
@@ -437,6 +445,8 @@
 	     smscb/smscb_test.ok \
 	     smscb/gsm0341_test.ok \
 	     smscb/cbsp_test.ok \
+	     v110/test_frame.ok \
+	     v110/test_ra1.ok \
 	     $(NULL)
 
 if ENABLE_LIBSCTP
@@ -640,6 +650,10 @@
 		>$(srcdir)/time_cc/time_cc_test.ok
 	iuup/iuup_test \
 		>$(srcdir)/iuup/iuup_test.ok
+	v110/test_frame \
+		>$(srcdir)/v110/test_frame.ok
+	v110/test_ra1 \
+		>$(srcdir)/v110/test_ra1.ok
 
 check-local: atconfig $(TESTSUITE)
 	[ -e /proc/cpuinfo ] && cat /proc/cpuinfo
diff --git a/tests/testsuite.at b/tests/testsuite.at
index e447cdc..39cf54a 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -490,3 +490,15 @@
 cat $abs_srcdir/iuup/iuup_test.ok > expout
 AT_CHECK([$abs_top_builddir/tests/iuup/iuup_test], [0], [expout], [ignore])
 AT_CLEANUP
+
+AT_SETUP([v110_test_frame])
+AT_KEYWORDS([v110_test_frame])
+cat $abs_srcdir/v110/test_frame.ok > expout
+AT_CHECK([$abs_top_builddir/tests/v110/test_frame], [], [expout],[])
+AT_CLEANUP
+
+AT_SETUP([v110_test_ra1])
+AT_KEYWORDS([v110_test_ra1])
+cat $abs_srcdir/v110/test_ra1.ok > expout
+AT_CHECK([$abs_top_builddir/tests/v110/test_ra1], [], [expout],[])
+AT_CLEANUP
diff --git a/tests/v110/test_frame.c b/tests/v110/test_frame.c
new file mode 100644
index 0000000..ebc617c
--- /dev/null
+++ b/tests/v110/test_frame.c
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/isdn/v110.h>
+
+
+static void test_frame_enc(void)
+{
+	struct osmo_v110_decoded_frame fr;
+	ubit_t bits[80];
+	unsigned int i;
+
+	memset(&fr, 0, sizeof(fr));
+
+	/* we abuse the fact that ubit_t is 8bit so we can actually
+	 * store integer values to clearly identify which bit ends up where */
+
+	/* D1..D48: 101..148 */
+	for (i = 0; i < ARRAY_SIZE(fr.d_bits); i++)
+		fr.d_bits[i] = 101 + i;
+	/* E1..E7: 201..207 */
+	for (i = 0; i < ARRAY_SIZE(fr.e_bits); i++)
+		fr.e_bits[i] = 201 + i;
+	/* S1..S9: 211..219 */
+	for (i = 0; i < ARRAY_SIZE(fr.s_bits); i++)
+		fr.s_bits[i] = 211 + i;
+	/* X1..X2: 221..222 */
+	for (i = 0; i < ARRAY_SIZE(fr.x_bits); i++)
+		fr.x_bits[i] = 221 + i;
+
+	/* run encoder and dump to stdout */
+	memset(bits, 0xff, sizeof(bits));
+	osmo_v110_encode_frame(bits, sizeof(bits), &fr);
+	osmo_v110_ubit_dump(stdout, bits, sizeof(bits));
+
+	/* run decoder on what we just encoded */
+	memset(&fr, 0, sizeof(fr));
+	osmo_v110_decode_frame(&fr, bits, sizeof(bits));
+
+	/* re-encode and dump again 'expout' will match it. */
+	memset(bits, 0xff, sizeof(bits));
+	osmo_v110_encode_frame(bits, sizeof(bits), &fr);
+	osmo_v110_ubit_dump(stdout, bits, sizeof(bits));
+}
+
+
+int main(int argc, char **argv)
+{
+	test_frame_enc();
+}
+
diff --git a/tests/v110/test_frame.ok b/tests/v110/test_frame.ok
new file mode 100644
index 0000000..ecefaa8
--- /dev/null
+++ b/tests/v110/test_frame.ok
@@ -0,0 +1,20 @@
+0	0	0	0	0	0	0	0
+1	101	102	103	104	105	106	211
+1	107	108	109	110	111	112	221
+1	113	114	115	116	117	118	213
+1	119	120	121	122	123	124	214
+1	201	202	203	204	205	206	207
+1	125	126	127	128	129	130	216
+1	131	132	133	134	135	136	222
+1	137	138	139	140	141	142	218
+1	143	144	145	146	147	148	219
+0	0	0	0	0	0	0	0
+1	101	102	103	104	105	106	211
+1	107	108	109	110	111	112	221
+1	113	114	115	116	117	118	213
+1	119	120	121	122	123	124	214
+1	201	202	203	204	205	206	207
+1	125	126	127	128	129	130	216
+1	131	132	133	134	135	136	222
+1	137	138	139	140	141	142	218
+1	143	144	145	146	147	148	219
diff --git a/tests/v110/test_ra1.c b/tests/v110/test_ra1.c
new file mode 100644
index 0000000..775ec4b
--- /dev/null
+++ b/tests/v110/test_ra1.c
@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/isdn/v110.h>
+
+
+static void test_ra1(enum osmo_v100_sync_ra1_rate rate)
+{
+	int user_rate = osmo_v110_sync_ra1_get_user_data_rate(rate);
+	int user_data_chunk_bits = osmo_v110_sync_ra1_get_user_data_chunk_bitlen(rate);
+	struct osmo_v110_decoded_frame fr;
+	ubit_t user_bits[48];
+	ubit_t bits[80];
+	unsigned int i;
+	int rc;
+
+	printf("\n======= User data rate %u\n", user_rate);
+
+	/* we abuse the fact that ubit_t is 8bit so we can actually
+	 * store integer values to clearly identify which bit ends up where */
+	memset(user_bits, 0xFE, sizeof(user_bits));
+	for (i = 0; i < user_data_chunk_bits; i++)
+		user_bits[i] = 101 + i;
+
+	printf("user_bits: ");
+	for (i = 0; i < user_data_chunk_bits; i++)
+		printf("%03d ", user_bits[i]);
+	printf("\n");
+
+	/* generate the decoded v.110 frame */
+	memset(&fr, 0, sizeof(fr));
+	rc = osmo_v110_sync_ra1_user_to_ir(rate, &fr, user_bits, user_data_chunk_bits);
+	OSMO_ASSERT(rc == 0);
+
+	/* run encoder and dump to stdout */
+	memset(bits, 0xff, sizeof(bits));
+	osmo_v110_encode_frame(bits, sizeof(bits), &fr);
+	printf("dumping %u encoded bits in V.110 frame:\n", user_data_chunk_bits);
+	osmo_v110_ubit_dump(stdout, bits, sizeof(bits));
+
+	/* run decoder on what we just encoded */
+	memset(&fr, 0, sizeof(fr));
+	osmo_v110_decode_frame(&fr, bits, sizeof(bits));
+	printf("dumping re-decoded V.110 frame:\n");
+	printf("E-bits: %s\n", osmo_hexdump(fr.e_bits, sizeof(fr.e_bits)));
+	printf("S-bits: %s\n", osmo_hexdump(fr.s_bits, sizeof(fr.s_bits)));
+
+	/* re-encode and dump again 'expout' will match it. */
+	memset(user_bits, 0xff, sizeof(user_bits));
+	rc = osmo_v110_sync_ra1_ir_to_user(rate, user_bits, sizeof(user_bits), &fr);
+	if (rc != user_data_chunk_bits) {
+		fprintf(stderr, "ERROR: adapt_ir_to_user() returned %d, expected %u\n", rc,
+			user_data_chunk_bits);
+		exit(23);
+	}
+	fprintf(stdout, "re-decoded user bits: ");
+	for (i = 0; i < user_data_chunk_bits; i++)
+		printf("%03d ", user_bits[i]);
+	printf("\n");
+}
+
+
+int main(int argc, char **argv)
+{
+	for (int i = 0; i < _NUM_OSMO_V110_SYNC_RA1; i++)
+		test_ra1(i);
+}
+
diff --git a/tests/v110/test_ra1.ok b/tests/v110/test_ra1.ok
new file mode 100644
index 0000000..8a61fc3
--- /dev/null
+++ b/tests/v110/test_ra1.ok
@@ -0,0 +1,216 @@
+
+======= User data rate 600
+user_bits: 101 102 103 104 105 106 
+dumping 6 encoded bits in V.110 frame:
+0	0	0	0	0	0	0	0
+1	101	101	101	101	101	101	0
+1	101	101	102	102	102	102	0
+1	102	102	102	102	103	103	0
+1	103	103	103	103	103	103	0
+1	1	0	0	0	0	0	0
+1	104	104	104	104	104	104	0
+1	104	104	105	105	105	105	0
+1	105	105	105	105	106	106	0
+1	106	106	106	106	106	106	0
+dumping re-decoded V.110 frame:
+E-bits: 01 00 00 00 00 00 00 
+S-bits: 00 00 00 00 00 00 00 00 00 
+re-decoded user bits: 101 102 103 104 105 106 
+
+======= User data rate 1200
+user_bits: 101 102 103 104 105 106 107 108 109 110 111 112 
+dumping 12 encoded bits in V.110 frame:
+0	0	0	0	0	0	0	0
+1	101	101	101	101	102	102	0
+1	102	102	103	103	103	103	0
+1	104	104	104	104	105	105	0
+1	105	105	106	106	106	106	0
+1	0	1	0	0	0	0	0
+1	107	107	107	107	108	108	0
+1	108	108	109	109	109	109	0
+1	110	110	110	110	111	111	0
+1	111	111	112	112	112	112	0
+dumping re-decoded V.110 frame:
+E-bits: 00 01 00 00 00 00 00 
+S-bits: 00 00 00 00 00 00 00 00 00 
+re-decoded user bits: 101 102 103 104 105 106 107 108 109 110 111 112 
+
+======= User data rate 2400
+user_bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 
+dumping 24 encoded bits in V.110 frame:
+0	0	0	0	0	0	0	0
+1	101	101	102	102	103	103	0
+1	104	104	105	105	106	106	0
+1	107	107	108	108	109	109	0
+1	110	110	111	111	112	112	0
+1	1	1	0	0	0	0	0
+1	113	113	114	114	115	115	0
+1	116	116	117	117	118	118	0
+1	119	119	120	120	121	121	0
+1	122	122	123	123	124	124	0
+dumping re-decoded V.110 frame:
+E-bits: 01 01 00 00 00 00 00 
+S-bits: 00 00 00 00 00 00 00 00 00 
+re-decoded user bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 
+
+======= User data rate 4800
+user_bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 
+dumping 48 encoded bits in V.110 frame:
+0	0	0	0	0	0	0	0
+1	101	102	103	104	105	106	0
+1	107	108	109	110	111	112	0
+1	113	114	115	116	117	118	0
+1	119	120	121	122	123	124	0
+1	0	1	1	0	0	0	0
+1	125	126	127	128	129	130	0
+1	131	132	133	134	135	136	0
+1	137	138	139	140	141	142	0
+1	143	144	145	146	147	148	0
+dumping re-decoded V.110 frame:
+E-bits: 00 01 01 00 00 00 00 
+S-bits: 00 00 00 00 00 00 00 00 00 
+re-decoded user bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 
+
+======= User data rate 7200
+user_bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 
+dumping 36 encoded bits in V.110 frame:
+0	0	0	0	0	0	0	0
+1	101	102	103	104	105	106	0
+1	107	108	109	110	1	1	0
+1	111	112	1	1	113	114	0
+1	1	1	115	116	117	118	0
+1	1	0	1	0	0	0	0
+1	119	120	121	122	123	124	0
+1	125	126	127	128	1	1	0
+1	129	130	1	1	131	132	0
+1	1	1	133	134	135	136	0
+dumping re-decoded V.110 frame:
+E-bits: 01 00 01 00 00 00 00 
+S-bits: 00 00 00 00 00 00 00 00 00 
+re-decoded user bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 
+
+======= User data rate 9600
+user_bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 
+dumping 48 encoded bits in V.110 frame:
+0	0	0	0	0	0	0	0
+1	101	102	103	104	105	106	0
+1	107	108	109	110	111	112	0
+1	113	114	115	116	117	118	0
+1	119	120	121	122	123	124	0
+1	0	1	1	0	0	0	0
+1	125	126	127	128	129	130	0
+1	131	132	133	134	135	136	0
+1	137	138	139	140	141	142	0
+1	143	144	145	146	147	148	0
+dumping re-decoded V.110 frame:
+E-bits: 00 01 01 00 00 00 00 
+S-bits: 00 00 00 00 00 00 00 00 00 
+re-decoded user bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 
+
+======= User data rate 12000
+user_bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 
+dumping 30 encoded bits in V.110 frame:
+0	0	0	0	0	0	0	0
+1	101	102	103	104	105	106	0
+1	107	108	109	110	1	1	0
+1	111	112	1	1	113	114	0
+1	1	1	115	1	1	1	0
+1	0	0	1	0	0	0	0
+1	116	117	118	119	120	121	0
+1	122	123	124	125	1	1	0
+1	126	127	1	1	128	129	0
+1	1	1	130	1	1	1	0
+dumping re-decoded V.110 frame:
+E-bits: 00 00 01 00 00 00 00 
+S-bits: 00 00 00 00 00 00 00 00 00 
+re-decoded user bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 
+
+======= User data rate 14400
+user_bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 
+dumping 36 encoded bits in V.110 frame:
+0	0	0	0	0	0	0	0
+1	101	102	103	104	105	106	0
+1	107	108	109	110	1	1	0
+1	111	112	1	1	113	114	0
+1	1	1	115	116	117	118	0
+1	1	0	1	0	0	0	0
+1	119	120	121	122	123	124	0
+1	125	126	127	128	1	1	0
+1	129	130	1	1	131	132	0
+1	1	1	133	134	135	136	0
+dumping re-decoded V.110 frame:
+E-bits: 01 00 01 00 00 00 00 
+S-bits: 00 00 00 00 00 00 00 00 00 
+re-decoded user bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 
+
+======= User data rate 19200
+user_bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 
+dumping 48 encoded bits in V.110 frame:
+0	0	0	0	0	0	0	0
+1	101	102	103	104	105	106	0
+1	107	108	109	110	111	112	0
+1	113	114	115	116	117	118	0
+1	119	120	121	122	123	124	0
+1	0	1	1	0	0	0	0
+1	125	126	127	128	129	130	0
+1	131	132	133	134	135	136	0
+1	137	138	139	140	141	142	0
+1	143	144	145	146	147	148	0
+dumping re-decoded V.110 frame:
+E-bits: 00 01 01 00 00 00 00 
+S-bits: 00 00 00 00 00 00 00 00 00 
+re-decoded user bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 
+
+======= User data rate 24000
+user_bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 
+dumping 30 encoded bits in V.110 frame:
+0	0	0	0	0	0	0	0
+1	101	102	103	104	105	106	0
+1	107	108	109	110	1	1	0
+1	111	112	1	1	113	114	0
+1	1	1	115	1	1	1	0
+1	0	0	1	0	0	0	0
+1	116	117	118	119	120	121	0
+1	122	123	124	125	1	1	0
+1	126	127	1	1	128	129	0
+1	1	1	130	1	1	1	0
+dumping re-decoded V.110 frame:
+E-bits: 00 00 01 00 00 00 00 
+S-bits: 00 00 00 00 00 00 00 00 00 
+re-decoded user bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 
+
+======= User data rate 28800
+user_bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 
+dumping 36 encoded bits in V.110 frame:
+0	0	0	0	0	0	0	0
+1	101	102	103	104	105	106	0
+1	107	108	109	110	1	1	0
+1	111	112	1	1	113	114	0
+1	1	1	115	116	117	118	0
+1	1	0	1	0	0	0	0
+1	119	120	121	122	123	124	0
+1	125	126	127	128	1	1	0
+1	129	130	1	1	131	132	0
+1	1	1	133	134	135	136	0
+dumping re-decoded V.110 frame:
+E-bits: 01 00 01 00 00 00 00 
+S-bits: 00 00 00 00 00 00 00 00 00 
+re-decoded user bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 
+
+======= User data rate 38400
+user_bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 
+dumping 48 encoded bits in V.110 frame:
+0	0	0	0	0	0	0	0
+1	101	102	103	104	105	106	0
+1	107	108	109	110	111	112	0
+1	113	114	115	116	117	118	0
+1	119	120	121	122	123	124	0
+1	0	1	1	0	0	0	0
+1	125	126	127	128	129	130	0
+1	131	132	133	134	135	136	0
+1	137	138	139	140	141	142	0
+1	143	144	145	146	147	148	0
+dumping re-decoded V.110 frame:
+E-bits: 00 01 01 00 00 00 00 
+S-bits: 00 00 00 00 00 00 00 00 00 
+re-decoded user bits: 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148