[PATCH] libosmocore[master]: gsm0503: migrate transcoding routines from OsmoBTS

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/.

Vadim Yanitskiy gerrit-no-reply at lists.osmocom.org
Mon Sep 5 16:15:29 UTC 2016


Review at  https://gerrit.osmocom.org/816

gsm0503: migrate transcoding routines from OsmoBTS

The GSM 05.03 transcoding routines are becoming increasingly popular,
and some projects (such as GR-GSM and OsmocomBB) also require transcoding
capabilities implemented within the libosmocore. Moreover, it would be
beeter to clean up the OsmoBTS source code, sharing this code.

Currently there are the following data types supported:

 - xCCH
 - PDTCH
 - PDTCH (EDGE)
 - TCH/FR
 - TCH/HR
 - TCH/AFS
 - RCH/AHS
 - RACH
 - SCH

Also, the conv_gen.py was updated, and now writes a single file.
The EDGE MCS convolutional codes are migrated 'as is', i.e. already
in generated state.

Change-Id: I257a5d015798ee9e690fd035ca97fd971cf9f60a
---
M .gitignore
M include/osmocom/gsm/gsm0503.h
A include/osmocom/gsm/gsm0503_coding.h
A include/osmocom/gsm/gsm0503_interleaving.h
A include/osmocom/gsm/gsm0503_mapping.h
A include/osmocom/gsm/gsm0503_parity.h
A include/osmocom/gsm/gsm0503_tables.h
M src/gsm/Makefile.am
A src/gsm/gsm0503_coding.c
A src/gsm/gsm0503_conv_edge.c
A src/gsm/gsm0503_interleaving.c
A src/gsm/gsm0503_mapping.c
A src/gsm/gsm0503_parity.c
A src/gsm/gsm0503_tables.c
M src/gsm/libosmogsm.map
M utils/conv_gen.py
16 files changed, 6,752 insertions(+), 327 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/16/816/1

diff --git a/.gitignore b/.gitignore
index 5165364..dd9c61b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -110,6 +110,7 @@
 doc/*.tag
 
 src/crc*gen.c
+src/gsm/gsm6*.c
 src/gsm/conv*gen.c
 include/osmocom/core/crc*gen.h
 include/osmocom/core/bit*gen.h
diff --git a/include/osmocom/gsm/gsm0503.h b/include/osmocom/gsm/gsm0503.h
index cf1c976..3fda4ce 100644
--- a/include/osmocom/gsm/gsm0503.h
+++ b/include/osmocom/gsm/gsm0503.h
@@ -26,7 +26,7 @@
 
 #include <osmocom/core/conv.h>
 
-/*! \file conv_gen.h
+/*! \file gsm0503.h
  * Osmocom convolutional encoder/decoder for xCCH channels, see 3GPP TS 05.03
  */
 
@@ -36,10 +36,26 @@
  */
 extern const struct osmo_conv_code gsm0503_xcch;
 
+/*! \brief structure describing convolutional code RACH
+ */
+extern const struct osmo_conv_code gsm0503_rach;
+
+/*! \brief structure describing convolutional code SCH
+ */
+extern const struct osmo_conv_code gsm0503_sch;
+
 /*! \brief structures describing convolutional codes CS2/3
  */
 extern const struct osmo_conv_code gsm0503_cs2;
 extern const struct osmo_conv_code gsm0503_cs3;
+
+/*! \brief structure describing convolutional code TCH/FR
+ */
+extern const struct osmo_conv_code gsm0503_tch_fr;
+
+/*! \brief structure describing convolutional code TCH/HR
+ */
+extern const struct osmo_conv_code gsm0503_tch_hr;
 
 /*! \brief structure describing convolutional code TCH/AFS 12.2
  */
@@ -72,3 +88,87 @@
 /*! \brief structure describing convolutional code TCH/AFS 4.75
  */
 extern const struct osmo_conv_code gsm0503_tch_afs_4_75;
+
+/*! \brief structure describing convolutional code TCH/AHS 7.95
+ */
+extern const struct osmo_conv_code gsm0503_tch_ahs_7_95;
+
+/*! \brief structure describing convolutional code TCH/AHS 7.4
+ */
+extern const struct osmo_conv_code gsm0503_tch_ahs_7_4;
+
+/*! \brief structure describing convolutional code TCH/AHS 6.7
+ */
+extern const struct osmo_conv_code gsm0503_tch_ahs_6_7;
+
+/*! \brief structure describing convolutional code TCH/AHS 5.9
+ */
+extern const struct osmo_conv_code gsm0503_tch_ahs_5_9;
+
+/*! \brief structure describing convolutional code TCH/AHS 5.15
+ */
+extern const struct osmo_conv_code gsm0503_tch_ahs_5_15;
+
+/*! \brief structure describing convolutional code TCH/AHS 4.75
+ */
+extern const struct osmo_conv_code gsm0503_tch_ahs_4_75;
+
+/*! \brief structure describing convolutional code EDGE MCS1 DL HDR
+ */
+extern const struct osmo_conv_code gsm0503_mcs1_dl_hdr;
+
+/*! \brief structure describing convolutional code EDGE MCS1 UL HDR
+ */
+extern const struct osmo_conv_code gsm0503_mcs1_ul_hdr;
+
+/*! \brief structure describing convolutional code EDGE MCS1
+ */
+extern const struct osmo_conv_code gsm0503_mcs1;
+
+/*! \brief structure describing convolutional code EDGE MCS2
+ */
+extern const struct osmo_conv_code gsm0503_mcs2;
+
+/*! \brief structure describing convolutional code EDGE MCS3
+ */
+extern const struct osmo_conv_code gsm0503_mcs3;
+
+/*! \brief structure describing convolutional code EDGE MCS4
+ */
+extern const struct osmo_conv_code gsm0503_mcs4;
+
+/*! \brief structure describing convolutional code EDGE MCS5 DL HDR
+ */
+extern const struct osmo_conv_code gsm0503_mcs5_dl_hdr;
+
+/*! \brief structure describing convolutional code EDGE MCS5 UL HDR
+ */
+extern const struct osmo_conv_code gsm0503_mcs5_ul_hdr;
+
+/*! \brief structure describing convolutional code EDGE MCS5
+ */
+extern const struct osmo_conv_code gsm0503_mcs5;
+
+/*! \brief structure describing convolutional code EDGE MCS6
+ */
+extern const struct osmo_conv_code gsm0503_mcs6;
+
+/*! \brief structure describing convolutional code EDGE MCS7 DL HDR
+ */
+extern const struct osmo_conv_code gsm0503_mcs7_dl_hdr;
+
+/*! \brief structure describing convolutional code EDGE MCS7 UL HDR
+ */
+extern const struct osmo_conv_code gsm0503_mcs7_ul_hdr;
+
+/*! \brief structure describing convolutional code EDGE MCS7
+ */
+extern const struct osmo_conv_code gsm0503_mcs7;
+
+/*! \brief structure describing convolutional code EDGE MCS8
+ */
+extern const struct osmo_conv_code gsm0503_mcs8;
+
+/*! \brief structure describing convolutional code EDGE MCS9
+ */
+extern const struct osmo_conv_code gsm0503_mcs9;
diff --git a/include/osmocom/gsm/gsm0503_coding.h b/include/osmocom/gsm/gsm0503_coding.h
new file mode 100644
index 0000000..76f6b7a
--- /dev/null
+++ b/include/osmocom/gsm/gsm0503_coding.h
@@ -0,0 +1,85 @@
+/* 
+ * GSM 05.03 transcoding routines
+ *
+ * (C) 2013 by Andreas Eversberg <jolly at eversberg.eu>
+ * (C) 2015 by Alexander Chemeris <Alexander.Chemeris at fairwaves.co>
+ * (C) 2016 by Tom Tsou <tom.tsou at ettus.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#define GSM0503_GPRS_BURSTS_NBITS	(116 * 4)
+#define GSM0503_EGPRS_BURSTS_NBITS	(348 * 4)
+
+struct osmo_conv_code;
+
+enum gsm0503_egprs_mcs {
+	EGPRS_MCS0,
+	EGPRS_MCS1,
+	EGPRS_MCS2,
+	EGPRS_MCS3,
+	EGPRS_MCS4,
+	EGPRS_MCS5,
+	EGPRS_MCS6,
+	EGPRS_MCS7,
+	EGPRS_MCS8,
+	EGPRS_MCS9,
+	EGPRS_NUM_MCS,
+};
+
+int gsm0503_xcch_encode(ubit_t *bursts, uint8_t *l2_data);
+int gsm0503_xcch_decode(uint8_t *l2_data, sbit_t *bursts,
+	int *n_errors, int *n_bits_total);
+
+int gsm0503_pdtch_encode(ubit_t *bursts, uint8_t *l2_data, uint8_t l2_len);
+int gsm0503_pdtch_decode(uint8_t *l2_data, sbit_t *bursts, uint8_t *usf_p,
+	int *n_errors, int *n_bits_total);
+
+int gsm0503_pdtch_egprs_encode(ubit_t *bursts, uint8_t *l2_data,
+	uint8_t l2_len);
+int gsm0503_pdtch_egprs_decode(uint8_t *l2_data, sbit_t *bursts,
+	uint16_t nbits, uint8_t *usf_p, int *n_errors, int *n_bits_total);
+
+int gsm0503_tch_fr_encode(ubit_t *bursts, uint8_t *tch_data, int len,
+	int net_order);
+int gsm0503_tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order,
+	int efr, int *n_errors, int *n_bits_total);
+
+int gsm0503_tch_hr_encode(ubit_t *bursts, uint8_t *tch_data, int len);
+int gsm0503_tch_hr_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
+	int *n_errors, int *n_bits_total);
+
+int gsm0503_tch_afs_encode(ubit_t *bursts, uint8_t *tch_data, int len,
+	int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft,
+	uint8_t cmr);
+int gsm0503_tch_afs_decode(uint8_t *tch_data, sbit_t *bursts,
+	int codec_mode_req, uint8_t *codec, int codecs, uint8_t *ft,
+	uint8_t *cmr, int *n_errors, int *n_bits_total);
+
+int gsm0503_tch_ahs_encode(ubit_t *bursts, uint8_t *tch_data, int len,
+	int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft, uint8_t cmr);
+int gsm0503_tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
+	int codec_mode_req, uint8_t *codec, int codecs, uint8_t *ft, 
+	uint8_t *cmr, int *n_errors, int *n_bits_total);
+
+int gsm0503_rach_encode(ubit_t *burst, uint8_t *ra, uint8_t bsic);
+int gsm0503_rach_decode(uint8_t *ra, sbit_t *burst, uint8_t bsic);
+
+int gsm0503_sch_encode(ubit_t *burst, uint8_t *sb_info);
+int gsm0503_sch_decode(uint8_t *sb_info, sbit_t *burst);
diff --git a/include/osmocom/gsm/gsm0503_interleaving.h b/include/osmocom/gsm/gsm0503_interleaving.h
new file mode 100644
index 0000000..3f477cc
--- /dev/null
+++ b/include/osmocom/gsm/gsm0503_interleaving.h
@@ -0,0 +1,72 @@
+/* 
+ * GSM 05.03 interleaving
+ *
+ * (C) 2013 by Andreas Eversberg <jolly at eversberg.eu>
+ * (C) 2015 by Alexander Chemeris <Alexander.Chemeris at fairwaves.co>
+ * (C) 2016 by Tom Tsou <tom.tsou at ettus.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+void gsm0503_xcch_deinterleave(sbit_t *cB, const sbit_t *iB);
+void gsm0503_xcch_interleave(ubit_t *cB, ubit_t *iB);
+
+void gsm0503_tch_fr_deinterleave(sbit_t *cB, sbit_t *iB);
+void gsm0503_tch_fr_interleave(ubit_t *cB, ubit_t *iB);
+
+void gsm0503_tch_hr_deinterleave(sbit_t *cB, sbit_t *iB);
+void gsm0503_tch_hr_interleave(ubit_t *cB, ubit_t *iB);
+
+void gsm0503_mcs1_ul_interleave(const ubit_t *hc, const ubit_t *dc, ubit_t *iB);
+void gsm0503_mcs1_ul_deinterleave(sbit_t *hc, sbit_t *dc, const sbit_t *iB);
+
+void gsm0503_mcs1_dl_interleave(const ubit_t *up, const ubit_t *hc,
+	const ubit_t *dc, ubit_t *iB);
+void gsm0503_mcs1_dl_deinterleave(sbit_t *u, sbit_t *hc,
+	sbit_t *dc, const sbit_t *iB);
+
+void gsm0503_mcs5_ul_interleave(const ubit_t *hc, const ubit_t *dc,
+	ubit_t *hi, ubit_t *di);
+void gsm0503_mcs5_ul_deinterleave(sbit_t *hc, sbit_t *dc,
+	const sbit_t *hi, const sbit_t *di);
+
+void gsm0503_mcs5_dl_interleave(const ubit_t *hc, const ubit_t *dc,
+	ubit_t *hi, ubit_t *di);
+void gsm0503_mcs5_dl_deinterleave(sbit_t *hc, sbit_t *dc,
+	const sbit_t *hi, const sbit_t *di);
+
+void gsm0503_mcs7_ul_interleave(const ubit_t *hc, const ubit_t *c1,
+	const ubit_t *c2, ubit_t *hi, ubit_t *di);
+void gsm0503_mcs7_ul_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
+	const sbit_t *hi, const sbit_t *di);
+
+void gsm0503_mcs7_dl_interleave(const ubit_t *hc, const ubit_t *c1,
+	const ubit_t *c2, ubit_t *hi, ubit_t *di);
+void gsm0503_mcs7_dl_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
+	const sbit_t *hi, const sbit_t *di);
+
+void gsm0503_mcs8_ul_interleave(const ubit_t *hc, const ubit_t *c1,
+	const ubit_t *c2, ubit_t *hi, ubit_t *di);
+void gsm0503_mcs8_ul_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
+	const sbit_t *hi, const sbit_t *di);
+
+void gsm0503_mcs8_dl_interleave(const ubit_t *hc, const ubit_t *c1,
+	const ubit_t *c2, ubit_t *hi, ubit_t *di);
+void gsm0503_mcs8_dl_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
+	const sbit_t *hi, const sbit_t *di);
diff --git a/include/osmocom/gsm/gsm0503_mapping.h b/include/osmocom/gsm/gsm0503_mapping.h
new file mode 100644
index 0000000..74a7b83
--- /dev/null
+++ b/include/osmocom/gsm/gsm0503_mapping.h
@@ -0,0 +1,55 @@
+/* 
+ * GSM 05.03 mapping
+ *
+ * (C) 2013 by Andreas Eversberg <jolly at eversberg.eu>
+ * (C) 2015 by Alexander Chemeris <Alexander.Chemeris at fairwaves.co>
+ * (C) 2016 by Tom Tsou <tom.tsou at ettus.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+void gsm0503_xcch_burst_unmap(sbit_t *iB, const sbit_t *eB,
+	sbit_t *hl, sbit_t *hn);
+void gsm0503_xcch_burst_map(ubit_t *iB, ubit_t *eB, const ubit_t *hl,
+	const ubit_t *hn);
+
+void gsm0503_tch_burst_unmap(sbit_t *iB, sbit_t *eB, sbit_t *h, int odd);
+void gsm0503_tch_burst_map(ubit_t *iB, ubit_t *eB, const ubit_t *h, int odd);
+
+void gsm0503_mcs5_ul_burst_map(const ubit_t *di, ubit_t *eB,
+	const ubit_t *hi, int B);
+void gsm0503_mcs5_ul_burst_unmap(sbit_t *di, const sbit_t *eB,
+	sbit_t *hi, int B);
+
+void gsm0503_mcs7_ul_burst_map(const ubit_t *di, ubit_t *eB,
+	const ubit_t *hi, int B);
+void gsm0503_mcs7_ul_burst_unmap(sbit_t *di, const sbit_t *eB,
+	sbit_t *hi, int B);
+
+void gsm0503_mcs5_dl_burst_map(const ubit_t *di, ubit_t *eB,
+	const ubit_t *hi, const ubit_t *up, int B);
+void gsm0503_mcs5_dl_burst_unmap(sbit_t *di, const sbit_t *eB,
+	sbit_t *hi, sbit_t *up, int B);
+
+void gsm0503_mcs7_dl_burst_map(const ubit_t *di, ubit_t *eB,
+	const ubit_t *hi, const ubit_t *up, int B);
+void gsm0503_mcs7_dl_burst_unmap(sbit_t *di, const sbit_t *eB,
+	sbit_t *hi, sbit_t *up, int B);
+
+void gsm0503_mcs5_burst_swap(sbit_t *eB);
diff --git a/include/osmocom/gsm/gsm0503_parity.h b/include/osmocom/gsm/gsm0503_parity.h
new file mode 100644
index 0000000..fa8bacc
--- /dev/null
+++ b/include/osmocom/gsm/gsm0503_parity.h
@@ -0,0 +1,35 @@
+/* 
+ * GSM 05.03 parity
+ *
+ * (C) 2013 by Andreas Eversberg <jolly at eversberg.eu>
+ * (C) 2015 by Alexander Chemeris <Alexander.Chemeris at fairwaves.co>
+ * (C) 2016 by Tom Tsou <tom.tsou at ettus.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+const struct osmo_crc64gen_code gsm0503_fire_crc40;
+const struct osmo_crc16gen_code gsm0503_cs234_crc16;
+const struct osmo_crc8gen_code gsm0503_mcs_crc8_hdr;
+const struct osmo_crc16gen_code gsm0503_mcs_crc12;
+const struct osmo_crc8gen_code gsm0503_rach_crc6;
+const struct osmo_crc16gen_code gsm0503_sch_crc10;
+const struct osmo_crc8gen_code gsm0503_tch_fr_crc3;
+const struct osmo_crc8gen_code gsm0503_tch_efr_crc8;
+const struct osmo_crc8gen_code gsm0503_amr_crc6;
diff --git a/include/osmocom/gsm/gsm0503_tables.h b/include/osmocom/gsm/gsm0503_tables.h
new file mode 100644
index 0000000..dbabfb7
--- /dev/null
+++ b/include/osmocom/gsm/gsm0503_tables.h
@@ -0,0 +1,71 @@
+/* 
+ * GSM 05.03 tables
+ *
+ * (C) 2013 by Andreas Eversberg <jolly at eversberg.eu>
+ * (C) 2015 by Alexander Chemeris <Alexander.Chemeris at fairwaves.co>
+ * (C) 2016 by Tom Tsou <tom.tsou at ettus.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+extern const ubit_t gsm0503_pdtch_hl_hn_ubit[4][8];
+extern const ubit_t gsm0503_pdtch_edge_hl_hn_ubit[3][8];
+extern const sbit_t gsm0503_pdtch_hl_hn_sbit[4][8];
+extern const sbit_t gsm0503_pdtch_edge_hl_hn_sbit[3][8];
+extern const ubit_t gsm0503_usf2six[8][6];
+extern const ubit_t gsm0503_usf2twelve_ubit[8][12];
+extern const sbit_t gsm0503_usf2twelve_sbit[8][12];
+extern const uint8_t gsm0503_puncture_cs2[588];
+extern const uint8_t gsm0503_puncture_cs3[676];
+extern const uint8_t gsm0503_puncture_mcs1_dl_hdr[108];
+extern const uint8_t gsm0503_puncture_mcs1_ul_hdr[117];
+extern const uint8_t gsm0503_puncture_mcs1_p1[588];
+extern const uint8_t gsm0503_puncture_mcs1_p2[588];
+extern const uint8_t gsm0503_puncture_mcs2_p1[732];
+extern const uint8_t gsm0503_puncture_mcs2_p2[732];
+extern const uint8_t gsm0503_puncture_mcs3_p1[948];
+extern const uint8_t gsm0503_puncture_mcs3_p2[948];
+extern const uint8_t gsm0503_puncture_mcs3_p3[948];
+extern const uint8_t gsm0503_puncture_mcs4_p1[1116];
+extern const uint8_t gsm0503_puncture_mcs4_p2[1116];
+extern const uint8_t gsm0503_puncture_mcs4_p3[1116];
+extern const uint8_t gsm0503_puncture_mcs5_p1[1404];
+extern const uint8_t gsm0503_puncture_mcs5_p2[1404];
+extern const uint8_t gsm0503_puncture_mcs6_p1[1836];
+extern const uint8_t gsm0503_puncture_mcs6_p2[1836];
+extern const uint8_t gsm0503_puncture_mcs7_dl_hdr[135];
+extern const uint8_t gsm0503_puncture_mcs7_ul_hdr[162];
+extern const uint8_t gsm0503_puncture_mcs7_p1[1404];
+extern const uint8_t gsm0503_puncture_mcs7_p2[1404];
+extern const uint8_t gsm0503_puncture_mcs7_p3[1404];
+extern const uint8_t gsm0503_puncture_mcs8_p1[1692];
+extern const uint8_t gsm0503_puncture_mcs8_p2[1692];
+extern const uint8_t gsm0503_puncture_mcs8_p3[1692];
+extern const uint8_t gsm0503_puncture_mcs9_p1[1836];
+extern const uint8_t gsm0503_puncture_mcs9_p2[1836];
+extern const uint8_t gsm0503_puncture_mcs9_p3[1836];
+extern const uint16_t gsm0503_interleave_mcs5[1248];
+extern const uint8_t gsm0503_gsm_fr_map[76];
+extern const uint8_t gsm0503_gsm_efr_protected_bits[65];
+extern const ubit_t gsm0503_afs_ic_ubit[4][8];
+extern const sbit_t gsm0503_afs_ic_sbit[4][8];
+extern const ubit_t gsm0503_ahs_ic_ubit[4][4];
+extern const sbit_t gsm0503_ahs_ic_sbit[4][4];
+extern const uint8_t gsm0503_tch_hr_interleaving[228][2];
+extern const ubit_t gsm0503_mcs5_usf_precode_table[8][36];
diff --git a/src/gsm/Makefile.am b/src/gsm/Makefile.am
index a2f2524..4d86566 100644
--- a/src/gsm/Makefile.am
+++ b/src/gsm/Makefile.am
@@ -18,16 +18,16 @@
 			gprs_cipher_core.c gprs_rlc.c gsm0480.c abis_nm.c gsm0502.c \
 			gsm0411_utils.c gsm0411_smc.c gsm0411_smr.c \
 			lapd_core.c lapdm.c kasumi.c gsm_04_08_gprs.c \
-			conv_cs2_gen.c conv_cs3_gen.c conv_xcch_gen.c \
-			conv_tch_afs_12_2_gen.c conv_tch_afs_10_2_gen.c \
-			conv_tch_afs_7_95_gen.c conv_tch_afs_7_4_gen.c \
-			conv_tch_afs_6_7_gen.c conv_tch_afs_5_9_gen.c \
-			conv_tch_afs_5_15_gen.c conv_tch_afs_4_75_gen.c \
+			gsm610.c gsm620.c gsm660.c gsm0503_conv.c \
+			gsm0503_conv_edge.c gsm0503_tables.c \
+			gsm0503_parity.c gsm0503_interleaving.c \
+			gsm0503_mapping.c gsm0503_coding.c \
 			auth_core.c auth_comp128v1.c auth_comp128v23.c \
 			auth_milenage.c milenage/aes-encblock.c gea.c \
 			milenage/aes-internal.c milenage/aes-internal-enc.c \
 			milenage/milenage.c gan.c ipa.c gsm0341.c apn.c \
 			gsup.c gprs_gea.c
+
 libgsmint_la_LDFLAGS = -no-undefined
 libgsmint_la_LIBADD = ../libosmocore.la
 
@@ -37,5 +37,18 @@
 
 EXTRA_DIST = libosmogsm.map
 
-conv%gen.c: ../../utils/conv_gen.py
+# Convolutional codes generation
+gsm0503_conv.c: ../../utils/conv_gen.py
 	$(AM_V_GEN)python2 ../../utils/conv_gen.py
+
+# Some dependencies from libosmocodec
+gsm610.c:
+	$(AM_V_GEN)cp ../codec/gsm610.c ./
+
+gsm620.c:
+	$(AM_V_GEN)cp ../codec/gsm620.c ./
+
+gsm660.c:
+	$(AM_V_GEN)cp ../codec/gsm660.c ./
+
+CLEANFILES = gsm0503_conv.c gsm610.c gsm620.c gsm660.c
diff --git a/src/gsm/gsm0503_coding.c b/src/gsm/gsm0503_coding.c
new file mode 100644
index 0000000..49cbee7
--- /dev/null
+++ b/src/gsm/gsm0503_coding.c
@@ -0,0 +1,2694 @@
+/* 
+ * (C) 2013 by Andreas Eversberg <jolly at eversberg.eu>
+ * (C) 2015 by Alexander Chemeris <Alexander.Chemeris at fairwaves.co>
+ * (C) 2016 by Tom Tsou <tom.tsou at ettus.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/bits.h>
+#include <osmocom/core/conv.h>
+#include <osmocom/core/crcgen.h>
+#include <osmocom/core/endian.h>
+
+#include <osmocom/gprs/gprs_rlc.h>
+#include <osmocom/gprs/protocol/gsm_04_60.h>
+
+#include <osmocom/codec/codec.h>
+
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/gsm0503_interleaving.h>
+#include <osmocom/gsm/gsm0503_mapping.h>
+#include <osmocom/gsm/gsm0503_tables.h>
+#include <osmocom/gsm/gsm0503_coding.h>
+#include <osmocom/gsm/gsm0503_parity.h>
+#include <osmocom/gsm/gsm0503.h>
+
+/*
+ * EGPRS coding limits
+ */
+
+/* Max header size with parity bits */
+#define EGPRS_HDR_UPP_MAX	54
+
+/* Max encoded header size */
+#define EGPRS_HDR_C_MAX		162
+
+/* Max punctured header size */
+#define EGPRS_HDR_HC_MAX	160
+
+/* Max data block size with parity bits */
+#define EGPRS_DATA_U_MAX	612
+
+/* Max encoded data block size */
+#define EGPRS_DATA_C_MAX	1836
+
+/* Max single block punctured data size */
+#define EGPRS_DATA_DC_MAX	1248
+
+/* Dual block punctured data size */
+#define EGPRS_DATA_C1		612
+#define EGPRS_DATA_C2		EGPRS_DATA_C1
+
+/* TS 101318 Chapter 5.1: 260 bits + 4bit sig */
+#define GSM_FR_BYTES	33
+/* TS 101318 Chapter 5.2: 112 bits, no sig */
+#define GSM_HR_BYTES	14
+/* TS 101318 Chapter 5.3: 244 bits + 4bit sig */
+#define GSM_EFR_BYTES	31
+
+struct gsm0503_mcs_code {
+	uint8_t mcs;
+	uint8_t usf_len;
+
+	/* Header coding */
+	uint8_t hdr_len;
+	uint8_t hdr_code_len;
+	uint8_t hdr_punc_len;
+	const struct osmo_conv_code *hdr_conv;
+	const uint8_t *hdr_punc;
+
+	/* Data coding */
+	uint16_t data_len;
+	uint16_t data_code_len;
+	uint16_t data_punc_len;
+	const struct osmo_conv_code *data_conv;
+	const uint8_t *data_punc[3];
+};
+
+/*
+ * EGPRS UL coding parameters
+ */
+struct gsm0503_mcs_code gsm0503_mcs_ul_codes[EGPRS_NUM_MCS] = {
+	{
+		.mcs = EGPRS_MCS0,
+	},
+	{
+		.mcs = EGPRS_MCS1,
+		.hdr_len = 31,
+		.hdr_code_len = 117,
+		.hdr_punc_len = 80,
+		.hdr_conv = &gsm0503_mcs1_ul_hdr,
+		.hdr_punc = gsm0503_puncture_mcs1_ul_hdr,
+
+		.data_len = 178,
+		.data_code_len = 588,
+		.data_punc_len = 372,
+		.data_conv = &gsm0503_mcs1,
+		.data_punc = {
+			gsm0503_puncture_mcs1_p1,
+			gsm0503_puncture_mcs1_p2,
+			NULL,
+		},
+	},
+	{
+		.mcs = EGPRS_MCS2,
+		.hdr_len = 31,
+		.hdr_code_len = 117,
+		.hdr_punc_len = 80,
+		.hdr_conv = &gsm0503_mcs1_ul_hdr,
+		.hdr_punc = gsm0503_puncture_mcs1_ul_hdr,
+
+		.data_len = 226,
+		.data_code_len = 732,
+		.data_punc_len = 372,
+		.data_conv = &gsm0503_mcs2,
+		.data_punc = {
+			gsm0503_puncture_mcs2_p1,
+			gsm0503_puncture_mcs2_p2,
+			NULL,
+		},
+	},
+	{
+		.mcs = EGPRS_MCS3,
+		.hdr_len = 31,
+		.hdr_code_len = 117,
+		.hdr_punc_len = 80,
+		.hdr_conv = &gsm0503_mcs1_ul_hdr,
+		.hdr_punc = gsm0503_puncture_mcs1_ul_hdr,
+
+		.data_len = 298,
+		.data_code_len = 948,
+		.data_punc_len = 372,
+		.data_conv = &gsm0503_mcs3,
+		.data_punc = {
+			gsm0503_puncture_mcs3_p1,
+			gsm0503_puncture_mcs3_p2,
+			gsm0503_puncture_mcs3_p3,
+		},
+	},
+	{
+		.mcs = EGPRS_MCS4,
+		.hdr_len = 31,
+		.hdr_code_len = 117,
+		.hdr_punc_len = 80,
+		.hdr_conv = &gsm0503_mcs1_ul_hdr,
+		.hdr_punc = gsm0503_puncture_mcs1_ul_hdr,
+
+		.data_len = 354,
+		.data_code_len = 1116,
+		.data_punc_len = 372,
+		.data_conv = &gsm0503_mcs4,
+		.data_punc = {
+			gsm0503_puncture_mcs4_p1,
+			gsm0503_puncture_mcs4_p2,
+			gsm0503_puncture_mcs4_p3,
+		},
+	},
+	{
+		.mcs = EGPRS_MCS5,
+		.hdr_len = 37,
+		.hdr_code_len = 135,
+		.hdr_punc_len = 136,
+		.hdr_conv = &gsm0503_mcs5_ul_hdr,
+		.hdr_punc = NULL,
+
+		.data_len = 450,
+		.data_code_len = 1404,
+		.data_punc_len = 1248,
+		.data_conv = &gsm0503_mcs5,
+		.data_punc = {
+			gsm0503_puncture_mcs5_p1,
+			gsm0503_puncture_mcs5_p2,
+			NULL,
+		},
+	},
+	{
+		.mcs = EGPRS_MCS6,
+		.hdr_len = 37,
+		.hdr_code_len = 135,
+		.hdr_punc_len = 136,
+		.hdr_conv = &gsm0503_mcs5_ul_hdr,
+		.hdr_punc = NULL,
+
+		.data_len = 594,
+		.data_code_len = 1836,
+		.data_punc_len = 1248,
+		.data_conv = &gsm0503_mcs6,
+		.data_punc = {
+			gsm0503_puncture_mcs6_p1,
+			gsm0503_puncture_mcs6_p2,
+			NULL,
+		},
+	},
+	{
+		.mcs = EGPRS_MCS7,
+		.hdr_len = 46,
+		.hdr_code_len = 162,
+		.hdr_punc_len = 160,
+		.hdr_conv = &gsm0503_mcs7_ul_hdr,
+		.hdr_punc = gsm0503_puncture_mcs7_ul_hdr,
+		.hdr_len = 46,
+
+		.data_len = 900,
+		.data_code_len = 1404,
+		.data_punc_len = 612,
+		.data_conv = &gsm0503_mcs7,
+		.data_punc = {
+			gsm0503_puncture_mcs7_p1,
+			gsm0503_puncture_mcs7_p2,
+			gsm0503_puncture_mcs7_p3,
+		}
+	},
+	{
+		.mcs = EGPRS_MCS8,
+		.hdr_len = 46,
+		.hdr_code_len = 162,
+		.hdr_punc_len = 160,
+		.hdr_conv = &gsm0503_mcs7_ul_hdr,
+		.hdr_punc = gsm0503_puncture_mcs7_ul_hdr,
+		.hdr_len = 46,
+
+		.data_len = 1092,
+		.data_code_len = 1692,
+		.data_punc_len = 612,
+		.data_conv = &gsm0503_mcs8,
+		.data_punc = {
+			gsm0503_puncture_mcs8_p1,
+			gsm0503_puncture_mcs8_p2,
+			gsm0503_puncture_mcs8_p3,
+		}
+	},
+	{
+		.mcs = EGPRS_MCS9,
+		.hdr_len = 46,
+		.hdr_code_len = 162,
+		.hdr_punc_len = 160,
+		.hdr_conv = &gsm0503_mcs7_ul_hdr,
+		.hdr_punc = gsm0503_puncture_mcs7_ul_hdr,
+		.hdr_len = 46,
+
+		.data_len = 1188,
+		.data_code_len = 1836,
+		.data_punc_len = 612,
+		.data_conv = &gsm0503_mcs9,
+		.data_punc = {
+			gsm0503_puncture_mcs9_p1,
+			gsm0503_puncture_mcs9_p2,
+			gsm0503_puncture_mcs9_p3,
+		}
+	},
+};
+
+/*
+ * EGPRS DL coding parameters
+ */
+struct gsm0503_mcs_code gsm0503_mcs_dl_codes[EGPRS_NUM_MCS] = {
+	{
+		.mcs = EGPRS_MCS0,
+	},
+	{
+		.mcs = EGPRS_MCS1,
+		.usf_len = 3,
+		.hdr_len = 28,
+		.hdr_code_len = 108,
+		.hdr_punc_len = 68,
+		.hdr_conv = &gsm0503_mcs1_dl_hdr,
+		.hdr_punc = gsm0503_puncture_mcs1_dl_hdr,
+
+		.data_len = 178,
+		.data_code_len = 588,
+		.data_punc_len = 372,
+		.data_conv = &gsm0503_mcs1,
+		.data_punc = {
+			gsm0503_puncture_mcs1_p1,
+			gsm0503_puncture_mcs1_p2,
+			NULL,
+		},
+	},
+	{
+		.mcs = EGPRS_MCS2,
+		.usf_len = 3,
+		.hdr_len = 28,
+		.hdr_code_len = 108,
+		.hdr_punc_len = 68,
+		.hdr_conv = &gsm0503_mcs1_dl_hdr,
+		.hdr_punc = gsm0503_puncture_mcs1_dl_hdr,
+
+		.data_len = 226,
+		.data_code_len = 732,
+		.data_punc_len = 372,
+		.data_conv = &gsm0503_mcs2,
+		.data_punc = {
+			gsm0503_puncture_mcs2_p1,
+			gsm0503_puncture_mcs2_p2,
+			NULL,
+		},
+	},
+	{
+		.mcs = EGPRS_MCS3,
+		.usf_len = 3,
+		.hdr_len = 28,
+		.hdr_code_len = 108,
+		.hdr_punc_len = 68,
+		.hdr_conv = &gsm0503_mcs1_dl_hdr,
+		.hdr_punc = gsm0503_puncture_mcs1_dl_hdr,
+
+		.data_len = 298,
+		.data_code_len = 948,
+		.data_punc_len = 372,
+		.data_conv = &gsm0503_mcs3,
+		.data_punc = {
+			gsm0503_puncture_mcs3_p1,
+			gsm0503_puncture_mcs3_p2,
+			gsm0503_puncture_mcs3_p3,
+		},
+	},
+	{
+		.mcs = EGPRS_MCS4,
+		.usf_len = 3,
+		.hdr_len = 28,
+		.hdr_code_len = 108,
+		.hdr_punc_len = 68,
+		.hdr_conv = &gsm0503_mcs1_dl_hdr,
+		.hdr_punc = gsm0503_puncture_mcs1_dl_hdr,
+
+		.data_len = 354,
+		.data_code_len = 1116,
+		.data_punc_len = 372,
+		.data_conv = &gsm0503_mcs4,
+		.data_punc = {
+			gsm0503_puncture_mcs4_p1,
+			gsm0503_puncture_mcs4_p2,
+			gsm0503_puncture_mcs4_p3,
+		},
+	},
+	{
+		.mcs = EGPRS_MCS5,
+		.usf_len = 3,
+		.hdr_len = 25,
+		.hdr_code_len = 99,
+		.hdr_punc_len = 100,
+		.hdr_conv = &gsm0503_mcs5_dl_hdr,
+		.hdr_punc = NULL,
+
+		.data_len = 450,
+		.data_code_len = 1404,
+		.data_punc_len = 1248,
+		.data_conv = &gsm0503_mcs5,
+		.data_punc = {
+			gsm0503_puncture_mcs5_p1,
+			gsm0503_puncture_mcs5_p2,
+			NULL,
+		},
+	},
+	{
+		.mcs = EGPRS_MCS6,
+		.usf_len = 3,
+		.hdr_len = 25,
+		.hdr_code_len = 99,
+		.hdr_punc_len = 100,
+		.hdr_conv = &gsm0503_mcs5_dl_hdr,
+		.hdr_punc = NULL,
+
+		.data_len = 594,
+		.data_code_len = 1836,
+		.data_punc_len = 1248,
+		.data_conv = &gsm0503_mcs6,
+		.data_punc = {
+			gsm0503_puncture_mcs6_p1,
+			gsm0503_puncture_mcs6_p2,
+			NULL,
+		},
+	},
+	{
+		.mcs = EGPRS_MCS7,
+		.usf_len = 3,
+		.hdr_len = 37,
+		.hdr_code_len = 135,
+		.hdr_punc_len = 124,
+		.hdr_conv = &gsm0503_mcs7_dl_hdr,
+		.hdr_punc = gsm0503_puncture_mcs7_dl_hdr,
+
+		.data_len = 900,
+		.data_code_len = 1404,
+		.data_punc_len = 612,
+		.data_conv = &gsm0503_mcs7,
+		.data_punc = {
+			gsm0503_puncture_mcs7_p1,
+			gsm0503_puncture_mcs7_p2,
+			gsm0503_puncture_mcs7_p3,
+		}
+	},
+	{
+		.mcs = EGPRS_MCS8,
+		.usf_len = 3,
+		.hdr_len = 37,
+		.hdr_code_len = 135,
+		.hdr_punc_len = 124,
+		.hdr_conv = &gsm0503_mcs7_dl_hdr,
+		.hdr_punc = gsm0503_puncture_mcs7_dl_hdr,
+
+		.data_len = 1092,
+		.data_code_len = 1692,
+		.data_punc_len = 612,
+		.data_conv = &gsm0503_mcs8,
+		.data_punc = {
+			gsm0503_puncture_mcs8_p1,
+			gsm0503_puncture_mcs8_p2,
+			gsm0503_puncture_mcs8_p3,
+		}
+	},
+	{
+		.mcs = EGPRS_MCS9,
+		.usf_len = 3,
+		.hdr_len = 37,
+		.hdr_code_len = 135,
+		.hdr_punc_len = 124,
+		.hdr_conv = &gsm0503_mcs7_dl_hdr,
+		.hdr_punc = gsm0503_puncture_mcs7_dl_hdr,
+
+		.data_len = 1188,
+		.data_code_len = 1836,
+		.data_punc_len = 612,
+		.data_conv = &gsm0503_mcs9,
+		.data_punc = {
+			gsm0503_puncture_mcs9_p1,
+			gsm0503_puncture_mcs9_p2,
+			gsm0503_puncture_mcs9_p3,
+		}
+	},
+};
+
+static int osmo_conv_decode_ber(const struct osmo_conv_code *code,
+	const sbit_t *input, ubit_t *output,
+	int *n_errors, int *n_bits_total)
+{
+	int res, i, coded_len;
+	ubit_t recoded[EGPRS_DATA_C_MAX];
+
+	res = osmo_conv_decode(code, input, output);
+
+	if (n_bits_total || n_errors) {
+		coded_len = osmo_conv_encode(code, output, recoded);
+		OSMO_ASSERT(sizeof(recoded) / sizeof(recoded[0]) >= coded_len);
+	}
+
+	/* Count bit errors */
+	if (n_errors) {
+		*n_errors = 0;
+		for (i = 0; i < coded_len; i++) {
+			if (! ((recoded[i] && input[i] < 0) ||
+			       (!recoded[i] && input[i] > 0)) )
+				*n_errors += 1;
+		}
+	}
+
+	if (n_bits_total)
+		*n_bits_total = coded_len;
+
+	return res;
+}
+
+
+static int _xcch_decode_cB(uint8_t *l2_data, sbit_t *cB,
+	int *n_errors, int *n_bits_total)
+{
+	ubit_t conv[224];
+	int rv;
+
+	osmo_conv_decode_ber(&gsm0503_xcch, cB,
+		conv, n_errors, n_bits_total);
+
+	rv = osmo_crc64gen_check_bits(&gsm0503_fire_crc40,
+		conv, 184, conv + 184);
+	if (rv)
+		return -1;
+
+	osmo_ubit2pbit_ext(l2_data, 0, conv, 0, 184, 1);
+
+	return 0;
+}
+
+static int _xcch_encode_cB(ubit_t *cB, uint8_t *l2_data)
+{
+	ubit_t conv[224];
+
+	osmo_pbit2ubit_ext(conv, 0, l2_data, 0, 184, 1);
+
+	osmo_crc64gen_set_bits(&gsm0503_fire_crc40, conv, 184, conv + 184);
+
+	osmo_conv_encode(&gsm0503_xcch, conv, cB);
+
+	return 0;
+}
+
+
+/*
+ * GSM xCCH block transcoding
+ */
+
+int gsm0503_xcch_decode(uint8_t *l2_data, sbit_t *bursts,
+	int *n_errors, int *n_bits_total)
+{
+	sbit_t iB[456], cB[456];
+	int i;
+
+	for (i = 0; i < 4; i++)
+		gsm0503_xcch_burst_unmap(&iB[i * 114], &bursts[i * 116], NULL, NULL);
+
+	gsm0503_xcch_deinterleave(cB, iB);
+
+	return _xcch_decode_cB(l2_data, cB, n_errors, n_bits_total);
+}
+
+int gsm0503_xcch_encode(ubit_t *bursts, uint8_t *l2_data)
+{
+	ubit_t iB[456], cB[456], hl = 1, hn = 1;
+	int i;
+
+	_xcch_encode_cB(cB, l2_data);
+
+	gsm0503_xcch_interleave(cB, iB);
+
+	for (i = 0; i < 4; i++)
+		gsm0503_xcch_burst_map(&iB[i * 114], &bursts[i * 116], &hl, &hn);
+
+	return 0;
+}
+
+/*
+ * EGPRS PDTCH UL block decoding
+ */
+
+/*
+ * Type 3 - MCS-1,2,3,4
+ * Unmapping and deinterleaving
+ */
+static int egprs_type3_unmap(const sbit_t *bursts, sbit_t *hc, sbit_t *dc)
+{
+	int i;
+	sbit_t iB[456], q[8];
+
+	for (i = 0; i < 4; i++) {
+		gsm0503_xcch_burst_unmap(&iB[i * 114], &bursts[i * 116],
+			q + i * 2, q + i * 2 + 1);
+	}
+
+	gsm0503_mcs1_ul_deinterleave(hc, dc, iB);
+
+	return 0;
+}
+
+/*
+ * Type 2 - MCS-5,6
+ * Unmapping and deinterleaving
+ */
+static int egprs_type2_unmap(const sbit_t *bursts, sbit_t *hc, sbit_t *dc)
+{
+	int i;
+	sbit_t burst[348];
+	sbit_t hi[EGPRS_HDR_HC_MAX];
+	sbit_t di[EGPRS_DATA_DC_MAX];
+
+	for (i=0; i<4; i++) {
+		memcpy(burst, &bursts[i * 348], 348);
+
+		gsm0503_mcs5_burst_swap(burst);
+		gsm0503_mcs5_ul_burst_unmap(di, burst, hi, i);
+	}
+
+	gsm0503_mcs5_ul_deinterleave(hc, dc, hi, di);
+
+	return 0;
+}
+
+/*
+ * Type 1 - MCS-7,8,9
+ * Unmapping and deinterleaving - Note that MCS-7 interleaver is unique
+ */
+static int egprs_type1_unmap(const sbit_t *bursts, sbit_t *hc,
+			     sbit_t *c1, sbit_t *c2, int msc)
+{
+	int i;
+	sbit_t burst[348];
+	sbit_t hi[EGPRS_HDR_HC_MAX];
+	sbit_t di[EGPRS_DATA_C1 * 2];
+
+	for (i = 0; i < 4; i++) {
+		memcpy(burst, &bursts[i * 348], 348);
+
+		gsm0503_mcs5_burst_swap(burst);
+		gsm0503_mcs7_ul_burst_unmap(di, burst, hi, i);
+	}
+
+	if (msc == EGPRS_MCS7)
+		gsm0503_mcs7_ul_deinterleave(hc, c1, c2, hi, di);
+	else
+		gsm0503_mcs8_ul_deinterleave(hc, c1, c2, hi, di);
+
+	return 0;
+}
+
+union gprs_rlc_ul_hdr_egprs {
+        struct gprs_rlc_ul_header_egprs_1 type1;
+        struct gprs_rlc_ul_header_egprs_2 type2;
+        struct gprs_rlc_ul_header_egprs_3 type3;
+};
+
+/*
+ * Decode EGPRS UL header section
+ *
+ * 1. Depuncture
+ * 2. Convolutional decoding
+ * 3. CRC check
+ */
+static int _egprs_decode_hdr(const sbit_t *hc, int mcs,
+			     union gprs_rlc_ul_hdr_egprs *hdr)
+{
+	sbit_t C[EGPRS_HDR_C_MAX];
+	ubit_t upp[EGPRS_HDR_UPP_MAX];
+	int i, j, rc;
+	struct gsm0503_mcs_code *code;
+
+	code = &gsm0503_mcs_ul_codes[mcs];
+
+	/* Skip depuncturing on MCS-5,6 header */
+	if ((mcs == EGPRS_MCS5) || (mcs == EGPRS_MCS6)) {
+		memcpy(C, hc, code->hdr_code_len);
+		goto hdr_conv_decode;
+	}
+
+	if (!code->hdr_punc) {
+		/* Invalid MCS-X header puncture matrix */
+		return -1;
+	}
+
+	i = code->hdr_code_len - 1;
+	j = code->hdr_punc_len - 1;
+
+	for (; i >= 0; i--) {
+		if (!code->hdr_punc[i])
+			C[i] = hc[j--];
+		else
+			C[i] = 0;
+	}
+
+hdr_conv_decode:
+	osmo_conv_decode_ber(code->hdr_conv, C, upp, NULL, NULL);
+	rc = osmo_crc8gen_check_bits(&gsm0503_mcs_crc8_hdr, upp,
+				     code->hdr_len, upp + code->hdr_len);
+	if (rc)
+		return -1;
+
+	osmo_ubit2pbit_ext((pbit_t *) hdr, 0, upp, 0, code->hdr_len, 1);
+
+	return 0;
+}
+
+/*
+ * Blind MCS header decoding based on burst length and CRC validation.
+ * Ignore 'q' value coding indentification. This approach provides
+ * the strongest chance of header recovery.
+ */
+static int egprs_decode_hdr(union gprs_rlc_ul_hdr_egprs *hdr,
+			    const sbit_t *bursts, uint16_t nbits)
+{
+	int rc;
+	sbit_t hc[EGPRS_HDR_HC_MAX];
+
+	if (nbits == GSM0503_GPRS_BURSTS_NBITS) {
+		/* MCS-1,2,3,4 */
+		egprs_type3_unmap(bursts, hc, NULL);
+		rc = _egprs_decode_hdr(hc, EGPRS_MCS1, hdr);
+		if (!rc)
+			return EGPRS_HDR_TYPE3;
+	} else if (nbits == GSM0503_EGPRS_BURSTS_NBITS) {
+		/* MCS-5,6 */
+		egprs_type2_unmap(bursts, hc, NULL);
+		rc = _egprs_decode_hdr(hc, EGPRS_MCS5, hdr);
+		if (!rc)
+			return EGPRS_HDR_TYPE2;
+
+		/* MCS-7,8,9 */
+		egprs_type1_unmap(bursts, hc, NULL, NULL, EGPRS_MCS7);
+		rc = _egprs_decode_hdr(hc, EGPRS_MCS7, hdr);
+		if (!rc)
+			return EGPRS_HDR_TYPE1;
+	}
+
+	return -1;
+}
+
+/*
+ * Parse EGPRS UL header for coding and puncturing scheme (CPS)
+ *
+ * Type 1 - MCS-7,8,9
+ * Type 2 - MCS-5,6
+ * Type 3 - MCS-1,2,3,4
+ */
+static int egprs_parse_ul_cps(struct egprs_cps *cps,
+			      union gprs_rlc_ul_hdr_egprs *hdr, int type)
+{
+	uint8_t bits;
+
+	switch (type) {
+	case EGPRS_HDR_TYPE1:
+		bits = hdr->type1.cps;
+		break;
+	case EGPRS_HDR_TYPE2:
+		bits = (hdr->type2.cps_lo << 2) | hdr->type2.cps_hi;
+		break;
+	case EGPRS_HDR_TYPE3:
+		bits = (hdr->type3.cps_lo << 2) | hdr->type3.cps_hi;
+		break;
+	default:
+		return -1;
+	}
+
+	return egprs_get_cps(cps, type, bits);
+}
+
+#define NUM_BYTES(N) ((N + 8 - 1) / 8)
+
+/*
+ * Decode EGPRS UL data section
+ *
+ * 1. Depuncture
+ * 2. Convolutional decoding
+ * 3. CRC check
+ * 4. Block combining (MCS-7,8,9 only)
+ */
+static int egprs_decode_data(uint8_t *l2_data, sbit_t *c,
+			     int mcs, int p, int blk,
+			     int *n_errors, int *n_bits_total)
+{
+	ubit_t u[EGPRS_DATA_U_MAX];
+	sbit_t C[EGPRS_DATA_C_MAX];
+
+	int i, j, rc, data_len;
+	struct gsm0503_mcs_code *code;
+
+	if (blk && mcs < EGPRS_MCS7) {
+		/* Invalid MCS-X block state */
+		return -1;
+	}
+
+	code = &gsm0503_mcs_ul_codes[mcs];
+	if (!code->data_punc[p]) {
+		/* Invalid MCS-X data puncture matrix */
+		return -1;
+	}
+
+	/*
+	 * MCS-1,6 - single block processing
+	 * MCS-7,9 - dual block processing
+	 */
+	if (mcs >= EGPRS_MCS7)
+		data_len = code->data_len / 2;
+	else
+		data_len = code->data_len;
+
+	i = code->data_code_len - 1;
+	j = code->data_punc_len - 1;
+
+	for (; i >= 0; i--) {
+		if (!code->data_punc[p][i])
+			C[i] = c[j--];
+		else
+			C[i] = 0;
+	}
+
+	osmo_conv_decode_ber(code->data_conv, C, u, n_errors, n_bits_total);
+	rc = osmo_crc16gen_check_bits(&gsm0503_mcs_crc12, u,
+		data_len, u + data_len);
+	if (rc)
+		return -1;
+
+	/* Offsets output pointer on the second block of Type 1 MCS */
+	osmo_ubit2pbit_ext(l2_data, code->hdr_len + blk * data_len,
+		u, 0, data_len, 1);
+
+	/* Return the number of bytes required for the bit message */
+	return NUM_BYTES(code->hdr_len + code->data_len);
+}
+
+/*
+ * Decode EGPRS UL message
+ *
+ * 1. Header section decoding
+ * 2. Extract CPS settings
+ * 3. Burst unmapping and deinterleaving
+ * 4. Data section decoding
+ */
+int gsm0503_pdtch_egprs_decode(uint8_t *l2_data, sbit_t *bursts, uint16_t nbits,
+		      uint8_t *usf_p, int *n_errors, int *n_bits_total)
+{
+	sbit_t dc[EGPRS_DATA_DC_MAX];
+	sbit_t c1[EGPRS_DATA_C1], c2[EGPRS_DATA_C2];
+	int type, rc;
+	struct egprs_cps cps;
+	union gprs_rlc_ul_hdr_egprs *hdr;
+
+	if ((nbits != GSM0503_GPRS_BURSTS_NBITS) &&
+	    (nbits != GSM0503_EGPRS_BURSTS_NBITS)) {
+		/* Invalid EGPRS bit length */
+		return -1;
+	}
+
+	hdr = (union gprs_rlc_ul_hdr_egprs *) l2_data;
+	type = egprs_decode_hdr(hdr, bursts, nbits);
+	if (egprs_parse_ul_cps(&cps, hdr, type) < 0)
+		return -1;
+
+	switch (cps.mcs) {
+	case EGPRS_MCS1:
+	case EGPRS_MCS2:
+	case EGPRS_MCS3:
+	case EGPRS_MCS4:
+		egprs_type3_unmap(bursts, NULL, dc);
+		break;
+	case EGPRS_MCS5:
+	case EGPRS_MCS6:
+		egprs_type2_unmap(bursts, NULL, dc);
+		break;
+	case EGPRS_MCS7:
+	case EGPRS_MCS8:
+	case EGPRS_MCS9:
+		egprs_type1_unmap(bursts, NULL, c1, c2, cps.mcs);
+		break;
+	default:
+		/* Invalid MCS-X */
+		return -1;
+	}
+
+	/* Decode MCS-X block, where X = cps.mcs */
+	if (cps.mcs < EGPRS_MCS7) {
+		rc = egprs_decode_data(l2_data, dc, cps.mcs, cps.p[0],
+			0, n_errors, n_bits_total);
+		if (rc < 0)
+			return -1;
+	} else {
+		/* MCS-7,8,9 block 1 */
+		rc = egprs_decode_data(l2_data, c1, cps.mcs, cps.p[0],
+			0, n_errors, n_bits_total);
+		if (rc < 0)
+			return -1;
+
+		/* MCS-7,8,9 block 2 */
+		rc = egprs_decode_data(l2_data, c2, cps.mcs, cps.p[1],
+			1, n_errors, n_bits_total);
+		if (rc < 0)
+			return -1;
+	}
+
+	return rc;
+}
+
+/*
+ * GSM PDTCH block transcoding
+ */
+
+int gsm0503_pdtch_decode(uint8_t *l2_data, sbit_t *bursts, uint8_t *usf_p,
+	int *n_errors, int *n_bits_total)
+{
+	sbit_t iB[456], cB[676], hl_hn[8];
+	ubit_t conv[456];
+	int i, j, k, rv, best = 0, cs = 0, usf = 0; /* make GCC happy */
+
+	for (i = 0; i < 4; i++)
+		gsm0503_xcch_burst_unmap(&iB[i * 114], &bursts[i * 116],
+			hl_hn + i * 2, hl_hn + i * 2 + 1);
+
+	for (i = 0; i < 4; i++) {
+		for (j = 0, k = 0; j < 8; j++)
+			k += abs(((int)gsm0503_pdtch_hl_hn_sbit[i][j]) - ((int)hl_hn[j]));
+
+		if (i == 0 || k < best) {
+			best = k;
+			cs = i+1;
+		}
+	}
+
+	gsm0503_xcch_deinterleave(cB, iB);
+
+	switch (cs) {
+	case 1:
+		osmo_conv_decode_ber(&gsm0503_xcch, cB,
+			conv, n_errors, n_bits_total);
+
+		rv = osmo_crc64gen_check_bits(&gsm0503_fire_crc40,
+			conv, 184, conv + 184);
+		if (rv)
+			return -1;
+
+		osmo_ubit2pbit_ext(l2_data, 0, conv, 0, 184, 1);
+
+		return 23;
+	case 2:
+		for (i = 587, j = 455; i >= 0; i--) {
+			if (!gsm0503_puncture_cs2[i])
+				cB[i] = cB[j--];
+			else
+				cB[i] = 0;
+		}
+
+		osmo_conv_decode_ber(&gsm0503_cs2, cB,
+			conv, n_errors, n_bits_total);
+
+		for (i = 0; i < 8; i++) {
+			for (j = 0, k = 0; j < 6; j++)
+				k += abs(((int)gsm0503_usf2six[i][j]) - ((int)conv[j]));
+
+			if (i == 0 || k < best) {
+				best = k;
+				usf = i;
+			}
+		}
+
+		conv[3] = usf & 1;
+		conv[4] = (usf >> 1) & 1;
+		conv[5] = (usf >> 2) & 1;
+		if (usf_p)
+			*usf_p = usf;
+
+		rv = osmo_crc16gen_check_bits(&gsm0503_cs234_crc16,
+			conv + 3, 271, conv + 3 + 271);
+		if (rv)
+			return -1;
+
+		osmo_ubit2pbit_ext(l2_data, 0, conv, 3, 271, 1);
+
+		return 34;
+	case 3:
+		for (i = 675, j = 455; i >= 0; i--) {
+			if (!gsm0503_puncture_cs3[i])
+				cB[i] = cB[j--];
+			else
+				cB[i] = 0;
+		}
+
+		osmo_conv_decode_ber(&gsm0503_cs3, cB,
+			conv, n_errors, n_bits_total);
+
+		for (i = 0; i < 8; i++) {
+			for (j = 0, k = 0; j < 6; j++)
+				k += abs(((int)gsm0503_usf2six[i][j]) - ((int)conv[j]));
+
+			if (i == 0 || k < best) {
+				best = k;
+				usf = i;
+			}
+		}
+
+		conv[3] = usf & 1;
+		conv[4] = (usf >> 1) & 1;
+		conv[5] = (usf >> 2) & 1;
+		if (usf_p)
+			*usf_p = usf;
+
+		rv = osmo_crc16gen_check_bits(&gsm0503_cs234_crc16,
+			conv + 3, 315, conv + 3 + 315);
+		if (rv)
+			return -1;
+
+		osmo_ubit2pbit_ext(l2_data, 0, conv, 3, 315, 1);
+
+		return 40;
+	case 4:
+		for (i = 12; i < 456; i++)
+			conv[i] = (cB[i] < 0) ? 1 : 0;
+
+		for (i = 0; i < 8; i++) {
+			for (j = 0, k = 0; j < 12; j++)
+				k += abs(((int)gsm0503_usf2twelve_sbit[i][j]) - ((int)cB[j]));
+
+			if (i == 0 || k < best) {
+				best = k;
+				usf = i;
+			}
+		}
+
+		conv[9] = usf & 1;
+		conv[10] = (usf >> 1) & 1;
+		conv[11] = (usf >> 2) & 1;
+		if (usf_p)
+			*usf_p = usf;
+
+		rv = osmo_crc16gen_check_bits(&gsm0503_cs234_crc16,
+			conv + 9, 431, conv + 9 + 431);
+		if (rv) {
+			*n_bits_total = 456 - 12;
+			*n_errors = *n_bits_total;
+			return -1;
+		}
+
+		*n_bits_total = 456 - 12;
+		*n_errors = 0;
+
+		osmo_ubit2pbit_ext(l2_data, 0, conv, 9, 431, 1);
+
+		return 54;
+	default:
+		*n_bits_total = 0;
+		*n_errors = 0;
+		break;
+	}
+
+	return -1;
+}
+
+/*
+ * EGPRS PDTCH UL block encoding
+ */
+static int egprs_type3_map(ubit_t *bursts, ubit_t *hc, ubit_t *dc, int usf)
+{
+	int i;
+	ubit_t iB[456];
+	const ubit_t *hl_hn = gsm0503_pdtch_hl_hn_ubit[3];
+
+	gsm0503_mcs1_dl_interleave(gsm0503_usf2six[usf], hc, dc, iB);
+
+	for (i = 0; i < 4; i++) {
+		gsm0503_xcch_burst_map(&iB[i * 114], &bursts[i * 116],
+			hl_hn + i * 2, hl_hn + i * 2 + 1);
+	}
+
+	return 0;
+}
+
+static int egprs_type2_map(ubit_t *bursts, ubit_t *hc, ubit_t *dc, int usf)
+{
+	int i;
+	const ubit_t *up;
+	ubit_t hi[EGPRS_HDR_HC_MAX];
+	ubit_t di[EGPRS_DATA_DC_MAX];
+
+	gsm0503_mcs5_dl_interleave(hc, dc, hi, di);
+	up = gsm0503_mcs5_usf_precode_table[usf];
+
+	for (i = 0; i < 4; i++) {
+		gsm0503_mcs5_dl_burst_map(di, &bursts[i * 348], hi, up, i);
+		gsm0503_mcs5_burst_swap((sbit_t *) &bursts[i * 348]);
+	}
+
+	return 0;
+}
+
+static int egprs_type1_map(ubit_t *bursts, ubit_t *hc,
+			   ubit_t *c1, ubit_t *c2, int usf, int mcs)
+{
+	int i;
+	const ubit_t *up;
+	ubit_t hi[EGPRS_HDR_HC_MAX];
+	ubit_t di[EGPRS_DATA_C1 * 2];
+
+	if (mcs == EGPRS_MCS7)
+		gsm0503_mcs7_dl_interleave(hc, c1, c2, hi, di);
+	else
+		gsm0503_mcs8_dl_interleave(hc, c1, c2, hi, di);
+
+	up = gsm0503_mcs5_usf_precode_table[usf];
+
+	for (i = 0; i < 4; i++) {
+		gsm0503_mcs7_dl_burst_map(di, &bursts[i * 348], hi, up, i);
+		gsm0503_mcs5_burst_swap((sbit_t *) &bursts[i * 348]);
+	}
+
+	return 0;
+}
+
+static int egprs_encode_hdr(ubit_t *hc, uint8_t *l2_data, int mcs)
+{
+	int i, j;
+	ubit_t upp[EGPRS_HDR_UPP_MAX], C[EGPRS_HDR_C_MAX];
+	struct gsm0503_mcs_code *code;
+
+	code = &gsm0503_mcs_dl_codes[mcs];
+
+	osmo_pbit2ubit_ext(upp, 0, l2_data, code->usf_len, code->hdr_len, 1);
+	osmo_crc8gen_set_bits(&gsm0503_mcs_crc8_hdr, upp,
+			      code->hdr_len, upp + code->hdr_len);
+
+	osmo_conv_encode(code->hdr_conv, upp, C);
+
+	/* MCS-5,6 header direct puncture instead of table */
+	if ((mcs == EGPRS_MCS5) || (mcs == EGPRS_MCS6)) {
+		memcpy(hc, C, code->hdr_code_len);
+		hc[99] = hc[98];
+		return 0;
+	}
+
+	if (!code->hdr_punc) {
+		/* Invalid MCS-X header puncture matrix */
+		return -1;
+	}
+
+	for (i = 0, j = 0; i < code->hdr_code_len; i++) {
+		if (!code->hdr_punc[i])
+			hc[j++] = C[i];
+	}
+
+	return 0;
+}
+
+static int egprs_encode_data(ubit_t *c, uint8_t *l2_data,
+			     int mcs, int p, int blk)
+{
+	int i, j, data_len;
+	ubit_t u[EGPRS_DATA_U_MAX], C[EGPRS_DATA_C_MAX];
+	struct gsm0503_mcs_code *code;
+
+	code = &gsm0503_mcs_dl_codes[mcs];
+
+	/*
+	 * Dual block   - MCS-7,8,9
+	 * Single block - MCS-1,2,3,4,5,6
+	 */
+	if (mcs >= EGPRS_MCS7)
+		data_len = code->data_len / 2;
+	else
+		data_len = code->data_len;
+
+	osmo_pbit2ubit_ext(u, 0, l2_data,
+		code->usf_len + code->hdr_len + blk * data_len, data_len, 1);
+
+	osmo_crc16gen_set_bits(&gsm0503_mcs_crc12, u, data_len, u + data_len);
+
+	osmo_conv_encode(code->data_conv, u, C);
+
+	if (!code->data_punc[p]) {
+		/* Invalid MCS-X data puncture matrix */
+		return -1;
+	}
+
+	for (i = 0, j = 0; i < code->data_code_len; i++) {
+		if (!code->data_punc[p][i])
+			c[j++] = C[i];
+	}
+
+	return 0;
+}
+
+union gprs_rlc_dl_hdr_egprs {
+	struct gprs_rlc_dl_header_egprs_1 type1;
+	struct gprs_rlc_dl_header_egprs_2 type2;
+	struct gprs_rlc_dl_header_egprs_3 type3;
+};
+
+/*
+ * Parse EGPRS DL header for coding and puncturing scheme (CPS)
+ *
+ * Type 1 - MCS-7,8,9
+ * Type 2 - MCS-5,6
+ * Type 3 - MCS-1,2,3,4
+ */
+static int egprs_parse_dl_cps(struct egprs_cps *cps,
+			      union gprs_rlc_dl_hdr_egprs *hdr, int type)
+{
+	uint8_t bits;
+
+	switch (type) {
+	case EGPRS_HDR_TYPE1:
+		bits = hdr->type1.cps;
+		break;
+	case EGPRS_HDR_TYPE2:
+		bits = hdr->type2.cps;
+		break;
+	case EGPRS_HDR_TYPE3:
+		bits = hdr->type3.cps;
+		break;
+	default:
+		return -1;
+	}
+
+	return egprs_get_cps(cps, type, bits);
+}
+
+/*
+ * EGPRS DL message encoding
+ */
+int gsm0503_pdtch_egprs_encode(ubit_t *bursts,
+	uint8_t *l2_data, uint8_t l2_len)
+{
+	ubit_t hc[EGPRS_DATA_C_MAX], dc[EGPRS_DATA_DC_MAX];
+	ubit_t c1[EGPRS_DATA_C1], c2[EGPRS_DATA_C2];
+	uint8_t mcs;
+	struct egprs_cps cps;
+	union gprs_rlc_dl_hdr_egprs *hdr;
+
+	switch (l2_len) {
+	case 27:
+		mcs = EGPRS_MCS1;
+		break;
+	case 33:
+		mcs = EGPRS_MCS2;
+		break;
+	case 42:
+		mcs = EGPRS_MCS3;
+		break;
+	case 49:
+		mcs = EGPRS_MCS4;
+		break;
+	case 60:
+		mcs = EGPRS_MCS5;
+		break;
+	case 78:
+		mcs = EGPRS_MCS6;
+		break;
+	case 118:
+		mcs = EGPRS_MCS7;
+		break;
+	case 142:
+		mcs = EGPRS_MCS8;
+		break;
+	case 154:
+		mcs = EGPRS_MCS9;
+		break;
+	default:
+		return -1;
+	}
+
+	/* Read header for USF and puncturing matrix selection. */
+	hdr = (union gprs_rlc_dl_hdr_egprs *) l2_data;
+
+	switch (mcs) {
+	case EGPRS_MCS1:
+	case EGPRS_MCS2:
+	case EGPRS_MCS3:
+	case EGPRS_MCS4:
+		/* Check for valid CPS and matching MCS to message size */
+		if ((egprs_parse_dl_cps(&cps, hdr, EGPRS_HDR_TYPE3) < 0) ||
+		    (cps.mcs != mcs))
+			goto bad_header;
+
+		egprs_encode_hdr(hc, l2_data, mcs);
+		egprs_encode_data(dc, l2_data, mcs, cps.p[0], 0);
+		egprs_type3_map(bursts, hc, dc, hdr->type3.usf);
+		break;
+	case EGPRS_MCS5:
+	case EGPRS_MCS6:
+		if ((egprs_parse_dl_cps(&cps, hdr, EGPRS_HDR_TYPE2) < 0) ||
+		    (cps.mcs != mcs))
+			goto bad_header;
+
+		egprs_encode_hdr(hc, l2_data, mcs);
+		egprs_encode_data(dc, l2_data, mcs, cps.p[0], 0);
+		egprs_type2_map(bursts, hc, dc, hdr->type2.usf);
+		break;
+	case EGPRS_MCS7:
+	case EGPRS_MCS8:
+	case EGPRS_MCS9:
+		if ((egprs_parse_dl_cps(&cps, hdr, EGPRS_HDR_TYPE1) < 0) ||
+		    (cps.mcs != mcs))
+			goto bad_header;
+
+		egprs_encode_hdr(hc, l2_data, mcs);
+		egprs_encode_data(c1, l2_data, mcs, cps.p[0], 0);
+		egprs_encode_data(c2, l2_data, mcs, cps.p[1], 1);
+		egprs_type1_map(bursts, hc, c1, c2, hdr->type1.usf, mcs);
+		break;
+	}
+
+	return mcs >= EGPRS_MCS5 ? GSM0503_EGPRS_BURSTS_NBITS :
+				   GSM0503_GPRS_BURSTS_NBITS;
+
+bad_header:
+	/* Invalid EGPRS MCS-X header */
+	return -1;
+}
+
+int gsm0503_pdtch_encode(ubit_t *bursts, uint8_t *l2_data, uint8_t l2_len)
+{
+	ubit_t iB[456], cB[676];
+	const ubit_t *hl_hn;
+	ubit_t conv[334];
+	int i, j, usf;
+
+	switch (l2_len) {
+	case 23:
+		osmo_pbit2ubit_ext(conv, 0, l2_data, 0, 184, 1);
+
+		osmo_crc64gen_set_bits(&gsm0503_fire_crc40, conv, 184, conv + 184);
+
+		osmo_conv_encode(&gsm0503_xcch, conv, cB);
+
+		hl_hn = gsm0503_pdtch_hl_hn_ubit[0];
+
+		break;
+	case 34:
+		osmo_pbit2ubit_ext(conv, 3, l2_data, 0, 271, 1);
+		usf = l2_data[0] & 0x7;
+
+		osmo_crc16gen_set_bits(&gsm0503_cs234_crc16, conv + 3,
+			271, conv + 3 + 271);
+
+		memcpy(conv, gsm0503_usf2six[usf], 6);
+
+		osmo_conv_encode(&gsm0503_cs2, conv, cB);
+
+		for (i = 0, j = 0; i < 588; i++)
+			if (!gsm0503_puncture_cs2[i])
+				cB[j++] = cB[i];
+
+		hl_hn = gsm0503_pdtch_hl_hn_ubit[1];
+
+		break;
+	case 40:
+		osmo_pbit2ubit_ext(conv, 3, l2_data, 0, 315, 1);
+		usf = l2_data[0] & 0x7;
+
+		osmo_crc16gen_set_bits(&gsm0503_cs234_crc16, conv + 3,
+			315, conv + 3 + 315);
+
+		memcpy(conv, gsm0503_usf2six[usf], 6);
+
+		osmo_conv_encode(&gsm0503_cs3, conv, cB);
+
+		for (i = 0, j = 0; i < 676; i++)
+			if (!gsm0503_puncture_cs3[i])
+				cB[j++] = cB[i];
+
+		hl_hn = gsm0503_pdtch_hl_hn_ubit[2];
+
+		break;
+	case 54:
+		osmo_pbit2ubit_ext(cB, 9, l2_data, 0, 431, 1);
+		usf = l2_data[0] & 0x7;
+
+		osmo_crc16gen_set_bits(&gsm0503_cs234_crc16, cB + 9,
+			431, cB + 9 + 431);
+
+		memcpy(cB, gsm0503_usf2twelve_ubit[usf], 12);
+
+		hl_hn = gsm0503_pdtch_hl_hn_ubit[3];
+
+		break;
+	default:
+		return -1;
+	}
+
+	gsm0503_xcch_interleave(cB, iB);
+
+	for (i = 0; i < 4; i++) {
+		gsm0503_xcch_burst_map(&iB[i * 114], &bursts[i * 116],
+			hl_hn + i * 2, hl_hn + i * 2 + 1);
+	}
+
+	return GSM0503_GPRS_BURSTS_NBITS;
+}
+
+
+/*
+ * GSM TCH/F FR/EFR transcoding
+ */
+
+static void tch_fr_reassemble(uint8_t *tch_data,
+	ubit_t *b_bits, int net_order)
+{
+	int i, j, k, l, o;
+
+	tch_data[0] = 0xd << 4;
+	memset(tch_data + 1, 0, 32);
+
+	if (net_order) {
+		for (i = 0, j = 4; i < 260; i++, j++)
+			tch_data[j >> 3] |= (b_bits[i] << (7 - (j & 7)));
+
+		return;
+	}
+
+	/* reassemble d-bits */
+	i = 0; /* counts bits */
+	j = 4; /* counts output bits */
+	k = gsm0503_gsm_fr_map[0]-1; /* current number bit in element */
+	l = 0; /* counts element bits */
+	o = 0; /* offset input bits */
+	while (i < 260) {
+		tch_data[j >> 3] |= (b_bits[k + o] << (7 - (j & 7)));
+		if (--k < 0) {
+			o += gsm0503_gsm_fr_map[l];
+			k = gsm0503_gsm_fr_map[++l]-1;
+		}
+		i++;
+		j++;
+	}
+}
+
+static void tch_fr_disassemble(ubit_t *b_bits,
+	uint8_t *tch_data, int net_order)
+{
+	int i, j, k, l, o;
+
+	if (net_order) {
+		for (i = 0, j = 4; i < 260; i++, j++)
+			b_bits[i] = (tch_data[j >> 3] >> (7 - (j & 7))) & 1;
+
+		return;
+	}
+
+	i = 0; /* counts bits */
+	j = 4; /* counts input bits */
+	k = gsm0503_gsm_fr_map[0] - 1; /* current number bit in element */
+	l = 0; /* counts element bits */
+	o = 0; /* offset output bits */
+	while (i < 260) {
+		b_bits[k + o] = (tch_data[j >> 3] >> (7 - (j & 7))) & 1;
+		if (--k < 0) {
+			o += gsm0503_gsm_fr_map[l];
+			k = gsm0503_gsm_fr_map[++l] - 1;
+		}
+		i++;
+		j++;
+	}
+}
+
+static void tch_hr_reassemble(uint8_t *tch_data, ubit_t *b_bits)
+{
+	int i, j;
+
+	tch_data[0] = 0x00; /* F = 0, FT = 000 */
+	memset(tch_data + 1, 0, 14);
+
+	for (i = 0, j = 8; i < 112; i++, j++)
+		tch_data[j >> 3] |= (b_bits[i] << (7 - (j & 7)));
+}
+
+static void tch_hr_disassemble(ubit_t *b_bits, uint8_t *tch_data)
+{
+	int i, j;
+
+	for (i = 0, j = 8; i < 112; i++, j++)
+		b_bits[i] = (tch_data[j >> 3] >> (7 - (j & 7))) & 1;
+}
+
+static void tch_efr_reassemble(uint8_t *tch_data, ubit_t *b_bits)
+{
+	int i, j;
+
+	tch_data[0] = 0xc << 4;
+	memset(tch_data + 1, 0, 30);
+
+	for (i = 0, j = 4; i < 244; i++, j++)
+		tch_data[j >> 3] |= (b_bits[i] << (7 - (j & 7)));
+}
+
+static void tch_efr_disassemble(ubit_t *b_bits, uint8_t *tch_data)
+{
+	int i, j;
+
+	for (i = 0, j = 4; i < 244; i++, j++)
+		b_bits[i] = (tch_data[j >> 3] >> (7 - (j & 7))) & 1;
+}
+
+static void tch_amr_reassemble(uint8_t *tch_data, ubit_t *d_bits, int len)
+{
+	int i, j;
+
+	memset(tch_data, 0, (len + 7) >> 3);
+
+	for (i = 0, j = 0; i < len; i++, j++)
+		tch_data[j >> 3] |= (d_bits[i] << (7 - (j & 7)));
+}
+
+static void tch_amr_disassemble(ubit_t *d_bits, uint8_t *tch_data, int len)
+{
+	int i, j;
+
+	for (i = 0, j = 0; i < len; i++, j++)
+		d_bits[i] = (tch_data[j >> 3] >> (7 - (j & 7))) & 1;
+}
+
+static void tch_fr_d_to_b(ubit_t *b_bits, ubit_t *d_bits)
+{
+	int i;
+
+	for (i = 0; i < 260; i++)
+		b_bits[gsm610_bitorder[i]] = d_bits[i];
+}
+
+static void tch_fr_b_to_d(ubit_t *d_bits, ubit_t *b_bits)
+{
+	int i;
+
+	for (i = 0; i < 260; i++)
+		d_bits[i] = b_bits[gsm610_bitorder[i]];
+}
+
+static void tch_hr_d_to_b(ubit_t *b_bits, ubit_t *d_bits)
+{
+	int i;
+
+	const uint16_t *map;
+
+	if (!d_bits[93] && !d_bits[94])
+		map = gsm620_unvoiced_bitorder;
+	else
+		map = gsm620_voiced_bitorder;
+
+	for (i = 0; i < 112; i++)
+		b_bits[map[i]] = d_bits[i];
+}
+
+static void tch_hr_b_to_d(ubit_t *d_bits, ubit_t *b_bits)
+{
+	int i;
+	const uint16_t *map;
+
+	if (!b_bits[34] && !b_bits[35])
+		map = gsm620_unvoiced_bitorder;
+	else
+		map = gsm620_voiced_bitorder;
+
+	for (i = 0; i < 112; i++)
+		d_bits[i] = b_bits[map[i]];
+}
+
+static void tch_efr_d_to_w(ubit_t *b_bits, ubit_t *d_bits)
+{
+	int i;
+
+	for (i = 0; i < 260; i++)
+		b_bits[gsm660_bitorder[i]] = d_bits[i];
+}
+
+static void tch_efr_w_to_d(ubit_t *d_bits, ubit_t *b_bits)
+{
+	int i;
+
+	for (i = 0; i < 260; i++)
+		d_bits[i] = b_bits[gsm660_bitorder[i]];
+}
+
+static void tch_efr_protected(ubit_t *s_bits, ubit_t *b_bits)
+{
+	int i;
+
+	for (i = 0; i < 65; i++)
+		b_bits[i] = s_bits[gsm0503_gsm_efr_protected_bits[i] - 1];
+}
+
+static void tch_fr_unreorder(ubit_t *d, ubit_t *p, ubit_t *u)
+{
+	int i;
+
+	for (i = 0; i < 91; i++) {
+		d[i << 1] = u[i];
+		d[(i << 1) + 1] = u[184 - i];
+	}
+
+	for (i = 0; i < 3; i++)
+		p[i] = u[91 + i];
+}
+
+static void tch_fr_reorder(ubit_t *u, ubit_t *d, ubit_t *p)
+{
+	int i;
+
+	for (i = 0; i < 91; i++) {
+		u[i] = d[i << 1];
+		u[184 - i] = d[(i << 1) + 1];
+	}
+
+	for (i = 0; i < 3; i++)
+		u[91 + i] = p[i];
+}
+
+static void tch_hr_unreorder(ubit_t *d, ubit_t *p, ubit_t *u)
+{
+	memcpy(d, u, 95);
+	memcpy(p, u + 95, 3);
+}
+
+static void tch_hr_reorder(ubit_t *u, ubit_t *d, ubit_t *p)
+{
+	memcpy(u, d, 95);
+	memcpy(u + 95, p, 3);
+}
+
+static void tch_efr_reorder(ubit_t *w, ubit_t *s, ubit_t *p)
+{
+	memcpy(w, s, 71);
+	w[71] = w[72] = s[69];
+	memcpy(w + 73, s + 71, 50);
+	w[123] = w[124] = s[119];
+	memcpy(w + 125, s + 121, 53);
+	w[178] = w[179] = s[172];
+	memcpy(w + 180, s + 174, 50);
+	w[230] = w[231] = s[222];
+	memcpy(w + 232, s + 224, 20);
+	memcpy(w + 252, p, 8);
+}
+
+static void tch_efr_unreorder(ubit_t *s, ubit_t *p, ubit_t *w)
+{
+	int sum;
+
+	memcpy(s, w, 71);
+	sum = s[69] + w[71] + w[72];
+	s[69] = (sum > 2);
+	memcpy(s + 71, w + 73, 50);
+	sum = s[119] + w[123] + w[124];
+	s[119] = (sum > 2);
+	memcpy(s + 121, w + 125, 53);
+	sum = s[172] + w[178] + w[179];
+	s[172] = (sum > 2);
+	memcpy(s + 174, w + 180, 50);
+	sum = s[220] + w[230] + w[231];
+	s[222] = (sum > 2);
+	memcpy(s + 224, w + 232, 20);
+	memcpy(p, w + 252, 8);
+}
+
+static void tch_amr_merge(ubit_t *u, ubit_t *d, ubit_t *p, int len, int prot)
+{
+	memcpy(u, d, prot);
+	memcpy(u + prot, p, 6);
+	memcpy(u + prot + 6, d + prot, len - prot);
+}
+
+static void tch_amr_unmerge(ubit_t *d, ubit_t *p,
+	ubit_t *u, int len, int prot)
+{
+	memcpy(d, u, prot);
+	memcpy(p, u+prot, 6);
+	memcpy(d + prot, u + prot + 6, len - prot);
+}
+
+int gsm0503_tch_fr_decode(uint8_t *tch_data, sbit_t *bursts,
+	int net_order, int efr, int *n_errors, int *n_bits_total)
+{
+	sbit_t iB[912], cB[456], h;
+	ubit_t conv[185], s[244], w[260], b[65], d[260], p[8];
+	int i, rv, len, steal = 0;
+
+	for (i=0; i<8; i++) {
+		gsm0503_tch_burst_unmap(&iB[i * 114],
+			&bursts[i * 116], &h, i >> 2);
+		steal -= h;
+	}
+
+	gsm0503_tch_fr_deinterleave(cB, iB);
+
+	if (steal > 0) {
+		rv = _xcch_decode_cB(tch_data, cB, n_errors, n_bits_total);
+		if (rv) {
+			/* Error decoding FACCH frame */
+			return -1;
+		}
+
+		return 23;
+	}
+
+	osmo_conv_decode_ber(&gsm0503_tch_fr, cB, conv, n_errors, n_bits_total);
+
+	tch_fr_unreorder(d, p, conv);
+
+	for (i = 0; i < 78; i++)
+		d[i + 182] = (cB[i + 378] < 0) ? 1 : 0;
+
+	rv = osmo_crc8gen_check_bits(&gsm0503_tch_fr_crc3, d, 50, p);
+	if (rv) {
+		/* Error checking CRC8 for the FR part of an EFR/FR frame */
+		return -1;
+	}
+
+	if (efr) {
+		tch_efr_d_to_w(w, d);
+
+		tch_efr_unreorder(s, p, w);
+
+		tch_efr_protected(s, b);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_tch_efr_crc8, b, 65, p);
+		if (rv) {
+			/* Error checking CRC8 for the EFR part of an EFR frame */
+			return -1;
+		}
+
+		tch_efr_reassemble(tch_data, s);
+
+		len = GSM_EFR_BYTES;
+	} else {
+		tch_fr_d_to_b(w, d);
+
+		tch_fr_reassemble(tch_data, w, net_order);
+
+		len = GSM_FR_BYTES;
+	}
+
+	return len;
+}
+
+int gsm0503_tch_fr_encode(ubit_t *bursts, uint8_t *tch_data,
+	int len, int net_order)
+{
+	ubit_t iB[912], cB[456], h;
+	ubit_t conv[185], w[260], b[65], s[244], d[260], p[8];
+	int i;
+
+	switch (len) {
+	case GSM_EFR_BYTES: /* TCH EFR */
+
+		tch_efr_disassemble(s, tch_data);
+
+		tch_efr_protected(s, b);
+
+		osmo_crc8gen_set_bits(&gsm0503_tch_efr_crc8, b, 65, p);
+
+		tch_efr_reorder(w, s, p);
+
+		tch_efr_w_to_d(d, w);
+
+		goto coding_efr_fr;
+	case GSM_FR_BYTES: /* TCH FR */
+		tch_fr_disassemble(w, tch_data, net_order);
+
+		tch_fr_b_to_d(d, w);
+
+coding_efr_fr:
+		osmo_crc8gen_set_bits(&gsm0503_tch_fr_crc3, d, 50, p);
+
+		tch_fr_reorder(conv, d, p);
+
+		memcpy(cB + 378, d + 182, 78);
+
+		osmo_conv_encode(&gsm0503_tch_fr, conv, cB);
+
+		h = 0;
+
+		break;
+	case GSM_MACBLOCK_LEN: /* FACCH */
+		_xcch_encode_cB(cB, tch_data);
+
+		h = 1;
+
+		break;
+	default:
+		return -1;
+	}
+
+	gsm0503_tch_fr_interleave(cB, iB);
+
+	for (i = 0; i < 8; i++) {
+		gsm0503_tch_burst_map(&iB[i * 114],
+			&bursts[i * 116], &h, i >> 2);
+	}
+
+	return 0;
+}
+
+int gsm0503_tch_hr_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
+	int *n_errors, int *n_bits_total)
+{
+	sbit_t iB[912], cB[456], h;
+	ubit_t conv[98], b[112], d[112], p[3];
+	int i, rv, steal = 0;
+
+	/* Only unmap the stealing bits */
+	if (!odd) {
+		for (i = 0; i < 4; i++) {
+			gsm0503_tch_burst_unmap(NULL, &bursts[i * 116], &h, 0);
+			steal -= h;
+		}
+
+		for (i = 2; i < 5; i++) {
+			gsm0503_tch_burst_unmap(NULL, &bursts[i * 116], &h, 1);
+			steal -= h;
+		}
+	}
+
+	/* If we found a stole FACCH, but only at correct alignment */
+	if (steal > 0) {
+		for (i = 0; i < 6; i++) {
+			gsm0503_tch_burst_unmap(&iB[i * 114],
+				&bursts[i * 116], NULL, i >> 2);
+		}
+
+		for (i = 2; i < 4; i++) {
+			gsm0503_tch_burst_unmap(&iB[i * 114 + 456],
+				&bursts[i * 116], NULL, 1);
+		}
+
+		gsm0503_tch_fr_deinterleave(cB, iB);
+
+		rv = _xcch_decode_cB(tch_data, cB, n_errors, n_bits_total);
+		if (rv) {
+			/* Error decoding FACCH frame */
+			return -1;
+		}
+
+		return GSM_MACBLOCK_LEN;
+	}
+
+	for (i = 0; i < 4; i++) {
+		gsm0503_tch_burst_unmap(&iB[i * 114],
+			&bursts[i * 116], NULL, i >> 1);
+	}
+
+	gsm0503_tch_hr_deinterleave(cB, iB);
+
+	osmo_conv_decode_ber(&gsm0503_tch_hr, cB, conv, n_errors, n_bits_total);
+
+	tch_hr_unreorder(d, p, conv);
+
+	for (i = 0; i < 17; i++)
+		d[i + 95] = (cB[i + 211] < 0) ? 1 : 0;
+
+	rv = osmo_crc8gen_check_bits(&gsm0503_tch_fr_crc3, d + 73, 22, p);
+	if (rv) {
+		/* Error checking CRC8 for an HR frame */
+		return -1;
+	}
+
+	tch_hr_d_to_b(b, d);
+
+	tch_hr_reassemble(tch_data, b);
+
+	return 15;
+}
+
+int gsm0503_tch_hr_encode(ubit_t *bursts, uint8_t *tch_data, int len)
+{
+	ubit_t iB[912], cB[456], h;
+	ubit_t conv[98], b[112], d[112], p[3];
+	int i;
+
+	switch (len) {
+	case 15: /* TCH HR */
+		tch_hr_disassemble(b, tch_data);
+
+		tch_hr_b_to_d(d, b);
+
+		osmo_crc8gen_set_bits(&gsm0503_tch_fr_crc3, d + 73, 22, p);
+
+		tch_hr_reorder(conv, d, p);
+
+		osmo_conv_encode(&gsm0503_tch_hr, conv, cB);
+
+		memcpy(cB + 211, d + 95, 17);
+
+		h = 0;
+
+		gsm0503_tch_hr_interleave(cB, iB);
+
+		for (i = 0; i < 4; i++) {
+			gsm0503_tch_burst_map(&iB[i * 114],
+				&bursts[i * 116], &h, i >> 1);
+		}
+
+		break;
+	case GSM_MACBLOCK_LEN: /* FACCH */
+		_xcch_encode_cB(cB, tch_data);
+
+		h = 1;
+
+		gsm0503_tch_fr_interleave(cB, iB);
+
+		for (i=0; i<6; i++) {
+			gsm0503_tch_burst_map(&iB[i * 114],
+				&bursts[i * 116], &h, i >> 2);
+		}
+
+		for (i=2; i<4; i++) {
+			gsm0503_tch_burst_map(&iB[i * 114 + 456],
+				&bursts[i * 116], &h, 1);
+		}
+
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+int gsm0503_tch_afs_decode(uint8_t *tch_data, sbit_t *bursts,
+	int codec_mode_req, uint8_t *codec, int codecs, uint8_t *ft,
+	uint8_t *cmr, int *n_errors, int *n_bits_total)
+{
+	sbit_t iB[912], cB[456], h;
+	ubit_t d[244], p[6], conv[250];
+	int i, j, k, best = 0, rv, len, steal = 0, id = 0;
+	*n_errors = 0; *n_bits_total = 0;
+
+	for (i=0; i<8; i++) {
+		gsm0503_tch_burst_unmap(&iB[i * 114], &bursts[i * 116], &h, i >> 2);
+		steal -= h;
+	}
+
+	gsm0503_tch_fr_deinterleave(cB, iB);
+
+	if (steal > 0) {
+		rv = _xcch_decode_cB(tch_data, cB, n_errors, n_bits_total);
+		if (rv) {
+			/* Error decoding FACCH frame */
+			return -1;
+		}
+
+		return GSM_MACBLOCK_LEN;
+	}
+
+	for (i = 0; i < 4; i++) {
+		for (j = 0, k = 0; j < 8; j++)
+			k += abs(((int)gsm0503_afs_ic_sbit[i][j]) - ((int)cB[j]));
+
+		if (i == 0 || k < best) {
+			best = k;
+			id = i;
+		}
+	}
+
+	/* Check if indicated codec fits into range of codecs */
+	if (id >= codecs) {
+		/* Codec mode out of range, return id */
+		return id;
+	}
+
+	switch ((codec_mode_req) ? codec[*ft] : codec[id]) {
+	case 7: /* TCH/AFS12.2 */
+		osmo_conv_decode_ber(&gsm0503_tch_afs_12_2, cB + 8,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 244, 81);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 81, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 12.2 frame */
+			return -1;
+		}
+
+		tch_amr_reassemble(tch_data, d, 244);
+
+		len = 31;
+
+		break;
+	case 6: /* TCH/AFS10.2 */
+		osmo_conv_decode_ber(&gsm0503_tch_afs_10_2, cB + 8,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 204, 65);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 65, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 10.2 frame */
+			return -1;
+		}
+
+		tch_amr_reassemble(tch_data, d, 204);
+
+		len = 26;
+
+		break;
+	case 5: /* TCH/AFS7.95 */
+		osmo_conv_decode_ber(&gsm0503_tch_afs_7_95, cB + 8,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 159, 75);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 75, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 7.95 frame */
+			return -1;
+		}
+
+		tch_amr_reassemble(tch_data, d, 159);
+
+		len = 20;
+
+		break;
+	case 4: /* TCH/AFS7.4 */
+		osmo_conv_decode_ber(&gsm0503_tch_afs_7_4, cB + 8,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 148, 61);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 61, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 7.4 frame */
+			return -1;
+		}
+
+		tch_amr_reassemble(tch_data, d, 148);
+
+		len = 19;
+
+		break;
+	case 3: /* TCH/AFS6.7 */
+		osmo_conv_decode_ber(&gsm0503_tch_afs_6_7, cB + 8,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 134, 55);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 55, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 6.7 frame */
+			return -1;
+		}
+
+		tch_amr_reassemble(tch_data, d, 134);
+
+		len = 17;
+
+		break;
+	case 2: /* TCH/AFS5.9 */
+		osmo_conv_decode_ber(&gsm0503_tch_afs_5_9, cB + 8,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 118, 55);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 55, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 5.9 frame */
+			return -1;
+		}
+
+		tch_amr_reassemble(tch_data, d, 118);
+
+		len = 15;
+
+		break;
+	case 1: /* TCH/AFS5.15 */
+		osmo_conv_decode_ber(&gsm0503_tch_afs_5_15, cB + 8,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 103, 49);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 49, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 5.15 frame */
+			return -1;
+		}
+
+		tch_amr_reassemble(tch_data, d, 103);
+
+		len = 13;
+
+		break;
+	case 0: /* TCH/AFS4.75 */
+		osmo_conv_decode_ber(&gsm0503_tch_afs_4_75, cB + 8,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 95, 39);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 39, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 4.75 frame */
+			return -1;
+		}
+
+		tch_amr_reassemble(tch_data, d, 95);
+
+		len = 12;
+
+		break;
+	default:
+		/* Unknown frame type */
+		*n_bits_total = 448;
+		*n_errors = *n_bits_total;
+		return -1;
+	}
+
+	/* Change codec request / indication, if frame is valid */
+	if (codec_mode_req)
+		*cmr = id;
+	else
+		*ft = id;
+
+	return len;
+}
+
+int gsm0503_tch_afs_encode(ubit_t *bursts, uint8_t *tch_data, int len,
+	int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft,
+	uint8_t cmr)
+{
+	ubit_t iB[912], cB[456], h;
+	ubit_t d[244], p[6], conv[250];
+	int i;
+	uint8_t id;
+
+	if (len == GSM_MACBLOCK_LEN) { /* FACCH */
+		_xcch_encode_cB(cB, tch_data);
+
+		h = 1;
+
+		goto facch;
+	}
+
+	h = 0;
+
+	if (codec_mode_req) {
+		if (cmr >= codecs) {
+			/* FIXME: CMR ID is not in codec list! */
+			return -1;
+		}
+		id = cmr;
+	} else {
+		if (ft >= codecs) {
+			/* FIXME: FT ID is not in codec list! */
+			return -1;
+		}
+		id = ft;
+	}
+
+	switch (codec[ft]) {
+	case 7: /* TCH/AFS12.2 */
+		if (len != 31)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 244);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 81, p);
+
+		tch_amr_merge(conv, d, p, 244, 81);
+
+		osmo_conv_encode(&gsm0503_tch_afs_12_2, conv, cB + 8);
+
+		break;
+	case 6: /* TCH/AFS10.2 */
+		if (len != 26)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 204);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 65, p);
+
+		tch_amr_merge(conv, d, p, 204, 65);
+
+		osmo_conv_encode(&gsm0503_tch_afs_10_2, conv, cB + 8);
+
+		break;
+	case 5: /* TCH/AFS7.95 */
+		if (len != 20)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 159);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 75, p);
+
+		tch_amr_merge(conv, d, p, 159, 75);
+
+		osmo_conv_encode(&gsm0503_tch_afs_7_95, conv, cB + 8);
+
+		break;
+	case 4: /* TCH/AFS7.4 */
+		if (len != 19)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 148);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 61, p);
+
+		tch_amr_merge(conv, d, p, 148, 61);
+
+		osmo_conv_encode(&gsm0503_tch_afs_7_4, conv, cB + 8);
+
+		break;
+	case 3: /* TCH/AFS6.7 */
+		if (len != 17)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 134);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p);
+
+		tch_amr_merge(conv, d, p, 134, 55);
+
+		osmo_conv_encode(&gsm0503_tch_afs_6_7, conv, cB + 8);
+
+		break;
+	case 2: /* TCH/AFS5.9 */
+		if (len != 15)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 118);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p);
+
+		tch_amr_merge(conv, d, p, 118, 55);
+
+		osmo_conv_encode(&gsm0503_tch_afs_5_9, conv, cB + 8);
+
+		break;
+	case 1: /* TCH/AFS5.15 */
+		if (len != 13)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 103);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 49, p);
+
+		tch_amr_merge(conv, d, p, 103, 49);
+
+		osmo_conv_encode(&gsm0503_tch_afs_5_15, conv, cB + 8);
+
+		break;
+	case 0: /* TCH/AFS4.75 */
+		if (len != 12)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 95);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 39, p);
+
+		tch_amr_merge(conv, d, p, 95, 39);
+
+		osmo_conv_encode(&gsm0503_tch_afs_4_75, conv, cB + 8);
+
+		break;
+	default:
+		/* FIXME: FT %ft is not supported */
+		return -1;
+	}
+
+	memcpy(cB, gsm0503_afs_ic_ubit[id], 8);
+
+facch:
+	gsm0503_tch_fr_interleave(cB, iB);
+
+	for (i = 0; i < 8; i++) {
+		gsm0503_tch_burst_map(&iB[i * 114],
+			&bursts[i * 116], &h, i >> 2);
+	}
+
+	return 0;
+
+invalid_length:
+	/* FIXME: payload length %len does not comply with codec type %ft */
+	return -1;
+}
+
+int gsm0503_tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
+	int codec_mode_req, uint8_t *codec, int codecs, uint8_t *ft,
+	uint8_t *cmr, int *n_errors, int *n_bits_total)
+{
+	sbit_t iB[912], cB[456], h;
+	ubit_t d[244], p[6], conv[135];
+	int i, j, k, best = 0, rv, len, steal = 0, id = 0;
+
+	/* only unmap the stealing bits */
+	if (!odd) {
+		for (i = 0; i < 4; i++) {
+			gsm0503_tch_burst_unmap(NULL, &bursts[i * 116], &h, 0);
+			steal -= h;
+		}
+		for (i = 2; i < 5; i++) {
+			gsm0503_tch_burst_unmap(NULL, &bursts[i * 116], &h, 1);
+			steal -= h;
+		}
+	}
+
+	/* if we found a stole FACCH, but only at correct alignment */
+	if (steal > 0) {
+		for (i = 0; i < 6; i++) {
+			gsm0503_tch_burst_unmap(&iB[i * 114],
+				&bursts[i * 116], NULL, i >> 2);
+		}
+
+		for (i = 2; i < 4; i++) {
+			gsm0503_tch_burst_unmap(&iB[i * 114 + 456],
+				&bursts[i * 116], NULL, 1);
+		}
+
+		gsm0503_tch_fr_deinterleave(cB, iB);
+
+		rv = _xcch_decode_cB(tch_data, cB, n_errors, n_bits_total);
+		if (rv) {
+			/* Error decoding FACCH frame */
+			return -1;
+		}
+
+		return GSM_MACBLOCK_LEN;
+	}
+
+	for (i = 0; i < 4; i++) {
+		gsm0503_tch_burst_unmap(&iB[i * 114],
+			&bursts[i * 116], NULL, i >> 1);
+	}
+
+	gsm0503_tch_hr_deinterleave(cB, iB);
+
+	for (i = 0; i < 4; i++) {
+		for (j = 0, k = 0; j < 4; j++)
+			k += abs(((int)gsm0503_ahs_ic_sbit[i][j]) - ((int)cB[j]));
+
+		if (i == 0 || k < best) {
+			best = k;
+			id = i;
+		}
+	}
+
+	/* Check if indicated codec fits into range of codecs */
+	if (id >= codecs) {
+		/* Codec mode out of range, return id */
+		return id;
+	}
+
+	switch ((codec_mode_req) ? codec[*ft] : codec[id]) {
+	case 5: /* TCH/AHS7.95 */
+		osmo_conv_decode_ber(&gsm0503_tch_ahs_7_95, cB + 4,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 123, 67);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 67, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 7.95 frame */
+			return -1;
+		}
+
+		for (i = 0; i < 36; i++)
+			d[i + 123] = (cB[i + 192] < 0) ? 1 : 0;
+
+		tch_amr_reassemble(tch_data, d, 159);
+
+		len = 20;
+
+		break;
+	case 4: /* TCH/AHS7.4 */
+		osmo_conv_decode_ber(&gsm0503_tch_ahs_7_4, cB + 4,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 120, 61);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 61, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 7.4 frame */
+			return -1;
+		}
+
+		for (i = 0; i < 28; i++)
+			d[i + 120] = (cB[i + 200] < 0) ? 1 : 0;
+
+		tch_amr_reassemble(tch_data, d, 148);
+
+		len = 19;
+
+		break;
+	case 3: /* TCH/AHS6.7 */
+		osmo_conv_decode_ber(&gsm0503_tch_ahs_6_7, cB + 4,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 110, 55);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 55, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 6.7 frame */
+			return -1;
+		}
+
+		for (i = 0; i < 24; i++)
+			d[i + 110] = (cB[i + 204] < 0) ? 1 : 0;
+
+		tch_amr_reassemble(tch_data, d, 134);
+
+		len = 17;
+
+		break;
+	case 2: /* TCH/AHS5.9 */
+		osmo_conv_decode_ber(&gsm0503_tch_ahs_5_9, cB + 4,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 102, 55);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 55, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 5.9 frame */
+			return -1;
+		}
+
+		for (i = 0; i < 16; i++)
+			d[i + 102] = (cB[i + 212] < 0) ? 1 : 0;
+
+		tch_amr_reassemble(tch_data, d, 118);
+
+		len = 15;
+
+		break;
+	case 1: /* TCH/AHS5.15 */
+		osmo_conv_decode_ber(&gsm0503_tch_ahs_5_15, cB + 4,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 91, 49);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 49, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 5.15 frame */
+			return -1;
+		}
+
+		for (i = 0; i < 12; i++)
+			d[i + 91] = (cB[i + 216] < 0) ? 1 : 0;
+
+		tch_amr_reassemble(tch_data, d, 103);
+
+		len = 13;
+
+		break;
+	case 0: /* TCH/AHS4.75 */
+		osmo_conv_decode_ber(&gsm0503_tch_ahs_4_75, cB + 4,
+			conv, n_errors, n_bits_total);
+
+		tch_amr_unmerge(d, p, conv, 83, 39);
+
+		rv = osmo_crc8gen_check_bits(&gsm0503_amr_crc6, d, 39, p);
+		if (rv) {
+			/* Error checking CRC8 for an AMR 4.75 frame */
+			return -1;
+		}
+
+		for (i = 0; i < 12; i++)
+			d[i + 83] = (cB[i + 216] < 0) ? 1 : 0;
+
+		tch_amr_reassemble(tch_data, d, 95);
+
+		len = 12;
+
+		break;
+	default:
+		/* Unknown frame type */
+		*n_bits_total = 159;
+		*n_errors = *n_bits_total;
+		return -1;
+	}
+
+	/* Change codec request / indication, if frame is valid */
+	if (codec_mode_req)
+		*cmr = id;
+	else
+		*ft = id;
+
+	return len;
+}
+
+int gsm0503_tch_ahs_encode(ubit_t *bursts, uint8_t *tch_data, int len,
+	int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft,
+	uint8_t cmr)
+{
+	ubit_t iB[912], cB[456], h;
+	ubit_t d[244], p[6], conv[135];
+	int i;
+	uint8_t id;
+
+	if (len == GSM_MACBLOCK_LEN) { /* FACCH */
+		_xcch_encode_cB(cB, tch_data);
+
+		h = 1;
+
+		gsm0503_tch_fr_interleave(cB, iB);
+
+		for (i = 0; i < 6; i++)
+			gsm0503_tch_burst_map(&iB[i * 114], &bursts[i * 116],
+				&h, i >> 2);
+		for (i = 2; i < 4; i++)
+			gsm0503_tch_burst_map(&iB[i * 114 + 456],
+				&bursts[i * 116], &h, 1);
+
+		return 0;
+	}
+
+	h = 0;
+
+	if (codec_mode_req) {
+		if (cmr >= codecs) {
+			/* FIXME: CMR ID %d not in codec list */
+			return -1;
+		}
+		id = cmr;
+	} else {
+		if (ft >= codecs) {
+			/* FIXME: FT ID %d not in codec list */
+			return -1;
+		}
+		id = ft;
+	}
+
+	switch (codec[ft]) {
+	case 5: /* TCH/AHS7.95 */
+		if (len != 20)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 159);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 67, p);
+
+		tch_amr_merge(conv, d, p, 123, 67);
+
+		osmo_conv_encode(&gsm0503_tch_ahs_7_95, conv, cB + 4);
+
+		memcpy(cB + 192, d + 123, 36);
+
+		break;
+	case 4: /* TCH/AHS7.4 */
+		if (len != 19)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 148);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 61, p);
+
+		tch_amr_merge(conv, d, p, 120, 61);
+
+		osmo_conv_encode(&gsm0503_tch_ahs_7_4, conv, cB + 4);
+
+		memcpy(cB + 200, d + 120, 28);
+
+		break;
+	case 3: /* TCH/AHS6.7 */
+		if (len != 17)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 134);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p);
+
+		tch_amr_merge(conv, d, p, 110, 55);
+
+		osmo_conv_encode(&gsm0503_tch_ahs_6_7, conv, cB + 4);
+
+		memcpy(cB + 204, d + 110, 24);
+
+		break;
+	case 2: /* TCH/AHS5.9 */
+		if (len != 15)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 118);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 55, p);
+
+		tch_amr_merge(conv, d, p, 102, 55);
+
+		osmo_conv_encode(&gsm0503_tch_ahs_5_9, conv, cB + 4);
+
+		memcpy(cB + 212, d + 102, 16);
+
+		break;
+	case 1: /* TCH/AHS5.15 */
+		if (len != 13)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 103);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 49, p);
+
+		tch_amr_merge(conv, d, p, 91, 49);
+
+		osmo_conv_encode(&gsm0503_tch_ahs_5_15, conv, cB + 4);
+
+		memcpy(cB + 216, d + 91, 12);
+
+		break;
+	case 0: /* TCH/AHS4.75 */
+		if (len != 12)
+			goto invalid_length;
+
+		tch_amr_disassemble(d, tch_data, 95);
+
+		osmo_crc8gen_set_bits(&gsm0503_amr_crc6, d, 39, p);
+
+		tch_amr_merge(conv, d, p, 83, 39);
+
+		osmo_conv_encode(&gsm0503_tch_ahs_4_75, conv, cB + 4);
+
+		memcpy(cB + 216, d + 83, 12);
+
+		break;
+	default:
+		/* FIXME: FT %ft is not supported */
+		return -1;
+	}
+
+	memcpy(cB, gsm0503_afs_ic_ubit[id], 4);
+
+	gsm0503_tch_hr_interleave(cB, iB);
+
+	for (i = 0; i < 4; i++)
+		gsm0503_tch_burst_map(&iB[i * 114], &bursts[i * 116], &h, i >> 1);
+
+	return 0;
+
+invalid_length:
+	/* FIXME: payload length %len does not comply with codec type %ft */
+	return -1;
+}
+
+/*
+ * GSM RACH transcoding
+ */
+
+/*
+ * GSM RACH apply BSIC to parity
+ *
+ * p(j) = p(j) xor b(j)     j = 0, ..., 5
+ * b(0) = MSB of PLMN colour code
+ * b(5) = LSB of BS colour code
+ */
+
+static int rach_apply_bsic(ubit_t *d, uint8_t bsic)
+{
+	int i;
+
+	/* Apply it */
+	for (i = 0; i < 6; i++)
+		d[8 + i] ^= ((bsic >> (5 - i)) & 1);
+
+	return 0;
+}
+
+int gsm0503_rach_decode(uint8_t *ra, sbit_t *burst, uint8_t bsic)
+{
+	ubit_t conv[14];
+	int rv;
+
+	osmo_conv_decode(&gsm0503_rach, burst, conv);
+
+	rach_apply_bsic(conv, bsic);
+
+	rv = osmo_crc8gen_check_bits(&gsm0503_rach_crc6, conv, 8, conv + 8);
+	if (rv)
+		return -1;
+
+	osmo_ubit2pbit_ext(ra, 0, conv, 0, 8, 1);
+
+	return 0;
+}
+
+int gsm0503_rach_encode(ubit_t *burst, uint8_t *ra, uint8_t bsic)
+{
+	ubit_t conv[14];
+
+	osmo_pbit2ubit_ext(conv, 0, ra, 0, 8, 1);
+
+	osmo_crc8gen_set_bits(&gsm0503_rach_crc6, conv, 8, conv + 8);
+
+	rach_apply_bsic(conv, bsic);
+
+	osmo_conv_encode(&gsm0503_rach, conv, burst);
+
+	return 0;
+}
+
+
+/*
+ * GSM SCH transcoding
+ */
+
+int gsm0503_sch_decode(uint8_t *sb_info, sbit_t *burst)
+{
+	ubit_t conv[35];
+	int rv;
+
+	osmo_conv_decode(&gsm0503_sch, burst, conv);
+
+	rv = osmo_crc16gen_check_bits(&gsm0503_sch_crc10, conv, 25, conv + 25);
+	if (rv)
+		return -1;
+
+	osmo_ubit2pbit_ext(sb_info, 0, conv, 0, 25, 1);
+
+	return 0;
+}
+
+int gsm0503_sch_encode(ubit_t *burst, uint8_t *sb_info)
+{
+	ubit_t conv[35];
+
+	osmo_pbit2ubit_ext(conv, 0, sb_info, 0, 25, 1);
+
+	osmo_crc16gen_set_bits(&gsm0503_sch_crc10, conv, 25, conv + 25);
+
+	osmo_conv_encode(&gsm0503_sch, conv, burst);
+
+	return 0;
+}
diff --git a/src/gsm/gsm0503_conv_edge.c b/src/gsm/gsm0503_conv_edge.c
new file mode 100644
index 0000000..a542323
--- /dev/null
+++ b/src/gsm/gsm0503_conv_edge.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2016 Tom Tsou <tom.tsou at ettus.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdint.h>
+#include <osmocom/core/conv.h>
+
+static const uint8_t conv_mcs_next_output[][2] = {
+	{ 0, 7 }, { 3, 4 }, { 6, 1 }, { 5, 2 },
+	{ 6, 1 }, { 5, 2 }, { 0, 7 }, { 3, 4 },
+	{ 1, 6 }, { 2, 5 }, { 7, 0 }, { 4, 3 },
+	{ 7, 0 }, { 4, 3 }, { 1, 6 }, { 2, 5 },
+	{ 4, 3 }, { 7, 0 }, { 2, 5 }, { 1, 6 },
+	{ 2, 5 }, { 1, 6 }, { 4, 3 }, { 7, 0 },
+	{ 5, 2 }, { 6, 1 }, { 3, 4 }, { 0, 7 },
+	{ 3, 4 }, { 0, 7 }, { 5, 2 }, { 6, 1 },
+	{ 7, 0 }, { 4, 3 }, { 1, 6 }, { 2, 5 },
+	{ 1, 6 }, { 2, 5 }, { 7, 0 }, { 4, 3 },
+	{ 6, 1 }, { 5, 2 }, { 0, 7 }, { 3, 4 },
+	{ 0, 7 }, { 3, 4 }, { 6, 1 }, { 5, 2 },
+	{ 3, 4 }, { 0, 7 }, { 5, 2 }, { 6, 1 },
+	{ 5, 2 }, { 6, 1 }, { 3, 4 }, { 0, 7 },
+	{ 2, 5 }, { 1, 6 }, { 4, 3 }, { 7, 0 },
+	{ 4, 3 }, { 7, 0 }, { 2, 5 }, { 1, 6 },
+};
+
+static const uint8_t conv_mcs_next_state[][2] = {
+	{  0,  1 }, {  2,  3 }, {  4,  5 }, {  6,  7 },
+	{  8,  9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
+	{ 16, 17 }, { 18, 19 }, { 20, 21 }, { 22, 23 },
+	{ 24, 25 }, { 26, 27 }, { 28, 29 }, { 30, 31 },
+	{ 32, 33 }, { 34, 35 }, { 36, 37 }, { 38, 39 },
+	{ 40, 41 }, { 42, 43 }, { 44, 45 }, { 46, 47 },
+	{ 48, 49 }, { 50, 51 }, { 52, 53 }, { 54, 55 },
+	{ 56, 57 }, { 58, 59 }, { 60, 61 }, { 62, 63 },
+	{  0,  1 }, {  2,  3 }, {  4,  5 }, {  6,  7 },
+	{  8,  9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
+	{ 16, 17 }, { 18, 19 }, { 20, 21 }, { 22, 23 },
+	{ 24, 25 }, { 26, 27 }, { 28, 29 }, { 30, 31 },
+	{ 32, 33 }, { 34, 35 }, { 36, 37 }, { 38, 39 },
+	{ 40, 41 }, { 42, 43 }, { 44, 45 }, { 46, 47 },
+	{ 48, 49 }, { 50, 51 }, { 52, 53 }, { 54, 55 },
+	{ 56, 57 }, { 58, 59 }, { 60, 61 }, { 62, 63 },
+};
+
+
+const struct osmo_conv_code gsm0503_mcs1_dl_hdr = {
+	.N = 3,
+	.K = 7,
+	.len = 36,
+	.term = CONV_TERM_TAIL_BITING,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs1_ul_hdr = {
+	.N = 3,
+	.K = 7,
+	.len = 39,
+	.term = CONV_TERM_TAIL_BITING,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs1 = {
+	.N = 3,
+	.K = 7,
+	.len = 190,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs2 = {
+	.N = 3,
+	.K = 7,
+	.len = 238,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs3 = {
+	.N = 3,
+	.K = 7,
+	.len = 310,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs4 = {
+	.N = 3,
+	.K = 7,
+	.len = 366,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs5_dl_hdr = {
+	.N = 3,
+	.K = 7,
+	.len = 33,
+	.term = CONV_TERM_TAIL_BITING,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs5_ul_hdr = {
+	.N = 3,
+	.K = 7,
+	.len = 45,
+	.term = CONV_TERM_TAIL_BITING,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs5 = {
+	.N = 3,
+	.K = 7,
+	.len = 462,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs6 = {
+	.N = 3,
+	.K = 7,
+	.len = 606,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs7_dl_hdr = {
+	.N = 3,
+	.K = 7,
+	.len = 45,
+	.term = CONV_TERM_TAIL_BITING,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs7_ul_hdr = {
+	.N = 3,
+	.K = 7,
+	.len = 54,
+	.term = CONV_TERM_TAIL_BITING,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs7 = {
+	.N = 3,
+	.K = 7,
+	.len = 462,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs8 = {
+	.N = 3,
+	.K = 7,
+	.len = 558,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
+
+const struct osmo_conv_code gsm0503_mcs9 = {
+	.N = 3,
+	.K = 7,
+	.len = 606,
+	.next_output = conv_mcs_next_output,
+	.next_state  = conv_mcs_next_state,
+};
diff --git a/src/gsm/gsm0503_interleaving.c b/src/gsm/gsm0503_interleaving.c
new file mode 100644
index 0000000..0c1b8a0
--- /dev/null
+++ b/src/gsm/gsm0503_interleaving.c
@@ -0,0 +1,574 @@
+/* 
+ * (C) 2013 by Andreas Eversberg <jolly at eversberg.eu>
+ * (C) 2016 by Tom Tsou <tom.tsou at ettus.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/gsm/gsm0503_tables.h>
+#include <osmocom/gsm/gsm0503_interleaving.h>
+
+/*
+ * GSM xCCH interleaving and burst mapping
+ *
+ * Interleaving:
+ *
+ * Given 456 coded input bits, form 4 blocks of 114 bits:
+ *
+ *      i(B, j) = c(n, k)       k = 0, ..., 455
+ *                              n = 0, ..., N, N + 1, ...
+ *                              B = B_0 + 4n + (k mod 4)
+ *                              j = 2(49k mod 57) + ((k mod 8) div 4)
+ *
+ * Mapping on Burst:
+ *
+ *      e(B, j) = i(B, j)
+ *      e(B, 59 + j) = i(B, 57 + j)     j = 0, ..., 56
+ *      e(B, 57) = h_l(B)
+ *      e(B, 58) = h_n(B)
+ *
+ * Where hl(B) and hn(B) are bits in burst B indicating flags.
+ */
+
+void gsm0503_xcch_deinterleave(sbit_t *cB, const sbit_t *iB)
+{
+	int j, k, B;
+
+	for (k=0; k<456; k++) {
+		B = k & 3;
+		j = 2 * ((49 * k) % 57) + ((k & 7) >> 2);
+		cB[k] = iB[B * 114 + j];
+	}
+}
+
+void gsm0503_xcch_interleave(ubit_t *cB, ubit_t *iB)
+{
+	int j, k, B;
+
+	for (k=0; k<456; k++) {
+		B = k & 3;
+		j = 2 * ((49 * k) % 57) + ((k & 7) >> 2);
+		iB[B * 114 + j] = cB[k];
+	}
+}
+
+void gsm0503_mcs1_dl_deinterleave(sbit_t *u, sbit_t *hc,
+				  sbit_t *dc, const sbit_t *iB)
+{
+	int k;
+	sbit_t c[452];
+	sbit_t cp[456];
+
+	gsm0503_xcch_deinterleave(cp, iB);
+
+	for (k=0; k<25; k++)
+		c[k] = cp[k];
+	for (k=26; k<82; k++)
+		c[k - 1] = cp[k];
+	for (k=83; k<139; k++)
+		c[k - 2] = cp[k];
+	for (k=140; k<424; k++)
+		c[k - 3] = cp[k];
+	for (k=425; k<456; k++)
+		c[k - 4] = cp[k];
+
+	if (u) {
+		for (k=0; k<12; k++)
+			u[k] = c[k];
+	}
+
+	if (hc) {
+		for (k=12; k<80; k++)
+			hc[k - 12] = c[k];
+	}
+
+	if (dc) {
+		for (k=80; k<452; k++)
+			dc[k - 80] = c[k];
+	}
+}
+
+void gsm0503_mcs1_dl_interleave(const ubit_t *up, const ubit_t *hc,
+				const ubit_t *dc, ubit_t *iB)
+{
+	int k;
+	ubit_t c[452];
+	ubit_t cp[456];
+
+	for (k=0; k<12; k++)
+		c[k] = up[k];
+	for (k=12; k<80; k++)
+		c[k] = hc[k - 12];
+	for (k=80; k<452; k++)
+		c[k] = dc[k - 80];
+
+	for (k=0; k<25; k++)
+		cp[k] = c[k];
+	for (k=26; k<82; k++)
+		cp[k] = c[k - 1];
+	for (k=83; k<139; k++)
+		cp[k] = c[k - 2];
+	for (k=140; k<424; k++)
+		cp[k] = c[k - 3];
+	for (k=425; k<456; k++)
+		cp[k] = c[k - 4];
+
+	cp[25] = 0;
+	cp[82] = 0;
+	cp[139] = 0;
+	cp[424] = 0;
+
+	gsm0503_xcch_interleave(cp, iB);
+}
+
+void gsm0503_mcs1_ul_deinterleave(sbit_t *hc, sbit_t *dc, const sbit_t *iB)
+{
+	int k;
+	sbit_t c[452];
+	sbit_t cp[456];
+
+	gsm0503_xcch_deinterleave(cp, iB);
+
+	for (k=0; k<25; k++)
+		c[k] = cp[k];
+	for (k=26; k<82; k++)
+		c[k - 1] = cp[k];
+	for (k=83; k<139; k++)
+		c[k - 2] = cp[k];
+	for (k=140; k<424; k++)
+		c[k - 3] = cp[k];
+	for (k=425; k<456; k++)
+		c[k - 4] = cp[k];
+
+	if (hc) {
+		for (k=0; k<80; k++)
+			hc[k] = c[k];
+	}
+
+	if (dc) {
+		for (k=80; k<452; k++)
+			dc[k - 80] = c[k];
+	}
+}
+
+void gsm0503_mcs1_ul_interleave(const ubit_t *hc, const ubit_t *dc, ubit_t *iB)
+{
+	int k;
+	ubit_t c[452];
+	ubit_t cp[456];
+
+	for (k=0; k<80; k++)
+		c[k] = hc[k];
+	for (k=80; k<452; k++)
+		c[k] = dc[k - 80];
+
+	for (k=0; k<25; k++)
+		cp[k] = c[k];
+	for (k=26; k<82; k++)
+		cp[k] = c[k - 1];
+	for (k=83; k<139; k++)
+		cp[k] = c[k - 2];
+	for (k=140; k<424; k++)
+		cp[k] = c[k - 3];
+	for (k=425; k<456; k++)
+		cp[k] = c[k - 4];
+
+	cp[25] = 0;
+	cp[82] = 0;
+	cp[139] = 0;
+	cp[424] = 0;
+
+	gsm0503_xcch_interleave(cp, iB);
+}
+
+void gsm0503_mcs5_ul_interleave(const ubit_t *hc, const ubit_t *dc,
+				ubit_t *hi, ubit_t *di)
+{
+	int j, k;
+
+	/* Header */
+	for (k=0; k<136; k++) {
+		j = 34 * (k % 4) + 2 * (11 * k % 17) + k % 8 / 4;
+		hi[j] = hc[k];
+	}
+
+	/* Data */
+	for (k=0; k<1248; k++) {
+		j = gsm0503_interleave_mcs5[k];
+		di[j] = dc[k];
+	}
+}
+
+void gsm0503_mcs5_ul_deinterleave(sbit_t *hc, sbit_t *dc,
+				  const sbit_t *hi, const sbit_t *di)
+{
+	int j, k;
+
+	/* Header */
+	if (hc) {
+		for (k=0; k<136; k++) {
+			j = 34 * (k % 4) + 2 * (11 * k % 17) + k % 8 / 4;
+			hc[k] = hi[j];
+		}
+	}
+
+	/* Data */
+	if (dc) {
+		for (k=0; k<1248; k++) {
+			j = gsm0503_interleave_mcs5[k];
+			dc[k] = di[j];
+		}
+	}
+}
+
+void gsm0503_mcs5_dl_interleave(const ubit_t *hc, const ubit_t *dc,
+				ubit_t *hi, ubit_t *di)
+{
+	int j, k;
+
+	/* Header */
+	for (k=0; k<100; k++) {
+		j = 25 * (k % 4) + ((17 * k) % 25);
+		hi[j] = hc[k];
+	}
+
+	/* Data */
+	for (k=0; k<1248; k++) {
+		j = gsm0503_interleave_mcs5[k];
+		di[j] = dc[k];
+	}
+}
+
+void gsm0503_mcs5_dl_deinterleave(sbit_t *hc, sbit_t *dc,
+				  const sbit_t *hi, const sbit_t *di)
+{
+	int j, k;
+
+	/* Header */
+	if (hc) {
+		for (k=0; k<100; k++) {
+			j = 25 * (k % 4) + ((17 * k) % 25);
+			hc[k] = hi[j];
+		}
+	}
+
+	/* Data */
+	if (dc) {
+		for (k=0; k<1248; k++) {
+			j = gsm0503_interleave_mcs5[k];
+			dc[k] = di[j];
+		}
+	}
+}
+
+void gsm0503_mcs7_dl_interleave(const ubit_t *hc, const ubit_t *c1,
+				const ubit_t *c2, ubit_t *hi, ubit_t *di)
+{
+	int j, k;
+	ubit_t dc[1224];
+
+	/* Header */
+	for (k=0; k<124; k++) {
+		j = 31 * (k % 4) + ((17 * k) % 31);
+		hi[j] = hc[k];
+	}
+
+	memcpy(&dc[0], c1, 612);
+	memcpy(&dc[612], c2, 612);
+
+	/* Data */
+	for (k=0; k<1224; k++) {
+		j = 306 * (k % 4) + 3 * (44 * k % 102 + k / 4 % 2) +
+		    (k + 2 - k / 408) % 3;
+		di[j] = dc[k];
+	}
+}
+
+
+void gsm0503_mcs7_dl_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
+				  const sbit_t *hi, const sbit_t *di)
+{
+	int j, k;
+	ubit_t dc[1224];
+
+	/* Header */
+	if (hc) {
+		for (k=0; k<124; k++) {
+			j = 31 * (k % 4) + ((17 * k) % 31);
+			hc[k] = hi[j];
+		}
+	}
+
+	/* Data */
+	if (c1 && c2) {
+		for (k=0; k<1224; k++) {
+			j = 306 * (k % 4) + 3 * (44 * k % 102 + k / 4 % 2) +
+			    (k + 2 - k / 408) % 3;
+			dc[k] = di[j];
+		}
+
+		memcpy(c1, &dc[0], 612);
+		memcpy(c2, &dc[612], 612);
+	}
+}
+
+void gsm0503_mcs7_ul_interleave(const ubit_t *hc, const ubit_t *c1,
+				const ubit_t *c2, ubit_t *hi, ubit_t *di)
+{
+	int j, k;
+	ubit_t dc[1224];
+
+	/* Header */
+	for (k=0; k<160; k++) {
+		j = 40 * (k % 4) + 2 * (13 * (k / 8) % 20) + k % 8 / 4;
+		hi[j] = hc[k];
+	}
+
+	memcpy(&dc[0], c1, 612);
+	memcpy(&dc[612], c2, 612);
+
+	/* Data */
+	for (k=0; k<1224; k++) {
+		j = 306 * (k % 4) + 3 * (44 * k % 102 + k / 4 % 2) +
+		    (k + 2 - k / 408) % 3;
+		di[j] = dc[k];
+	}
+}
+
+void gsm0503_mcs7_ul_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
+				  const sbit_t *hi, const sbit_t *di)
+{
+	int j, k;
+	ubit_t dc[1224];
+
+	/* Header */
+	if (hc) {
+		for (k=0; k<160; k++) {
+			j = 40 * (k % 4) + 2 * (13 * (k / 8) % 20) + k % 8 / 4;
+			hc[k] = hi[j];
+		}
+	}
+
+	/* Data */
+	if (c1 && c2) {
+		for (k=0; k<1224; k++) {
+			j = 306 * (k % 4) + 3 * (44 * k % 102 + k / 4 % 2) +
+			    (k + 2 - k / 408) % 3;
+			dc[k] = di[j];
+		}
+
+		memcpy(c1, &dc[0], 612);
+		memcpy(c2, &dc[612], 612);
+	}
+}
+
+void gsm0503_mcs8_ul_interleave(const ubit_t *hc, const ubit_t *c1,
+				const ubit_t *c2, ubit_t *hi, ubit_t *di)
+{
+	int j, k;
+	ubit_t dc[1224];
+
+	/* Header */
+	for (k=0; k<160; k++) {
+		j = 40 * (k % 4) + 2 * (13 * (k / 8) % 20) + k % 8 / 4;
+		hi[j] = hc[k];
+	}
+
+	memcpy(&dc[0], c1, 612);
+	memcpy(&dc[612], c2, 612);
+
+	/* Data */
+	for (k=0; k<1224; k++) {
+		j = 306 * (2 * (k / 612) + (k % 2)) +
+		    3 * (74 * k % 102 + k / 2 % 2) + (k + 2 - k / 204) % 3;
+		di[j] = dc[k];
+	}
+}
+
+void gsm0503_mcs8_ul_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
+				  const sbit_t *hi, const sbit_t *di)
+{
+	int j, k;
+	ubit_t dc[1224];
+
+	/* Header */
+	if (hc) {
+		for (k=0; k<160; k++) {
+			j = 40 * (k % 4) + 2 * (13 * (k / 8) % 20) + k % 8 / 4;
+			hc[k] = hi[j];
+		}
+	}
+
+	/* Data */
+	if (c1 && c2) {
+		for (k=0; k<1224; k++) {
+			j = 306 * (2 * (k / 612) + (k % 2)) +
+			    3 * (74 * k % 102 + k / 2 % 2) + (k + 2 - k / 204) % 3;
+			dc[k] = di[j];
+		}
+
+		memcpy(c1, &dc[0], 612);
+		memcpy(c2, &dc[612], 612);
+	}
+}
+
+void gsm0503_mcs8_dl_interleave(const ubit_t *hc, const ubit_t *c1,
+				const ubit_t *c2, ubit_t *hi, ubit_t *di)
+{
+	int j, k;
+	ubit_t dc[1224];
+
+	/* Header */
+	for (k=0; k<124; k++) {
+		j = 31 * (k % 4) + ((17 * k) % 31);
+		hi[j] = hc[k];
+	}
+
+	memcpy(&dc[0], c1, 612);
+	memcpy(&dc[612], c2, 612);
+
+	/* Data */
+	for (k=0; k<1224; k++) {
+		j = 306 * (2 * (k / 612) + (k % 2)) +
+		    3 * (74 * k % 102 + k / 2 % 2) + (k + 2 - k / 204) % 3;
+		di[j] = dc[k];
+	}
+}
+
+void gsm0503_mcs8_dl_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
+				  const sbit_t *hi, const sbit_t *di)
+{
+	int j, k;
+	ubit_t dc[1224];
+
+	/* Header */
+	if (hc) {
+		for (k=0; k<124; k++) {
+			j = 31 * (k % 4) + ((17 * k) % 31);
+			hc[k] = hi[j];
+		}
+	}
+
+	/* Data */
+	if (c1 && c2) {
+		for (k=0; k<1224; k++) {
+			j = 306 * (2 * (k / 612) + (k % 2)) +
+			    3 * (74 * k % 102 + k / 2 % 2) + (k + 2 - k / 204) % 3;
+			dc[k] = di[j];
+		}
+
+		memcpy(c1, &dc[0], 612);
+		memcpy(c2, &dc[612], 612);
+	}
+}
+
+/*
+ * GSM TCH FR/EFR/AFS interleaving and burst mapping
+ *
+ * Interleaving:
+ *
+ * Given 456 coded input bits, form 8 blocks of 114 bits,
+ * where even bits of the first 4 blocks and odd bits of the last 4 blocks
+ * are used:
+ *
+ *      i(B, j) = c(n, k)       k = 0, ..., 455
+ *                              n = 0, ..., N, N + 1, ...
+ *                              B = B_0 + 4n + (k mod 8)
+ *                              j = 2(49k mod 57) + ((k mod 8) div 4)
+ *
+ * Mapping on Burst:
+ *
+ *      e(B, j) = i(B, j)
+ *      e(B, 59 + j) = i(B, 57 + j)     j = 0, ..., 56
+ *      e(B, 57) = h_l(B)
+ *      e(B, 58) = h_n(B)
+ *
+ * Where hl(B) and hn(B) are bits in burst B indicating flags.
+ */
+
+void gsm0503_tch_fr_deinterleave(sbit_t *cB, sbit_t *iB)
+{
+	int j, k, B;
+
+	for (k=0; k<456; k++) {
+		B = k & 7;
+		j = 2 * ((49 * k) % 57) + ((k & 7) >> 2);
+		cB[k] = iB[B * 114 + j];
+	}
+}
+
+void gsm0503_tch_fr_interleave(ubit_t *cB, ubit_t *iB)
+{
+	int j, k, B;
+
+	for (k=0; k<456; k++) {
+		B = k & 7;
+		j = 2 * ((49 * k) % 57) + ((k & 7) >> 2);
+		iB[B * 114 + j] = cB[k];
+	}
+}
+
+/*
+ * GSM TCH HR/AHS interleaving and burst mapping
+ *
+ * Interleaving:
+ *
+ * Given 288 coded input bits, form 4 blocks of 114 bits,
+ * where even bits of the first 2 blocks and odd bits of the last 2 blocks
+ * are used:
+ *
+ *      i(B, j) = c(n, k)       k = 0, ..., 227
+ *                              n = 0, ..., N, N + 1, ...
+ *                              B = B_0 + 2n + b
+ *                              j, b = table[k];
+ *
+ * Mapping on Burst:
+ *
+ *      e(B, j) = i(B, j)
+ *      e(B, 59 + j) = i(B, 57 + j)     j = 0, ..., 56
+ *      e(B, 57) = h_l(B)
+ *      e(B, 58) = h_n(B)
+ *
+ * Where hl(B) and hn(B) are bits in burst B indicating flags.
+ */
+
+void gsm0503_tch_hr_deinterleave(sbit_t *cB, sbit_t *iB)
+{
+	int j, k, B;
+
+	for (k=0; k<228; k++) {
+		B = gsm0503_tch_hr_interleaving[k][1];
+		j = gsm0503_tch_hr_interleaving[k][0];
+		cB[k] = iB[B * 114 + j];
+	}
+}
+
+void gsm0503_tch_hr_interleave(ubit_t *cB, ubit_t *iB)
+{
+	int j, k, B;
+
+	for (k=0; k<228; k++) {
+		B = gsm0503_tch_hr_interleaving[k][1];
+		j = gsm0503_tch_hr_interleaving[k][0];
+		iB[B * 114 + j] = cB[k];
+	}
+}
+
diff --git a/src/gsm/gsm0503_mapping.c b/src/gsm/gsm0503_mapping.c
new file mode 100644
index 0000000..c2079b9
--- /dev/null
+++ b/src/gsm/gsm0503_mapping.c
@@ -0,0 +1,291 @@
+/* 
+ * (C) 2013 by Andreas Eversberg <jolly at eversberg.eu>
+ * (C) 2016 by Tom Tsou <tom.tsou at ettus.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/gsm/gsm0503_mapping.h>
+
+void gsm0503_xcch_burst_unmap(sbit_t *iB, const sbit_t *eB,
+			      sbit_t *hl, sbit_t *hn)
+{
+	memcpy(iB,    eB,    57);
+	memcpy(iB+57, eB+59, 57);
+
+	if (hl)
+		*hl = eB[57];
+
+	if (hn)
+		*hn = eB[58];
+}
+
+void gsm0503_xcch_burst_map(ubit_t *iB, ubit_t *eB, const ubit_t *hl,
+	const ubit_t *hn)
+{
+	memcpy(eB,    iB,    57);
+	memcpy(eB+59, iB+57, 57);
+
+	if (hl)
+		eB[57] = *hl;
+	if (hn)
+		eB[58] = *hn;
+}
+
+void gsm0503_tch_burst_unmap(sbit_t *iB, sbit_t *eB, sbit_t *h, int odd)
+{
+	int i;
+
+	/* brainfuck: only copy even or odd bits */
+	if (iB) {
+		for (i=odd; i<57; i+=2)
+			iB[i] = eB[i];
+		for (i=58-odd; i<114; i+=2)
+			iB[i] = eB[i+2];
+	}
+
+	if (h) {
+		if (!odd)
+			*h = eB[58];
+		else
+			*h = eB[57];
+	}
+}
+
+void gsm0503_tch_burst_map(ubit_t *iB, ubit_t *eB, const ubit_t *h, int odd)
+{
+	int i;
+
+	/* brainfuck: only copy even or odd bits */
+	if (eB) {
+		for (i=odd; i<57; i+=2)
+			eB[i] = iB[i];
+		for (i=58-odd; i<114; i+=2)
+			eB[i+2] = iB[i];
+	}
+
+	if (h) {
+		if (!odd)
+			eB[58] = *h;
+		else
+			eB[57] = *h;
+	}
+}
+
+void gsm0503_mcs5_dl_burst_map(const ubit_t *di, ubit_t *eB,
+			       const ubit_t *hi, const ubit_t *up, int B)
+{
+	int j;
+	int q[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
+
+	for (j=0; j<156; j++)
+		eB[j] = di[312*B+j];
+	for (j=156; j<168; j++)
+		eB[j] = hi[25*B+j-156];
+	for (j=168; j<174; j++)
+		eB[j] = up[9*B+j-168];
+	for (j=174; j<176; j++)
+		eB[j] = q[2*B+j-174];
+	for (j=176; j<179; j++)
+		eB[j] = up[9*B+j-170];
+	for (j=179; j<192; j++)
+		eB[j] = hi[25*B+j-167];
+	for (j=192; j<348; j++)
+		eB[j] = di[312*B+j-36];
+}
+
+void gsm0503_mcs5_dl_burst_unmap(sbit_t *di, const sbit_t *eB,
+			         sbit_t *hi, sbit_t *up, int B)
+{
+	int j;
+
+	for (j=0; j<156; j++)
+		di[312*B+j] = eB[j];
+	for (j=156; j<168; j++)
+		hi[25*B+j-156] = eB[j];
+	for (j=168; j<174; j++)
+		up[9*B+j-168] = eB[j];
+
+	for (j=176; j<179; j++)
+		up[9*B+j-170] = eB[j];
+	for (j=179; j<192; j++)
+		hi[25*B+j-167] = eB[j];
+	for (j=192; j<348; j++)
+		di[312*B+j-36] = eB[j];
+}
+
+void gsm0503_mcs5_ul_burst_map(const ubit_t *di, ubit_t *eB,
+			       const ubit_t *hi, int B)
+{
+	int j;
+
+	for (j=0; j<156; j++)
+		eB[j] = di[312*B+j];
+	for (j=156; j<174; j++)
+		eB[j] = hi[34*B+j-156];
+	for (j=174; j<176; j++)
+		eB[j] = 0;
+	for (j=176; j<192; j++)
+		eB[j] = hi[34*B+j-158];
+	for (j=192; j<348; j++)
+		eB[j] = di[312*B+j-36];
+}
+
+void gsm0503_mcs5_ul_burst_unmap(sbit_t *di, const sbit_t *eB,
+			         sbit_t *hi, int B)
+{
+	int j;
+
+	for (j=0; j<156; j++)
+		di[312*B+j] = eB[j];
+	for (j=156; j<174; j++)
+		hi[34*B+j-156] = eB[j];
+	for (j=176; j<192; j++)
+		hi[34*B+j-158] = eB[j];
+	for (j=192; j<348; j++)
+		di[312*B+j-36] = eB[j];
+}
+
+void gsm0503_mcs7_dl_burst_map(const ubit_t *di, ubit_t *eB,
+			       const ubit_t *hi, const ubit_t *up, int B)
+{
+	int j;
+	int q[8] = { 1, 1, 1, 0, 0, 1, 1, 1, };
+
+	for (j=0; j<153; j++)
+		eB[j] = di[306*B+j];
+	for (j=153; j<168; j++)
+		eB[j] = hi[31*B+j-153];
+	for (j=168; j<174; j++)
+		eB[j] = up[9*B+j-168];
+	for (j=174; j<176; j++)
+		eB[j] = q[2*B+j-174];
+	for (j=176; j<179; j++)
+		eB[j] = up[9*B+j-170];
+	for (j=179; j<195; j++)
+		eB[j] = hi[31*B+j-164];
+	for (j=195; j<348; j++)
+		eB[j] = di[306*B+j-42];
+}
+
+void gsm0503_mcs7_dl_burst_unmap(sbit_t *di, const sbit_t *eB,
+			         sbit_t *hi, sbit_t *up, int B)
+{
+	int j;
+
+	for (j=0; j<153; j++)
+		di[306*B+j] = eB[j];
+	for (j=153; j<168; j++)
+		hi[31*B+j-153] = eB[j];
+	for (j=168; j<174; j++)
+		up[9*B+j-168] = eB[j];
+
+	for (j=176; j<179; j++)
+		up[9*B+j-170] = eB[j];
+	for (j=179; j<195; j++)
+		hi[31*B+j-164] = eB[j];
+	for (j=195; j<348; j++)
+		di[306*B+j-42] = eB[j];
+}
+
+void gsm0503_mcs7_ul_burst_map(const ubit_t *di, ubit_t *eB,
+			       const ubit_t *hi, int B)
+{
+	int j;
+	int q[8] = { 1, 1, 1, 0, 0, 1, 1, 1, };
+
+	for (j=0; j<153; j++)
+		eB[j] = di[306*B+j];
+	for (j=153; j<174; j++)
+		eB[j] = hi[40*B+j-153];
+	for (j=174; j<176; j++)
+		eB[j] = q[2*B+j-174];
+	for (j=176; j<195; j++)
+		eB[j] = hi[40*B+j-155];
+	for (j=195; j<348; j++)
+		eB[j] = di[306*B+j-42];
+}
+
+void gsm0503_mcs7_ul_burst_unmap(sbit_t *di, const sbit_t *eB,
+			         sbit_t *hi, int B)
+{
+	int j;
+
+	for (j=0; j<153; j++)
+		di[306*B+j] = eB[j];
+	for (j=153; j<174; j++)
+		hi[40*B+j-153] = eB[j];
+
+	for (j=176; j<195; j++)
+		hi[40*B+j-155] = eB[j];
+	for (j=195; j<348; j++)
+		di[306*B+j-42] = eB[j];
+}
+
+void gsm0503_mcs5_burst_swap(sbit_t *eB)
+{
+	sbit_t t[14];
+
+	t[0]  = eB[155];
+	t[1]  = eB[158];
+	t[2]  = eB[161];
+	t[3]  = eB[164];
+	t[4]  = eB[167];
+	t[5]  = eB[170];
+	t[6]  = eB[173];
+	t[7]  = eB[195];
+	t[8]  = eB[196];
+	t[9]  = eB[198];
+	t[10] = eB[199];
+	t[11] = eB[201];
+	t[12] = eB[202];
+	t[13] = eB[204];
+
+	eB[155] = eB[142];
+	eB[158] = eB[144];
+	eB[161] = eB[145];
+	eB[164] = eB[147];
+	eB[167] = eB[148];
+	eB[170] = eB[150];
+	eB[173] = eB[151];
+	eB[195] = eB[176];
+	eB[196] = eB[179];
+	eB[198] = eB[182];
+	eB[199] = eB[185];
+	eB[201] = eB[188];
+	eB[202] = eB[191];
+	eB[204] = eB[194];
+
+	eB[142] = t[0];
+	eB[144] = t[1];
+	eB[145] = t[2];
+	eB[147] = t[3];
+	eB[148] = t[4];
+	eB[150] = t[5];
+	eB[151] = t[6];
+	eB[176] = t[7];
+	eB[179] = t[8];
+	eB[182] = t[9];
+	eB[185] = t[10];
+	eB[188] = t[11];
+	eB[191] = t[12];
+	eB[194] = t[13];
+}
diff --git a/src/gsm/gsm0503_parity.c b/src/gsm/gsm0503_parity.c
new file mode 100644
index 0000000..c9cfba4
--- /dev/null
+++ b/src/gsm/gsm0503_parity.c
@@ -0,0 +1,145 @@
+/* 
+ * (C) 2013 by Andreas Eversberg <jolly at eversberg.eu>
+ * (C) 2016 by Tom Tsou <tom.tsou at ettus.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+
+#include <osmocom/core/crcgen.h>
+#include <osmocom/gsm/gsm0503_parity.h>
+
+/*
+ * GSM (SACCH) parity (FIRE code)
+ *
+ * g(x) = (x^23 + 1)(x^17 + x^3 + 1)
+ *      = x^40 + x^26 + x^23 + x^17 + x^3 + a1
+ */
+
+const struct osmo_crc64gen_code gsm0503_fire_crc40 = {
+	.bits = 40,
+	.poly = 0x0004820009ULL,
+	.init = 0x0000000000ULL,
+	.remainder = 0xffffffffffULL,
+};
+
+
+/*
+ * GSM PDTCH CS-2, CS-3, CS-4 parity
+ *
+ * g(x) = x^16 + x^12 + x^5 + 1
+ */
+
+const struct osmo_crc16gen_code gsm0503_cs234_crc16 = {
+	.bits = 16,
+	.poly = 0x1021,
+	.init = 0x0000,
+	.remainder = 0xffff,
+};
+
+/*
+ * EDGE MCS header parity
+ *
+ */
+
+const struct osmo_crc8gen_code gsm0503_mcs_crc8_hdr = {
+	.bits = 8,
+	.poly = 0x49,
+	.init = 0x00,
+	.remainder = 0xff,
+};
+
+/*
+ * EDGE MCS data parity
+ *
+ */
+
+const struct osmo_crc16gen_code gsm0503_mcs_crc12 = {
+	.bits = 12,
+	.poly = 0x0d31,
+	.init = 0x0000,
+	.remainder = 0x0fff,
+};
+
+/*
+ * GSM RACH parity
+ *
+ * g(x) = x^6 + x^5 + x^3 + x^2 + x^1 + 1
+ */
+
+const struct osmo_crc8gen_code gsm0503_rach_crc6 = {
+	.bits = 6,
+	.poly = 0x2f,
+	.init = 0x00,
+	.remainder = 0x3f,
+};
+
+
+/*
+ * GSM SCH parity
+ *
+ * g(x) = x^10 + x^8 + x^6 + x^5 + x^4 + x^2 + 1
+ */
+
+const struct osmo_crc16gen_code gsm0503_sch_crc10 = {
+	.bits = 10,
+	.poly = 0x175,
+	.init = 0x000,
+	.remainder = 0x3ff,
+};
+
+
+/*
+ * GSM TCH FR/HR/EFR parity
+ *
+ * g(x) = x^3 + x + 1
+ */
+
+const struct osmo_crc8gen_code gsm0503_tch_fr_crc3 = {
+	.bits = 3,
+	.poly = 0x3,
+	.init = 0x0,
+	.remainder = 0x7,
+};
+
+/*
+ * GSM TCH EFR parity
+ *
+ * g(x) = x^8 + x^4 + x^3 + x^2 + 1
+ */
+
+const struct osmo_crc8gen_code gsm0503_tch_efr_crc8 = {
+	.bits = 8,
+	.poly = 0x1d,
+	.init = 0x00,
+	.remainder = 0x00,
+};
+
+/*
+ * GSM AMR parity
+ *
+ * g(x) = x^6 + x^5 + x^3 + x^2 + x^1 + 1
+ */
+
+const struct osmo_crc8gen_code gsm0503_amr_crc6 = {
+	.bits = 6,
+	.poly = 0x2f,
+	.init = 0x00,
+	.remainder = 0x3f,
+};
+
diff --git a/src/gsm/gsm0503_tables.c b/src/gsm/gsm0503_tables.c
new file mode 100644
index 0000000..95132b1
--- /dev/null
+++ b/src/gsm/gsm0503_tables.c
@@ -0,0 +1,1732 @@
+/* 
+ * (C) 2013 by Andreas Eversberg <jolly at eversberg.eu>
+ * (C) 2016 by Tom Tsou <tom.tsou at ettus.com>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/gsm/gsm0503_tables.h>
+
+const ubit_t gsm0503_pdtch_hl_hn_ubit[4][8] = {
+	{ 1,1, 1,1, 1,1, 1,1 },
+	{ 1,1, 0,0, 1,0, 0,0 },
+	{ 0,0, 1,0, 0,0, 0,1 },
+	{ 0,0, 0,1, 0,1, 1,0 },
+};
+
+const ubit_t gsm0503_pdtch_edge_hl_hn_ubit[3][8] = {
+	{ 0,0, 0,1, 0,1, 1,0 },
+	{ 0,0, 0,0, 0,0, 0,0 },
+	{ 1,1, 1,0, 0,1, 1,1 },
+};
+
+const sbit_t gsm0503_pdtch_hl_hn_sbit[4][8] = {
+	{ -127,-127, -127,-127, -127,-127, -127,-127 },
+	{ -127,-127,  127, 127, -127, 127,  127, 127 },
+	{  127, 127, -127, 127,  127, 127,  127,-127 },
+	{  127, 127,  127,-127,  127,-127, -127, 127 },
+};
+
+const sbit_t gsm0503_pdtch_edge_hl_hn_sbit[3][8] = {
+	{  127, 127,  127,-127,  127,-127, -127, 127 },
+	{  127, 127,  127, 127,  127, 127,  127, 127 },
+	{ -127,-127, -127, 127,  127,-127, -127,-127 },
+};
+
+const ubit_t gsm0503_usf2six[8][6] = {
+	{ 0,0,0, 0,0,0 },
+	{ 1,0,0, 1,0,1 },
+	{ 0,1,0, 1,1,0 },
+	{ 1,1,0, 0,1,1 },
+	{ 0,0,1, 0,1,1 },
+	{ 1,0,1, 1,1,0 },
+	{ 0,1,1, 1,0,1 },
+	{ 1,1,1, 0,0,0 },
+};
+
+const ubit_t gsm0503_usf2twelve_ubit[8][12] = {
+	{ 0,0,0, 0,0,0, 0,0,0, 0,0,0 },
+	{ 1,1,0, 1,0,0, 0,0,1, 0,1,1 },
+	{ 0,0,1, 1,0,1, 1,1,0, 1,1,0 },
+	{ 1,1,1, 0,0,1, 1,1,1, 1,0,1 },
+	{ 0,0,0, 0,1,1, 0,1,1, 1,0,1 },
+	{ 1,1,0, 1,1,1, 0,1,0, 1,1,0 },
+	{ 0,0,1, 1,1,0, 1,0,1, 0,1,1 },
+	{ 1,1,1, 0,1,0, 1,0,0, 0,0,0 },
+};
+
+const sbit_t gsm0503_usf2twelve_sbit[8][12] = {
+	{  127, 127, 127,  127, 127, 127,  127, 127, 127,  127, 127, 127 },
+	{ -127,-127, 127, -127, 127, 127,  127, 127,-127,  127,-127,-127 },
+	{  127, 127,-127, -127, 127,-127, -127,-127, 127, -127,-127, 127 },
+	{ -127,-127,-127,  127, 127,-127, -127,-127,-127, -127, 127,-127 },
+	{  127, 127, 127,  127,-127,-127,  127,-127,-127, -127, 127,-127 },
+	{ -127,-127, 127, -127,-127,-127,  127,-127, 127, -127,-127, 127 },
+	{  127, 127,-127, -127,-127, 127, -127, 127,-127,  127,-127,-127 },
+	{ -127,-127,-127,  127,-127, 127, -127, 127, 127,  127, 127, 127 },
+};
+
+const uint8_t gsm0503_puncture_cs2[588] = {
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,0, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,0, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,0, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,0, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,0, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,0, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0, 0,0,0,1, 0,0,0,1,
+	0,0,0,1, 0,0,0,1, 0,0,0,1
+};
+
+const uint8_t gsm0503_puncture_cs3[676] = {
+	0,0,0,0,0,0, 0,0,0,0,0,0, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,1,0,1,
+	0,0,0,1,0,1, 0,0,0,1,0,1, 0,0,0,0
+};
+
+const uint8_t gsm0503_puncture_mcs1_dl_hdr[108] = {
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,1,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,1,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,1,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,1,1,
+};
+
+const uint8_t gsm0503_puncture_mcs1_ul_hdr[117] = {
+	0,0,0,0,0,1,0,0,1,0,0,1,
+	0,0,0,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,
+};
+
+const uint8_t gsm0503_puncture_mcs1_p1[588] = {
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,0,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+	0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,
+};
+
+const uint8_t gsm0503_puncture_mcs1_p2[588] = {
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+	0,1,0,0,1,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,
+};
+
+const uint8_t gsm0503_puncture_mcs2_p1[732] = {
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,0,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,0,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,0,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,0,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,0,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,0,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0, 0,0,1,1,1,0,
+	0,0,1,1,1,0, 0,0,1,1,1,0,
+};
+
+const uint8_t gsm0503_puncture_mcs2_p2[732] = {
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 0,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 0,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 0,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	0,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 0,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 0,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1, 1,1,0,0,0,1,
+	1,1,0,0,0,1, 1,1,0,0,0,1,
+};
+
+const uint8_t gsm0503_puncture_mcs3_p1[948] = {
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,
+	0,0,1,0,1,1,0,1,1,1,0,1,
+};
+
+const uint8_t gsm0503_puncture_mcs3_p2[948] = {
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,
+};
+
+const uint8_t gsm0503_puncture_mcs3_p3[948] = {
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,
+};
+
+const uint8_t gsm0503_puncture_mcs4_p1[1116] = {
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1,
+};
+
+const uint8_t gsm0503_puncture_mcs4_p2[1116] = {
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1,
+};
+
+const uint8_t gsm0503_puncture_mcs4_p3[1116] = {
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0,
+};
+
+const uint8_t gsm0503_puncture_mcs5_p1[1404] = {
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0, 0,0,1,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0, 0,0,1,0,0,1,0,0,1, 0,0,1,0,0,1,0,0,1,
+};
+
+const uint8_t gsm0503_puncture_mcs5_p2[1404] = {
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0, 0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0, 0,1,0,0,1,0,0,1,0, 0,1,0,0,1,0,0,1,0,
+};
+
+const uint8_t gsm0503_puncture_mcs6_p1[1836] = {
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,0, 0,0,1, 0,0,1, 0,0,1, 0,0,1, 0,0,1,
+	0,0,1, 0,0,1,
+};
+
+const uint8_t gsm0503_puncture_mcs6_p2[1836] = {
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,0,0,
+	0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,1,0,
+	0,1,0, 0,1,0,
+};
+
+const uint8_t gsm0503_puncture_mcs7_dl_hdr[135] = {
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,1,0,0,0,0,0,
+	0,0,0,1,0,0,0,0,0,0,
+	0,0,0,1,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	1,0,0,0,0,0,0,0,0,1,
+	0,0,0,0,0,0,0,0,0,1,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,1,0,0,0,
+	0,0,0,0,0,1,0,0,0,0,
+	0,0,0,0,0,1,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,1,0,0,0,0,0,0,0,
+	0,1,0,0,0,
+};
+
+const uint8_t gsm0503_puncture_mcs7_ul_hdr[162] = {
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,1,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,1,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,
+	0,0,
+};
+
+const uint8_t gsm0503_puncture_mcs7_p1[1404] = {
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+	0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,
+};
+
+const uint8_t gsm0503_puncture_mcs7_p2[1404] = {
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0,
+	1,1,0,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0,
+};
+
+const uint8_t gsm0503_puncture_mcs7_p3[1404] = {
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,0,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+	1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,0,1,
+};
+
+const uint8_t gsm0503_puncture_mcs8_p1[1692] = {
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+	0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,
+};
+
+const uint8_t gsm0503_puncture_mcs8_p2[1692] = {
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,0,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+	1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,
+};
+
+const uint8_t gsm0503_puncture_mcs8_p3[1692] = {
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,0,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+	1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,0,1,
+};
+
+const uint8_t gsm0503_puncture_mcs9_p1[1836] = {
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+	0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1, 0,1,1,
+};
+
+const uint8_t gsm0503_puncture_mcs9_p2[1836] = {
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+	1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
+};
+
+const uint8_t gsm0503_puncture_mcs9_p3[1836] = {
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+	1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0, 1,1,0,
+};
+
+const uint16_t gsm0503_interleave_mcs5[1248] = {
+	   0,  463,  890, 1038,  220,  371,  795,  946,  582,  733, 1160,   63,  490,  641, 277,  428,
+	 852, 1003,  185,  333, 1223,  120,  547,  698, 1122,   28,  915, 1066,  242,  390, 817,  968,
+	 610,  761, 1185,   85,  512,  660,  305,  453,  880, 1031,  204,  355,  782, 1242, 148,  575,
+	 723, 1150,   50,  474,  625, 1088,  267,  418,  845,  993,  169,  320, 1207,  113, 537,  688,
+	1115,   12,  902, 1050,  232,  383,  807,  958,  594,  745, 1172,   75,  502,  653, 289,  440,
+	 864, 1015,  197,  345, 1235,  132,  559,  710, 1134,   40,  927, 1078,  254,  402, 829,  980,
+	 159,  622,  773, 1197,   97,  524,  672, 1099,    5,  465,  892, 1043,  216,  367, 794,  942,
+	 587,  735, 1162,   62,  486,  637,  279,  430,  857, 1005,  181,  332, 1219,  125, 549,  700,
+	1127,   24,  914, 1062,  244,  395,  819,  970,  606,  757, 1184,   87,  514,  665, 301,  452,
+	 876, 1027,  209,  357,  784, 1247,  144,  571,  722, 1146,   52,  479,  627, 1090, 266,  414,
+	 841,  992,  171,  322, 1209,  109,  536,  684, 1111,   17,  904, 1055,  228,  379, 806,  954,
+	 599,  747, 1174,   74,  498,  649,  291,  442,  869, 1017,  193,  344, 1231,  137, 561,  712,
+	1139,   36,  926, 1074,  256,  407,  831,  982,  158,  618,  769, 1196,   99,  526, 677, 1101,
+	   7,  458,  894, 1033,  227,  363,  802,  941,  577,  740, 1152,   70,  485,  645, 284,  420,
+	 859,  998,  189,  328, 1215,  127,  542,  702, 1117,   35,  922, 1061,  246,  385, 824,  960,
+	 605,  765, 1180,   92,  504,  667,  309,  448,  887, 1023,  211,  350,  786, 1237, 155,  567,
+	 730, 1145,   54,  469,  632, 1080,  274,  413,  849,  988,  176,  312, 1202,  117, 532,  695,
+	1107,   19,  906, 1045,  239,  375,  814,  953,  589,  752, 1164,   82,  497,  657, 296,  432,
+	 871, 1010,  201,  340, 1227,  139,  554,  714, 1129,   47,  934, 1073,  258,  397, 836,  972,
+	 166,  617,  777, 1192,  104,  516,  679, 1094,    9,  460,  899, 1035,  223,  362, 798,  937,
+	 579,  742, 1157,   66,  481,  644,  286,  425,  861, 1000,  188,  324, 1214,  129, 544,  707,
+	1119,   31,  918, 1057,  251,  387,  826,  965,  601,  764, 1176,   94,  509,  669, 308,  444,
+	 883, 1022,  213,  352,  791, 1239,  151,  566,  726, 1141,   59,  471,  634, 1085, 270,  409,
+	 848,  984,  178,  317, 1204,  116,  528,  691, 1106,   21,  911, 1047,  235,  374, 810,  949,
+	 591,  754, 1169,   78,  493,  656,  298,  437,  873, 1012,  200,  336, 1226,  141, 556,  719,
+	1131,   43,  930, 1069,  263,  399,  838,  977,  162,  613,  776, 1188,  106,  521, 681, 1096,
+	   2,  462,  889, 1040,  219,  370,  797,  945,  584,  732, 1159,   65,  489,  640, 276,  427,
+	 854, 1002,  184,  335, 1222,  122,  546,  697, 1124,   27,  917, 1065,  241,  392, 816,  967,
+	 609,  760, 1187,   84,  511,  662,  304,  455,  879, 1030,  206,  354,  781, 1244, 147,  574,
+	 725, 1149,   49,  476,  624, 1087,  269,  417,  844,  995,  168,  319, 1206,  112, 539,  687,
+	1114,   14,  901, 1052,  231,  382,  809,  957,  596,  744, 1171,   77,  501,  652, 288,  439,
+	 866, 1014,  196,  347, 1234,  134,  558,  709, 1136,   39,  929, 1077,  253,  404, 828,  979,
+	 161,  621,  772, 1199,   96,  523,  674, 1098,    4,  467,  891, 1042,  218,  366, 793,  944,
+	 586,  737, 1161,   61,  488,  636,  281,  429,  856, 1007,  180,  331, 1218,  124, 551,  699,
+	1126,   26,  913, 1064,  243,  394,  821,  969,  608,  756, 1183,   89,  513,  664, 300,  451,
+	 878, 1026,  208,  359,  783, 1246,  146,  570,  721, 1148,   51,  478,  629, 1089, 265,  416,
+	 840,  991,  173,  321, 1211,  108,  535,  686, 1110,   16,  903, 1054,  230,  378, 805,  956,
+	 598,  749, 1173,   73,  500,  648,  293,  441,  868, 1019,  192,  343, 1230,  136, 563,  711,
+	1138,   38,  925, 1076,  255,  406,  833,  981,  157,  620,  768, 1195,  101,  525, 676, 1103,
+	   6,  457,  896, 1032,  226,  365,  801,  940,  576,  739, 1154,   69,  484,  647, 283,  422,
+	 858,  997,  191,  327, 1217,  126,  541,  704, 1116,   34,  921, 1060,  248,  384, 823,  962,
+	 604,  767, 1179,   91,  506,  666,  311,  447,  886, 1025,  210,  349,  788, 1236, 154,  569,
+	 729, 1144,   56,  468,  631, 1082,  273,  412,  851,  987,  175,  314, 1201,  119, 531,  694,
+	1109,   18,  908, 1044,  238,  377,  813,  952,  588,  751, 1166,   81,  496,  659, 295,  434,
+	 870, 1009,  203,  339, 1229,  138,  553,  716, 1128,   46,  933, 1072,  260,  396, 835,  974,
+	 165,  616,  779, 1191,  103,  518,  678, 1093,   11,  459,  898, 1037,  222,  361, 800,  936,
+	 581,  741, 1156,   68,  480,  643,  285,  424,  863,  999,  187,  326, 1213,  131, 543,  706,
+	1121,   30,  920, 1056,  250,  389,  825,  964,  600,  763, 1178,   93,  508,  671, 307,  446,
+	 882, 1021,  215,  351,  790, 1241,  150,  565,  728, 1140,   58,  473,  633, 1084, 272,  408,
+	 847,  986,  177,  316, 1203,  115,  530,  690, 1105,   23,  910, 1049,  234,  373, 812,  948,
+	 593,  753, 1168,   80,  492,  655,  297,  436,  875, 1011,  199,  338, 1225,  143, 555,  718,
+	1133,   42,  932, 1068,  262,  401,  837,  976,  164,  612,  775, 1190,  105,  520, 683, 1095,
+	   1,  464,  888, 1039,  221,  369,  796,  947,  583,  734, 1158,   64,  491,  639, 278,  426,
+	 853, 1004,  183,  334, 1221,  121,  548,  696, 1123,   29,  916, 1067,  240,  391, 818,  966,
+	 611,  759, 1186,   86,  510,  661,  303,  454,  881, 1029,  205,  356,  780, 1243, 149,  573,
+	 724, 1151,   48,  475,  626, 1086,  268,  419,  843,  994,  170,  318, 1208,  111, 538,  689,
+	1113,   13,  900, 1051,  233,  381,  808,  959,  595,  746, 1170,   76,  503,  651, 290,  438,
+	 865, 1016,  195,  346, 1233,  133,  560,  708, 1135,   41,  928, 1079,  252,  403, 830,  978,
+	 160,  623,  771, 1198,   98,  522,  673, 1100,    3,  466,  893, 1041,  217,  368, 792,  943,
+	 585,  736, 1163,   60,  487,  638,  280,  431,  855, 1006,  182,  330, 1220,  123, 550,  701,
+	1125,   25,  912, 1063,  245,  393,  820,  971,  607,  758, 1182,   88,  515,  663, 302,  450,
+	 877, 1028,  207,  358,  785, 1245,  145,  572,  720, 1147,   53,  477,  628, 1091, 264,  415,
+	 842,  990,  172,  323, 1210,  110,  534,  685, 1112,   15,  905, 1053,  229,  380, 804,  955,
+	 597,  748, 1175,   72,  499,  650,  292,  443,  867, 1018,  194,  342, 1232,  135, 562,  713,
+	1137,   37,  924, 1075,  257,  405,  832,  983,  156,  619,  770, 1194,  100,  527, 675, 1102,
+	   8,  456,  895, 1034,  225,  364,  803,  939,  578,  738, 1153,   71,  483,  646, 282,  421,
+	 860,  996,  190,  329, 1216,  128,  540,  703, 1118,   33,  923, 1059,  247,  386, 822,  961,
+	 603,  766, 1181,   90,  505,  668,  310,  449,  885, 1024,  212,  348,  787, 1238, 153,  568,
+	 731, 1143,   55,  470,  630, 1081,  275,  411,  850,  989,  174,  313, 1200,  118, 533,  693,
+	1108,   20,  907, 1046,  237,  376,  815,  951,  590,  750, 1165,   83,  495,  658, 294,  433,
+	 872, 1008,  202,  341, 1228,  140,  552,  715, 1130,   45,  935, 1071,  259,  398, 834,  973,
+	 167,  615,  778, 1193,  102,  517,  680, 1092,   10,  461,  897, 1036,  224,  360, 799,  938,
+	 580,  743, 1155,   67,  482,  642,  287,  423,  862, 1001,  186,  325, 1212,  130, 545,  705,
+	1120,   32,  919, 1058,  249,  388,  827,  963,  602,  762, 1177,   95,  507,  670, 306,  445,
+	 884, 1020,  214,  353,  789, 1240,  152,  564,  727, 1142,   57,  472,  635, 1083, 271,  410,
+	 846,  985,  179,  315, 1205,  114,  529,  692, 1104,   22,  909, 1048,  236,  372, 811,  950,
+	 592,  755, 1167,   79,  494,  654,  299,  435,  874, 1013,  198,  337, 1224,  142, 557,  717,
+	1132,   44,  931, 1070,  261,  400,  839,  975,  163,  614,  774, 1189,  107,  519, 682, 1097,
+};
+
+/* this corresponds to the bit-lengths of the individual codec
+ * parameters as indicated in Table 1.1 of TS 06.10 */
+const uint8_t gsm0503_gsm_fr_map[76] = {
+	6, 6, 5, 5, 4, 4, 3, 3, 7, 2, 2, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 7, 2, 2, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 2, 2, 6, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 2, 2, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 3
+};
+
+/* this table describes the 65 most importaint bits from EFR coded
+ * bits as indicated in TS 05.03 (3.1.1.1) */
+const uint8_t gsm0503_gsm_efr_protected_bits[65] = {
+	 39, 40, 41, 42, 43, 44, 48, 87, 45,  2,
+	  3,  8, 10, 18, 19, 24, 46, 47,142,143,
+	144,145,146,147, 92, 93,195,196, 98,137,
+	148, 94,197,149,150, 95,198,  4,  5, 11,
+	 12, 16,  9,  6,  7, 13, 17, 20, 96,199,
+	  1, 14, 15, 21, 25, 26, 28,151,201,190,
+	240, 88,138,191,241
+};
+
+/* Encoded in-band data for speech frames */
+const ubit_t gsm0503_afs_ic_ubit[4][8] = {
+	{ 0,0,0,0,0,0,0,0 },
+	{ 0,1,0,1,1,1,0,1 },
+	{ 1,0,1,1,1,0,1,0 },
+	{ 1,1,1,0,0,1,1,1 },
+};
+
+const sbit_t gsm0503_afs_ic_sbit[4][8] = {
+	{  127, 127, 127, 127, 127, 127, 127, 127 },
+	{  127,-127, 127,-127,-127,-127, 127,-127 },
+	{ -127, 127,-127,-127,-127, 127,-127, 127 },
+	{ -127,-127,-127, 127, 127,-127,-127,-127 },
+};
+
+const ubit_t gsm0503_ahs_ic_ubit[4][4] = {
+	{ 0,0,0,0 },
+	{ 1,0,0,1 },
+	{ 1,1,1,0 },
+	{ 0,1,1,1 },
+};
+
+const sbit_t gsm0503_ahs_ic_sbit[4][4] = {
+	{  127, 127, 127, 127 },
+	{ -127, 127, 127,-127 },
+	{ -127,-127,-127, 127 },
+	{  127,-127,-127,-127 },
+};
+
+const uint8_t gsm0503_tch_hr_interleaving[228][2] = {
+	{ 0  ,0 }, { 1  ,2 }, { 78 ,1 }, { 79 ,3 }, { 48 ,0 }, { 49 ,2 },
+	{ 54 ,1 }, { 55 ,3 }, { 24 ,0 }, { 25 ,2 }, { 30 ,1 }, { 31 ,3 },
+	{ 72 ,0 }, { 73 ,2 }, { 6  ,1 }, { 7  ,3 }, { 96 ,0 }, { 97 ,2 },
+	{ 12 ,0 }, { 13 ,2 }, { 102,1 }, { 103,3 }, { 60 ,0 }, { 61 ,2 },
+	{ 66 ,1 }, { 67 ,3 }, { 90 ,1 }, { 91 ,3 }, { 36 ,0 }, { 37 ,2 },
+	{ 42 ,1 }, { 43 ,3 }, { 18 ,1 }, { 19 ,3 }, { 84 ,0 }, { 85 ,2 },
+	{ 108,0 }, { 109,2 }, { 2  ,0 }, { 3  ,2 }, { 80 ,1 }, { 81 ,3 },
+	{ 50 ,0 }, { 51 ,2 }, { 56 ,1 }, { 57 ,3 }, { 26 ,0 }, { 27 ,2 },
+	{ 32 ,1 }, { 33 ,3 }, { 74 ,0 }, { 75 ,2 }, { 8  ,1 }, { 9  ,3 },
+	{ 98 ,0 }, { 99 ,2 }, { 14 ,0 }, { 15 ,2 }, { 104,1 }, { 105,3 },
+	{ 62 ,0 }, { 63 ,2 }, { 68 ,1 }, { 69 ,3 }, { 92 ,1 }, { 93 ,3 },
+	{ 38 ,0 }, { 39 ,2 }, { 44 ,1 }, { 45 ,3 }, { 20 ,1 }, { 21 ,3 },
+	{ 86 ,0 }, { 87 ,2 }, { 110,0 }, { 111,2 }, { 4  ,0 }, { 5  ,2 },
+	{ 82 ,1 }, { 83 ,3 }, { 52 ,0 }, { 53 ,2 }, { 58 ,1 }, { 59 ,3 },
+	{ 28 ,0 }, { 29 ,2 }, { 34 ,1 }, { 35 ,3 }, { 76 ,0 }, { 77 ,2 },
+	{ 10 ,1 }, { 12 ,3 }, { 100,0 }, { 101,2 }, { 16 ,0 }, { 17 ,2 },
+	{ 106,1 }, { 107,3 }, { 64 ,0 }, { 65 ,2 }, { 70 ,1 }, { 71 ,3 },
+	{ 94 ,1 }, { 95 ,3 }, { 40 ,0 }, { 41 ,2 }, { 46 ,1 }, { 47 ,3 },
+	{ 22 ,1 }, { 23 ,3 }, { 88 ,0 }, { 89 ,2 }, { 112,0 }, { 113,2 },
+	{ 6  ,0 }, { 7  ,2 }, { 84 ,1 }, { 85 ,3 }, { 54 ,0 }, { 55 ,2 },
+	{ 60 ,1 }, { 61 ,3 }, { 30 ,0 }, { 31 ,2 }, { 36 ,1 }, { 37 ,3 },
+	{ 78 ,0 }, { 79 ,2 }, { 12 ,1 }, { 13 ,3 }, { 102,0 }, { 103,2 },
+	{ 18 ,0 }, { 19 ,2 }, { 108,1 }, { 109,3 }, { 66 ,0 }, { 67 ,2 },
+	{ 72 ,1 }, { 73 ,3 }, { 96 ,1 }, { 97 ,3 }, { 42 ,0 }, { 43 ,2 },
+	{ 48 ,1 }, { 49 ,3 }, { 24 ,1 }, { 25 ,3 }, { 90 ,0 }, { 91 ,2 },
+	{ 0  ,1 }, { 1  ,3 }, { 8  ,0 }, { 9  ,2 }, { 86 ,1 }, { 87 ,3 },
+	{ 56 ,0 }, { 57 ,2 }, { 62 ,1 }, { 63 ,3 }, { 32 ,0 }, { 33 ,2 },
+	{ 38 ,1 }, { 39 ,3 }, { 80 ,0 }, { 81 ,2 }, { 14 ,1 }, { 15 ,3 },
+	{ 104,0 }, { 105,2 }, { 20 ,0 }, { 21 ,2 }, { 110,1 }, { 111,3 },
+	{ 68 ,0 }, { 69 ,2 }, { 74 ,1 }, { 75 ,3 }, { 98 ,1 }, { 99 ,3 },
+	{ 44 ,0 }, { 45 ,2 }, { 50 ,1 }, { 51 ,3 }, { 26 ,1 }, { 27 ,3 },
+	{ 92 ,0 }, { 93 ,2 }, { 2  ,1 }, { 3  ,3 }, { 10 ,0 }, { 11 ,2 },
+	{ 88 ,1 }, { 89 ,3 }, { 58 ,0 }, { 59 ,2 }, { 64 ,1 }, { 65 ,3 },
+	{ 34 ,0 }, { 35 ,2 }, { 40 ,1 }, { 41 ,3 }, { 82 ,0 }, { 83 ,2 },
+	{ 16 ,1 }, { 17 ,3 }, { 106,0 }, { 107,2 }, { 22 ,0 }, { 23 ,2 },
+	{ 112,1 }, { 113,3 }, { 70 ,0 }, { 71 ,2 }, { 76 ,1 }, { 77 ,3 },
+	{ 100,1 }, { 101,3 }, { 46 ,0 }, { 47 ,2 }, { 52 ,1 }, { 53 ,3 },
+	{ 28 ,1 }, { 29 ,3 }, { 94 ,0 }, { 95 ,2 }, { 4  ,1 }, { 5  ,3 },
+};
+
+/*
+ * 3GPP TS 05.03 5.1.9.1.2 "USF precoding"
+ */
+const ubit_t gsm0503_mcs5_usf_precode_table[8][36] = {
+	{ 0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0, },
+	{ 1,1,1,1,1,0,0,0,0, 1,1,1,1,0,0,0,0,0, 1,1,1,1,1,1,0,0,0, 1,1,1,1,1,0,0,0,1, },
+	{ 1,1,1,0,0,1,1,1,0, 1,1,1,0,1,1,1,0,0, 1,1,0,0,0,0,1,1,0, 1,1,0,0,0,1,1,0,0, },
+	{ 1,0,0,1,1,1,1,0,0, 1,1,0,0,0,0,0,1,1, 1,0,1,1,1,0,1,1,1, 0,0,1,0,0,1,1,1,1, },
+	{ 0,0,0,1,1,0,0,1,1, 0,0,1,0,1,1,0,1,0, 1,0,0,0,0,1,1,0,1, 1,1,1,1,1,1,1,1,0, },
+	{ 1,1,0,1,0,1,0,1,1, 0,0,0,1,1,0,1,0,1, 0,1,1,1,0,1,0,1,1, 1,0,0,1,0,1,0,1,1, },
+	{ 0,0,1,0,0,1,1,0,1, 1,0,1,1,1,1,1,1,1, 0,1,1,0,1,0,0,0,1, 0,0,1,1,1,0,1,0,0, },
+	{ 0,1,1,0,1,0,1,1,1, 0,1,0,1,0,1,1,1,1, 0,0,0,1,1,1,1,1,0, 0,1,0,0,1,0,0,1,1, },
+};
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index dc8559f..1bde75d 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -71,8 +71,12 @@
 gsm0502_calc_paging_group;
 
 gsm0503_xcch;
+gsm0503_rach;
+gsm0503_sch;
 gsm0503_cs2;
 gsm0503_cs3;
+gsm0503_tch_fr;
+gsm0503_tch_hr;
 gsm0503_tch_afs_12_2;
 gsm0503_tch_afs_10_2;
 gsm0503_tch_afs_7_95;
@@ -81,6 +85,124 @@
 gsm0503_tch_afs_5_9;
 gsm0503_tch_afs_5_15;
 gsm0503_tch_afs_4_75;
+gsm0503_tch_ahs_7_95;
+gsm0503_tch_ahs_7_4;
+gsm0503_tch_ahs_6_7;
+gsm0503_tch_ahs_5_9;
+gsm0503_tch_ahs_5_15;
+gsm0503_tch_ahs_4_75;
+gsm0503_pdtch_hl_hn_ubit;
+gsm0503_pdtch_edge_hl_hn_ubit;
+gsm0503_pdtch_hl_hn_sbit;
+gsm0503_pdtch_edge_hl_hn_sbit;
+gsm0503_usf2six;
+gsm0503_usf2twelve_ubit;
+gsm0503_usf2twelve_sbit;
+gsm0503_puncture_cs2;
+gsm0503_puncture_cs3;
+gsm0503_puncture_mcs1_dl_hdr;
+gsm0503_puncture_mcs1_ul_hdr;
+gsm0503_puncture_mcs1_p1;
+gsm0503_puncture_mcs1_p2;
+gsm0503_puncture_mcs2_p1;
+gsm0503_puncture_mcs2_p2;
+gsm0503_puncture_mcs3_p1;
+gsm0503_puncture_mcs3_p2;
+gsm0503_puncture_mcs3_p3;
+gsm0503_puncture_mcs4_p1;
+gsm0503_puncture_mcs4_p2;
+gsm0503_puncture_mcs4_p3;
+gsm0503_puncture_mcs5_p1;
+gsm0503_puncture_mcs5_p2;
+gsm0503_puncture_mcs6_p1;
+gsm0503_puncture_mcs6_p2;
+gsm0503_puncture_mcs7_dl_hdr;
+gsm0503_puncture_mcs7_ul_hdr;
+gsm0503_puncture_mcs7_p1;
+gsm0503_puncture_mcs7_p2;
+gsm0503_puncture_mcs7_p3;
+gsm0503_puncture_mcs8_p1;
+gsm0503_puncture_mcs8_p2;
+gsm0503_puncture_mcs8_p3;
+gsm0503_puncture_mcs9_p1;
+gsm0503_puncture_mcs9_p2;
+gsm0503_puncture_mcs9_p3;
+gsm0503_interleave_mcs5;
+gsm0503_gsm_fr_map;
+gsm0503_gsm_efr_protected_bits;
+gsm0503_afs_ic_ubit;
+gsm0503_afs_ic_sbit;
+gsm0503_ahs_ic_ubit;
+gsm0503_ahs_ic_sbit;
+gsm0503_tch_hr_interleaving;
+gsm0503_mcs5_usf_precode_table;
+
+gsm0503_xcch_deinterleave;
+gsm0503_xcch_interleave;
+gsm0503_tch_fr_deinterleave;
+gsm0503_tch_fr_interleave;
+gsm0503_tch_hr_deinterleave;
+gsm0503_tch_hr_interleave;
+gsm0503_mcs1_ul_interleave;
+gsm0503_mcs1_ul_deinterleave;
+gsm0503_mcs1_dl_interleave;
+gsm0503_mcs1_dl_deinterleave;
+gsm0503_mcs5_ul_interleave;
+gsm0503_mcs5_ul_deinterleave;
+gsm0503_mcs5_dl_interleave;
+gsm0503_mcs5_dl_deinterleave;
+gsm0503_mcs7_ul_interleave;
+gsm0503_mcs7_ul_deinterleave;
+gsm0503_mcs7_dl_interleave;
+gsm0503_mcs7_dl_deinterleave;
+gsm0503_mcs8_ul_interleave;
+gsm0503_mcs8_ul_deinterleave;
+gsm0503_mcs8_dl_interleave;
+gsm0503_mcs8_dl_deinterleave;
+
+gsm0503_xcch_burst_unmap;
+gsm0503_xcch_burst_map;
+gsm0503_tch_burst_unmap;
+gsm0503_tch_burst_map;
+gsm0503_mcs5_ul_burst_map;
+gsm0503_mcs5_ul_burst_unmap;
+gsm0503_mcs7_ul_burst_map;
+gsm0503_mcs7_ul_burst_unmap;
+gsm0503_mcs5_dl_burst_map;
+gsm0503_mcs5_dl_burst_unmap;
+gsm0503_mcs7_dl_burst_map;
+gsm0503_mcs7_dl_burst_unmap;
+gsm0503_mcs5_burst_swap;
+
+gsm0503_fire_crc40;
+gsm0503_cs234_crc16;
+gsm0503_mcs_crc8_hdr;
+gsm0503_mcs_crc12;
+gsm0503_rach_crc6;
+gsm0503_sch_crc10;
+gsm0503_tch_fr_crc3;
+gsm0503_tch_efr_crc8;
+gsm0503_amr_crc6;
+
+gsm0503_egprs_mcs;
+gsm0503_xcch_decode;
+gsm0503_xcch_encode;
+gsm0503_pdtch_decode;
+gsm0503_pdtch_egprs_decode;
+gsm0503_pdtch_encode;
+gsm0503_pdtch_egprs_encode;
+gsm0503_tch_fr_decode;
+gsm0503_tch_fr_encode;
+gsm0503_tch_hr_decode;
+gsm0503_tch_hr_encode;
+gsm0503_tch_afs_decode;
+gsm0503_tch_afs_encode;
+gsm0503_tch_ahs_decode;
+gsm0503_tch_ahs_encode;
+gsm0503_rach_decode;
+gsm0503_rach_encode;
+gsm0503_sch_decode;
+gsm0503_sch_encode;
 
 gsm0808_att_tlvdef;
 gsm0808_bssap_name;
diff --git a/utils/conv_gen.py b/utils/conv_gen.py
index bb547de..7aa5a3c 100644
--- a/utils/conv_gen.py
+++ b/utils/conv_gen.py
@@ -1,7 +1,6 @@
 #!/usr/bin/python2
 
-mod_license = """
-/*
+mod_license = """/*
  * Copyright (C) 2011-2016 Sylvain Munaut <tnt at 246tNt.com>
  * Copyright (C) 2016 sysmocom s.f.m.c. GmbH
  *
@@ -27,7 +26,8 @@
 
 class ConvolutionalCode(object):
 
-	def __init__(self, block_len, polys, name = "call-me", description = "LOL", puncture = []):
+	def __init__(self, block_len, polys,
+				 name = "call-me", description = False, puncture = []):
 		# Save simple params
 		self.block_len = block_len
 		self.k = 1
@@ -50,9 +50,14 @@
 		rp = [x[1] for x in self.polys if x[1] != 1]
 		if rp:
 			if not all([x == rp[0] for x in rp]):
-				raise ValueError("Bad polynoms: Can't have multiple different divider polynoms !")
+				raise ValueError("Bad polynoms: "
+					"Can't have multiple different divider polynoms!")
+
 			if not all([x[0] == 1 for x in polys if x[1] == 1]):
-				raise ValueError("Bad polynoms: Can't have a '1' divider with a non '1' dividend in a recursive code")
+				raise ValueError("Bad polynoms: "
+					"Can't have a '1' divider with a non '1' dividend "
+					"in a recursive code")
+
 			self.poly_divider = rp[0]
 
 	@property
@@ -63,8 +68,13 @@
 	def _state_mask(self):
 		return (1 << (self.k - 1)) - 1
 
+	def combine(self, src, sel, nb):
+		x = src & sel
+		fn_xor = lambda x, y: x ^ y
+		return reduce(fn_xor, [(x >> n) & 1 for n in range(nb)])
+
 	def next_state(self, state, bit):
-		nb = combine(
+		nb = self.combine(
 			(state << 1) | bit,
 			self.poly_divider,
 			self.k,
@@ -85,9 +95,10 @@
 		rv = []
 		for p_n, p_d in self.polys:
 			if self.recursive and p_d == 1:
-				o = bit	# No choice ... (systematic output in recursive case)
+				# No choice ... (systematic output in recursive case)
+				o = bit
 			else:
-				o = combine(src, p_n, self.k)
+				o = self.combine(src, p_n, self.k)
 			rv.append(o)
 
 		return rv
@@ -104,9 +115,9 @@
 		for p_n, p_d in self.polys:
 			if self.recursive and p_d == 1:
 				# Systematic output are replaced when in 'termination' mode
-				o = combine(src, self.poly_divider, self.k)
+				o = self.combine(src, self.poly_divider, self.k)
 			else:
-				o = combine(src, p_n, self.k)
+				o = self.combine(src, p_n, self.k)
 			rv.append(o)
 
 		return rv
@@ -121,61 +132,118 @@
 		nb = self.next_term_output(state, ns = ns)
 		return ns, nb
 
-        def _print_term(self, fi, num_states, pack = False):
+	def _print_term(self, fi, num_states, pack = False):
+		# Up to 12 numbers should be placed per line
+		counter = 0
 		d = []
+
 		for state in range(num_states):
-			x = pack(self.next_term_output(state)) if pack else self.next_term_state(state)
-			d.append("%d, " % x)
-		print >>fi, "\t%s" % ''.join(d)
+			if pack:
+				x = pack(self.next_term_output(state))
+			else:
+				x = self.next_term_state(state)
+
+			if counter == 0:
+				fi.write("\t")
+			elif counter % 12 == 0:
+				fi.write("\n\t")
+
+			fi.write("%3d, " % x)
+			counter += 1
+
+		fi.write("\n")
 
 	def _print_x(self, fi, num_states, pack = False):
+		# Up to 4 blocks should be placed per line
+		counter = 0
+
 		for state in range(num_states):
-			x0 = pack(self.next_output(state, 0)) if pack else self.next_state(state, 0)
-			x1 = pack(self.next_output(state, 1)) if pack else self.next_state(state, 1)
-			print >>fi, "\t{ %2d, %2d }," % (x0, x1)
+			if pack:
+				x0 = pack(self.next_output(state, 0))
+				x1 = pack(self.next_output(state, 1))
+			else:
+				x0 = self.next_state(state, 0)
+				x1 = self.next_state(state, 1)
+
+			if counter == 0:
+				fi.write("\t")
+			elif counter % 4 == 0:
+				fi.write("\n\t")
+
+			fi.write("{ %2d, %2d }, " % (x0, x1))
+			counter += 1
+
+		fi.write("\n")
 
 	def gen_tables(self, pref, fi):
-		pack = lambda n: sum([x << (self.rate_inv - i - 1) for i, x in enumerate(n)])
 		num_states = 1 << (self.k - 1)
-		print >>fi, "\nstatic const uint8_t %s_state[][2] = {" % self.name
+		pack = lambda n: \
+			sum([x << (self.rate_inv - i - 1) for i, x in enumerate(n)])
+
+		print >>fi, \
+			"\nstatic const uint8_t %s_state[][2] = {" % self.name
 		self._print_x(fi, num_states)
-		print >>fi, "};\n\nstatic const uint8_t %s_output[][2] = {" % self.name
+
+		print >>fi, \
+			"};\n\nstatic const uint8_t %s_output[][2] = {" % self.name
 		self._print_x(fi, num_states, pack)
 		print >>fi, "};"
 
 		if self.recursive:
-			print >>fi, "\nstatic const uint8_t %s_term_state[] = {" % self.name
+			print >>fi, \
+				"\nstatic const uint8_t %s_term_state[] = {" % self.name
 			self._print_term(fi, num_states)
-			print >>fi, "};\n\nstatic const uint8_t %s_term_output[] = {" % self.name
+
+			print >>fi, \
+				"};\n\nstatic const uint8_t %s_term_output[] = {" % self.name
 			self._print_term(fi, num_states, pack)
 			print >>fi, "};"
 
 		if len(self.puncture):
-			print >>fi, "\nstatic const int %s_puncture[] = {" % self.name
-			for p in self.puncture:
-				print >>fi, "\t%d," % p
-			print >>fi, "};"
+			# Up to 12 numbers should be placed per line
+			counter = 0
 
-		print >>fi, "\n/* %s */" % self.description
-		print >>fi, "const struct osmo_conv_code %s_%s = {" % (pref, self.name)
+			print >>fi, \
+				"\nstatic const int %s_puncture[] = {" % self.name
+
+			for p in self.puncture:
+				if counter == 0:
+					fi.write("\t")
+				elif counter % 12 == 0:
+					fi.write("\n\t")
+
+				fi.write("%3d, " % p)
+				counter += 1
+
+			fi.write("\n};\n")
+
+		# Write description as a multiline comment
+		if self.description:
+			print >>fi, "\n/**"
+			for line in self.description:
+				print >>fi, " * %s" % line
+			print >>fi, " */"
+
+		# Write a final definition
+		print >>fi, \
+			"const struct osmo_conv_code %s_%s = {" % (pref, self.name)
+
 		print >>fi, "\t.N = %d," % self.rate_inv
 		print >>fi, "\t.K = %d," % self.k
 		print >>fi, "\t.len = %d," % self.block_len
 		print >>fi, "\t.next_output = %s_output," % self.name
 		print >>fi, "\t.next_state = %s_state," % self.name
+
 		if self.recursive:
 			print >>fi, "\t.next_term_output = %s_term_output," % self.name
 			print >>fi, "\t.next_term_state = %s_term_state," % self.name
+
 		if len(self.puncture):
 			print >>fi, "\t.puncture = %s_puncture," % self.name
+
 		print >>fi, "};"
 
 poly = lambda *args: sum([(1 << x) for x in args])
-
-def combine(src, sel, nb):
-	x = src & sel
-	fn_xor = lambda x, y: x ^ y
-	return reduce(fn_xor, [(x >> n) & 1 for n in range(nb)])
 
 # Polynomials according to 3GPP TS 05.03 Annex B
 G0 = poly(0, 3, 4)
@@ -188,307 +256,487 @@
 G7 = poly(0, 1, 2, 3, 6)
 
 CCH_poly = [
-		( G0, 1 ),
-		( G1, 1 )
+	( G0, 1 ),
+	( G1, 1 ),
 ]
 
-xCCH = ConvolutionalCode(
-	224,
-	CCH_poly,
-	name = "xcch",
-	description =""" *CCH convolutional code:
-        228 bits blocks, rate 1/2, k = 5
-        G0 = 1 + D3 + D4
-        G1 = 1 + D + D3 + D4
-"""
-)
+conv_codes = [
+	# xCCH definition
+	ConvolutionalCode(
+		224,
+		CCH_poly,
+		name = "xcch",
+		description = [
+			"xCCH convolutional code:",
+			"228 bits blocks, rate 1/2, k = 5",
+			"G0 = 1 + D3 + D4",
+			"G1 = 1 + D + D3 + D4",
+		]
+	),
 
-CS2 = ConvolutionalCode(
-	290,
-	CCH_poly,
-	puncture = [
-                 15,  19,  23,  27,  31,  35,  43,  47,  51,  55,  59,  63,  67,  71,
-                 75,  79,  83,  91,  95,  99, 103, 107, 111, 115, 119, 123, 127, 131,
-                139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179, 187, 191, 195,
-                199, 203, 207, 211, 215, 219, 223, 227, 235, 239, 243, 247, 251, 255,
-                259, 263, 267, 271, 275, 283, 287, 291, 295, 299, 303, 307, 311, 315,
-                319, 323, 331, 335, 339, 343, 347, 351, 355, 359, 363, 367, 371, 379,
-                383, 387, 391, 395, 399, 403, 407, 411, 415, 419, 427, 431, 435, 439,
-                443, 447, 451, 455, 459, 463, 467, 475, 479, 483, 487, 491, 495, 499,
-                503, 507, 511, 515, 523, 527, 531, 535, 539, 543, 547, 551, 555, 559,
-                563, 571, 575, 579, 583, 587, -1
-        ],
-	name = "cs2",
-	description =""" CS2 convolutional code:
-        G0 = 1 + D3 + D4
-        G1 = 1 + D + D3 + D4
-"""
-)
+	# RACH definition
+	ConvolutionalCode(
+		14,
+		CCH_poly,
+		name = "rach",
+		description = ["RACH convolutional code"]
+	),
 
-CS3 = ConvolutionalCode(
-	334,
-	CCH_poly,
-	puncture = [
-                 15,  17,  21,  23,  27,  29,  33,  35,  39,  41,  45,  47,  51,  53,
-                 57,  59,  63,  65,  69,  71,  75,  77,  81,  83,  87,  89,  93,  95,
-                 99, 101, 105, 107, 111, 113, 117, 119, 123, 125, 129, 131, 135, 137,
-                141, 143, 147, 149, 153, 155, 159, 161, 165, 167, 171, 173, 177, 179,
-                183, 185, 189, 191, 195, 197, 201, 203, 207, 209, 213, 215, 219, 221,
-                225, 227, 231, 233, 237, 239, 243, 245, 249, 251, 255, 257, 261, 263,
-                267, 269, 273, 275, 279, 281, 285, 287, 291, 293, 297, 299, 303, 305,
-                309, 311, 315, 317, 321, 323, 327, 329, 333, 335, 339, 341, 345, 347,
-                351, 353, 357, 359, 363, 365, 369, 371, 375, 377, 381, 383, 387, 389,
-                393, 395, 399, 401, 405, 407, 411, 413, 417, 419, 423, 425, 429, 431,
-                435, 437, 441, 443, 447, 449, 453, 455, 459, 461, 465, 467, 471, 473,
-                477, 479, 483, 485, 489, 491, 495, 497, 501, 503, 507, 509, 513, 515,
-                519, 521, 525, 527, 531, 533, 537, 539, 543, 545, 549, 551, 555, 557,
-                561, 563, 567, 569, 573, 575, 579, 581, 585, 587, 591, 593, 597, 599,
-                603, 605, 609, 611, 615, 617, 621, 623, 627, 629, 633, 635, 639, 641,
-                645, 647, 651, 653, 657, 659, 663, 665, 669, 671, -1
-        ],
-	name = "cs3",
-	description =""" CS3 convolutional code:
-        G0 = 1 + D3 + D4
-        G1 = 1 + D + D3 + D4
-"""
-)
+	# SCH definition
+	ConvolutionalCode(
+		35,
+		CCH_poly,
+		name = "sch",
+		description = ["SCH convolutional code"]
+	),
 
-TCH_AFS_12_2 = ConvolutionalCode(
-	250,
-	[
-		(  1,  1 ),
-		( G1, G0 ),
-	],
-        puncture = [
-                321, 325, 329, 333, 337, 341, 345, 349, 353, 357, 361, 363,
-                365, 369, 373, 377, 379, 381, 385, 389, 393, 395, 397, 401,
-                405, 409, 411, 413, 417, 421, 425, 427, 429, 433, 437, 441,
-                443, 445, 449, 453, 457, 459, 461, 465, 469, 473, 475, 477,
-                481, 485, 489, 491, 493, 495, 497, 499, 501, 503, 505, 507,
-                -1
-        ],
-	name = 'tch_afs_12_2',
-	description = """TCH/AFS 12.2 convolutional code:
-        250 bits block, rate 1/2, punctured
-        G0/G0 = 1
-        G1/G0 = 1 + D + D3 + D4 / 1 + D3 + D4
-"""
-)
+	# CS2 definition
+	ConvolutionalCode(
+		290,
+		CCH_poly,
+		puncture = [
+			 15,  19,  23,  27,  31,  35,  43,  47,  51,  55,  59,  63,  67,  71,
+			 75,  79,  83,  91,  95,  99, 103, 107, 111, 115, 119, 123, 127, 131,
+			139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179, 187, 191, 195,
+			199, 203, 207, 211, 215, 219, 223, 227, 235, 239, 243, 247, 251, 255,
+			259, 263, 267, 271, 275, 283, 287, 291, 295, 299, 303, 307, 311, 315,
+			319, 323, 331, 335, 339, 343, 347, 351, 355, 359, 363, 367, 371, 379,
+			383, 387, 391, 395, 399, 403, 407, 411, 415, 419, 427, 431, 435, 439,
+			443, 447, 451, 455, 459, 463, 467, 475, 479, 483, 487, 491, 495, 499,
+			503, 507, 511, 515, 523, 527, 531, 535, 539, 543, 547, 551, 555, 559,
+			563, 571, 575, 579, 583, 587, -1
+		],
+		name = "cs2",
+		description = [
+			"CS2 convolutional code:",
+			"G0 = 1 + D3 + D4",
+			"G1 = 1 + D + D3 + D4",
+		]
+	),
 
-TCH_AFS_10_2 = ConvolutionalCode(
-	210,
-	[
-		( G1, G3 ),
-		( G2, G3 ),
-		(  1,  1 ),
-	],
-	puncture = [
-                  1,   4,   7,  10,  16,  19,  22,  28,  31,  34,  40,  43,
-                 46,  52,  55,  58,  64,  67,  70,  76,  79,  82,  88,  91,
-                 94, 100, 103, 106, 112, 115, 118, 124, 127, 130, 136, 139,
-                142, 148, 151, 154, 160, 163, 166, 172, 175, 178, 184, 187,
-                190, 196, 199, 202, 208, 211, 214, 220, 223, 226, 232, 235,
-                238, 244, 247, 250, 256, 259, 262, 268, 271, 274, 280, 283,
-                286, 292, 295, 298, 304, 307, 310, 316, 319, 322, 325, 328,
-                331, 334, 337, 340, 343, 346, 349, 352, 355, 358, 361, 364,
-                367, 370, 373, 376, 379, 382, 385, 388, 391, 394, 397, 400,
-                403, 406, 409, 412, 415, 418, 421, 424, 427, 430, 433, 436,
-                439, 442, 445, 448, 451, 454, 457, 460, 463, 466, 469, 472,
-                475, 478, 481, 484, 487, 490, 493, 496, 499, 502, 505, 508,
-                511, 514, 517, 520, 523, 526, 529, 532, 535, 538, 541, 544,
-                547, 550, 553, 556, 559, 562, 565, 568, 571, 574, 577, 580,
-                583, 586, 589, 592, 595, 598, 601, 604, 607, 609, 610, 613,
-                616, 619, 621, 622, 625, 627, 628, 631, 633, 634, 636, 637,
-                639, 640, -1
-        ],
-	name = 'tch_afs_10_2',
-	description = """TCH/AFS 10.2 kbits convolutional code:
-        G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
-        G2/G3 = 1 + D2 + D4     / 1 + D + D2 + D3 + D4
-        G3/G3 = 1
-"""
-)
+	# CS3 definition
+	ConvolutionalCode(
+		334,
+		CCH_poly,
+		puncture = [
+			 15,  17,  21,  23,  27,  29,  33,  35,  39,  41,  45,  47,  51,  53,
+			 57,  59,  63,  65,  69,  71,  75,  77,  81,  83,  87,  89,  93,  95,
+			 99, 101, 105, 107, 111, 113, 117, 119, 123, 125, 129, 131, 135, 137,
+			141, 143, 147, 149, 153, 155, 159, 161, 165, 167, 171, 173, 177, 179,
+			183, 185, 189, 191, 195, 197, 201, 203, 207, 209, 213, 215, 219, 221,
+			225, 227, 231, 233, 237, 239, 243, 245, 249, 251, 255, 257, 261, 263,
+			267, 269, 273, 275, 279, 281, 285, 287, 291, 293, 297, 299, 303, 305,
+			309, 311, 315, 317, 321, 323, 327, 329, 333, 335, 339, 341, 345, 347,
+			351, 353, 357, 359, 363, 365, 369, 371, 375, 377, 381, 383, 387, 389,
+			393, 395, 399, 401, 405, 407, 411, 413, 417, 419, 423, 425, 429, 431,
+			435, 437, 441, 443, 447, 449, 453, 455, 459, 461, 465, 467, 471, 473,
+			477, 479, 483, 485, 489, 491, 495, 497, 501, 503, 507, 509, 513, 515,
+			519, 521, 525, 527, 531, 533, 537, 539, 543, 545, 549, 551, 555, 557,
+			561, 563, 567, 569, 573, 575, 579, 581, 585, 587, 591, 593, 597, 599,
+			603, 605, 609, 611, 615, 617, 621, 623, 627, 629, 633, 635, 639, 641,
+			645, 647, 651, 653, 657, 659, 663, 665, 669, 671, -1
+		],
+		name = "cs3",
+		description = [
+			"CS3 convolutional code:",
+			"G0 = 1 + D3 + D4",
+			"G1 = 1 + D + D3 + D4",
+		]
+	),
 
-TCH_AFS_7_95 = ConvolutionalCode(
-	165,
-	[
-		(  1,  1 ),
-		( G5, G4 ),
-		( G6, G4 ),
-	],
-	puncture = [
-                  1,   2,   4,   5,   8,  22,  70, 118, 166, 214, 262, 310,
-                317, 319, 325, 332, 334, 341, 343, 349, 356, 358, 365, 367,
-                373, 380, 382, 385, 389, 391, 397, 404, 406, 409, 413, 415,
-                421, 428, 430, 433, 437, 439, 445, 452, 454, 457, 461, 463,
-                469, 476, 478, 481, 485, 487, 490, 493, 500, 502, 503, 505,
-                506, 508, 509, 511, 512, -1
-        ],
-	name = 'tch_afs_7_95',
-	description = """TCH/AFS 7.95 kbits convolutional code:
-        G4/G4 = 1
-        G5/G4 = 1 + D + D4 + D6           / 1 + D2 + D3 + D5 + D6
-        G6/G4 = 1 + D + D2 + D3 + D4 + D6 / 1 + D2 + D3 + D5 + D6
-"""
-)
+	# TCH_AFS_12_2 definition
+	ConvolutionalCode(
+		250,
+		[
+			(  1,  1 ),
+			( G1, G0 ),
+		],
+		puncture = [
+			321, 325, 329, 333, 337, 341, 345, 349, 353, 357, 361, 363,
+			365, 369, 373, 377, 379, 381, 385, 389, 393, 395, 397, 401,
+			405, 409, 411, 413, 417, 421, 425, 427, 429, 433, 437, 441,
+			443, 445, 449, 453, 457, 459, 461, 465, 469, 473, 475, 477,
+			481, 485, 489, 491, 493, 495, 497, 499, 501, 503, 505, 507,
+			-1
+		],
+		name = 'tch_afs_12_2',
+		description = [
+			"TCH/AFS 12.2 kbits convolutional code:",
+			"250 bits block, rate 1/2, punctured",
+			"G0/G0 = 1",
+			"G1/G0 = 1 + D + D3 + D4 / 1 + D3 + D4",
+		]
+	),
 
-TCH_AFS_7_4 = ConvolutionalCode(
-	154,
-	[
-		( G1, G3 ),
-		( G2, G3 ),
-		(  1,  1 ),
-	],
-	puncture = [
-                  0, 355, 361, 367, 373, 379, 385, 391, 397, 403, 409, 415,
-                421, 427, 433, 439, 445, 451, 457, 460, 463, 466, 468, 469,
-                471, 472, -1
-        ],
-	name = 'tch_afs_7_4',
-	description = """TCH/AFS 7.4 kbits convolutional code:
-        G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
-        G2/G3 = 1 + D2 + D4     / 1 + D + D2 + D3 + D4
-        G3/G3 = 1
-"""
-)
+	# TCH_AFS_10_2 definition
+	ConvolutionalCode(
+		210,
+		[
+			( G1, G3 ),
+			( G2, G3 ),
+			(  1,  1 ),
+		],
+		puncture = [
+			  1,   4,   7,  10,  16,  19,  22,  28,  31,  34,  40,  43,
+			 46,  52,  55,  58,  64,  67,  70,  76,  79,  82,  88,  91,
+			 94, 100, 103, 106, 112, 115, 118, 124, 127, 130, 136, 139,
+			142, 148, 151, 154, 160, 163, 166, 172, 175, 178, 184, 187,
+			190, 196, 199, 202, 208, 211, 214, 220, 223, 226, 232, 235,
+			238, 244, 247, 250, 256, 259, 262, 268, 271, 274, 280, 283,
+			286, 292, 295, 298, 304, 307, 310, 316, 319, 322, 325, 328,
+			331, 334, 337, 340, 343, 346, 349, 352, 355, 358, 361, 364,
+			367, 370, 373, 376, 379, 382, 385, 388, 391, 394, 397, 400,
+			403, 406, 409, 412, 415, 418, 421, 424, 427, 430, 433, 436,
+			439, 442, 445, 448, 451, 454, 457, 460, 463, 466, 469, 472,
+			475, 478, 481, 484, 487, 490, 493, 496, 499, 502, 505, 508,
+			511, 514, 517, 520, 523, 526, 529, 532, 535, 538, 541, 544,
+			547, 550, 553, 556, 559, 562, 565, 568, 571, 574, 577, 580,
+			583, 586, 589, 592, 595, 598, 601, 604, 607, 609, 610, 613,
+			616, 619, 621, 622, 625, 627, 628, 631, 633, 634, 636, 637,
+			639, 640, -1
+		],
+		name = 'tch_afs_10_2',
+		description = [
+			"TCH/AFS 10.2 kbits convolutional code:",
+			"G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4",
+			"G2/G3 = 1 + D2 + D4     / 1 + D + D2 + D3 + D4",
+			"G3/G3 = 1",
+		]
+	),
 
-TCH_AFS_6_7 = ConvolutionalCode(
-	140,
-	[
-		( G1, G3 ),
-		( G2, G3 ),
-		(  1,  1 ),
-		(  1,  1 ),
-	],
-	puncture = [
-                  1,   3,   7,  11,  15,  27,  39,  55,  67,  79,  95, 107,
-                119, 135, 147, 159, 175, 187, 199, 215, 227, 239, 255, 267,
-                279, 287, 291, 295, 299, 303, 307, 311, 315, 319, 323, 327,
-                331, 335, 339, 343, 347, 351, 355, 359, 363, 367, 369, 371,
-                375, 377, 379, 383, 385, 387, 391, 393, 395, 399, 401, 403,
-                407, 409, 411, 415, 417, 419, 423, 425, 427, 431, 433, 435,
-                439, 441, 443, 447, 449, 451, 455, 457, 459, 463, 465, 467,
-                471, 473, 475, 479, 481, 483, 487, 489, 491, 495, 497, 499,
-                503, 505, 507, 511, 513, 515, 519, 521, 523, 527, 529, 531,
-                535, 537, 539, 543, 545, 547, 549, 551, 553, 555, 557, 559,
-                561, 563, 565, 567, 569, 571, 573, 575, -1
-        ],
-	name = 'tch_afs_6_7',
-	description = """TCH/AFS 6.7 kbits convolutional code:
-        G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
-        G2/G3 = 1 + D2 + D4     / 1 + D + D2 + D3 + D4
-        G3/G3 = 1
-        G3/G3 = 1
-"""
-)
+	# TCH_AFS_7_95 definition
+	ConvolutionalCode(
+		165,
+		[
+			(  1,  1 ),
+			( G5, G4 ),
+			( G6, G4 ),
+		],
+		puncture = [
+			  1,   2,   4,   5,   8,  22,  70, 118, 166, 214, 262, 310,
+			317, 319, 325, 332, 334, 341, 343, 349, 356, 358, 365, 367,
+			373, 380, 382, 385, 389, 391, 397, 404, 406, 409, 413, 415,
+			421, 428, 430, 433, 437, 439, 445, 452, 454, 457, 461, 463,
+			469, 476, 478, 481, 485, 487, 490, 493, 500, 502, 503, 505,
+			506, 508, 509, 511, 512, -1
+		],
+		name = 'tch_afs_7_95',
+		description = [
+			"TCH/AFS 7.95 kbits convolutional code:",
+			"G4/G4 = 1",
+			"G5/G4 = 1 + D + D4 + D6           / 1 + D2 + D3 + D5 + D6",
+			"G6/G4 = 1 + D + D2 + D3 + D4 + D6 / 1 + D2 + D3 + D5 + D6",
+		]
+	),
 
-TCH_AFS_5_9 = ConvolutionalCode(
-	124,
-	[
-		( G4, G6 ),
-		( G5, G6 ),
-		(  1,  1),
-		(  1,  1),
-	],
-	puncture = [
-                  0,   1,   3,   5,   7,  11,  15,  31,  47,  63,  79,  95,
-                111, 127, 143, 159, 175, 191, 207, 223, 239, 255, 271, 287,
-                303, 319, 327, 331, 335, 343, 347, 351, 359, 363, 367, 375,
-                379, 383, 391, 395, 399, 407, 411, 415, 423, 427, 431, 439,
-                443, 447, 455, 459, 463, 467, 471, 475, 479, 483, 487, 491,
-                495, 499, 503, 507, 509, 511, 512, 513, 515, 516, 517, 519,
-                -1
-        ],
-	name = 'tch_afs_5_9',
-	description = """TCH/AFS 5.9 kbits convolutional code:
-        124 bits
-        G4/G6 = 1 + D2 + D3 + D5 + D6 / 1 + D + D2 + D3 + D4 + D6
-        G5/G6 = 1 + D + D4 + D6 / 1 + D + D2 + D3 + D4 + D6
-        G6/G6 = 1
-        G6/G6 = 1
-"""
-)
+	# TCH_AFS_7_4 definition
+	ConvolutionalCode(
+		154,
+		[
+			( G1, G3 ),
+			( G2, G3 ),
+			(  1,  1 ),
+		],
+		puncture = [
+			  0, 355, 361, 367, 373, 379, 385, 391, 397, 403, 409, 415,
+			421, 427, 433, 439, 445, 451, 457, 460, 463, 466, 468, 469,
+			471, 472, -1
+		],
+		name = 'tch_afs_7_4',
+		description = [
+			"TCH/AFS 7.4 kbits convolutional code:",
+			"G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4",
+			"G2/G3 = 1 + D2 + D4     / 1 + D + D2 + D3 + D4",
+			"G3/G3 = 1",
+		]
+	),
 
-TCH_AFS_5_15 = ConvolutionalCode(
-	109,
-	[
-		( G1, G3 ),
-		( G1, G3 ),
-		( G2, G3 ),
-		(  1,  1 ),
-		(  1,  1 ),
-	],
-	puncture = [
-                  0,   4,   5,   9,  10,  14,  15,  20,  25,  30,  35,  40,
-                 50,  60,  70,  80,  90, 100, 110, 120, 130, 140, 150, 160,
-                170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280,
-                290, 300, 310, 315, 320, 325, 330, 334, 335, 340, 344, 345,
-                350, 354, 355, 360, 364, 365, 370, 374, 375, 380, 384, 385,
-                390, 394, 395, 400, 404, 405, 410, 414, 415, 420, 424, 425,
-                430, 434, 435, 440, 444, 445, 450, 454, 455, 460, 464, 465,
-                470, 474, 475, 480, 484, 485, 490, 494, 495, 500, 504, 505,
-                510, 514, 515, 520, 524, 525, 529, 530, 534, 535, 539, 540,
-                544, 545, 549, 550, 554, 555, 559, 560, 564, -1
-        ],
-	name = 'tch_afs_5_15',
-	description = """TCH/AFS 5.15 kbits convolutional code:
-        G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
-        G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
-        G2/G3 = 1 + D2 + D4     / 1 + D + D2 + D3 + D4
-        G3/G3 = 1
-        G3/G3 = 1
-"""
-)
+	# TCH_AFS_6_7 definition
+	ConvolutionalCode(
+		140,
+		[
+			( G1, G3 ),
+			( G2, G3 ),
+			(  1,  1 ),
+			(  1,  1 ),
+		],
+		puncture = [
+			  1,   3,   7,  11,  15,  27,  39,  55,  67,  79,  95, 107,
+			119, 135, 147, 159, 175, 187, 199, 215, 227, 239, 255, 267,
+			279, 287, 291, 295, 299, 303, 307, 311, 315, 319, 323, 327,
+			331, 335, 339, 343, 347, 351, 355, 359, 363, 367, 369, 371,
+			375, 377, 379, 383, 385, 387, 391, 393, 395, 399, 401, 403,
+			407, 409, 411, 415, 417, 419, 423, 425, 427, 431, 433, 435,
+			439, 441, 443, 447, 449, 451, 455, 457, 459, 463, 465, 467,
+			471, 473, 475, 479, 481, 483, 487, 489, 491, 495, 497, 499,
+			503, 505, 507, 511, 513, 515, 519, 521, 523, 527, 529, 531,
+			535, 537, 539, 543, 545, 547, 549, 551, 553, 555, 557, 559,
+			561, 563, 565, 567, 569, 571, 573, 575, -1
+		],
+		name = 'tch_afs_6_7',
+		description = [
+			"TCH/AFS 6.7 kbits convolutional code:",
+			"G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4",
+			"G2/G3 = 1 + D2 + D4     / 1 + D + D2 + D3 + D4",
+			"G3/G3 = 1",
+			"G3/G3 = 1",
+		]
+	),
 
-TCH_AFS_4_75 = ConvolutionalCode(
-	101,
-	[
-		( G4, G6 ),
-		( G4, G6 ),
-		( G5, G6 ),
-		(  1,  1 ),
-		(  1,  1 ),
-	],
-	puncture = [
-                  0,   1,   2,   4,   5,   7,   9,  15,  25,  35,  45,  55,
-                 65,  75,  85,  95, 105, 115, 125, 135, 145, 155, 165, 175,
-                185, 195, 205, 215, 225, 235, 245, 255, 265, 275, 285, 295,
-                305, 315, 325, 335, 345, 355, 365, 375, 385, 395, 400, 405,
-                410, 415, 420, 425, 430, 435, 440, 445, 450, 455, 459, 460,
-                465, 470, 475, 479, 480, 485, 490, 495, 499, 500, 505, 509,
-                510, 515, 517, 519, 520, 522, 524, 525, 526, 527, 529, 530,
-                531, 532, 534, -1
-        ],
-	name = 'tch_afs_4_75',
-	description = """TCH/AFS 4.75 kbits convolutional code:
-        G4/G6 = 1 + D2 + D3 + D5 + D6 / 1 + D + D2 + D3 + D4 + D6
-        G4/G6 = 1 + D2 + D3 + D5 + D6 / 1 + D + D2 + D3 + D4 + D6
-        G5/G6 = 1 + D + D4 + D6       / 1 + D + D2 + D3 + D4 + D6
-        G6/G6 = 1
-        G6/G6 = 1
-"""
-)
+	# TCH_AFS_5_9 definition
+	ConvolutionalCode(
+		124,
+		[
+			( G4, G6 ),
+			( G5, G6 ),
+			(  1,  1),
+			(  1,  1),
+		],
+		puncture = [
+			  0,   1,   3,   5,   7,  11,  15,  31,  47,  63,  79,  95,
+			111, 127, 143, 159, 175, 191, 207, 223, 239, 255, 271, 287,
+			303, 319, 327, 331, 335, 343, 347, 351, 359, 363, 367, 375,
+			379, 383, 391, 395, 399, 407, 411, 415, 423, 427, 431, 439,
+			443, 447, 455, 459, 463, 467, 471, 475, 479, 483, 487, 491,
+			495, 499, 503, 507, 509, 511, 512, 513, 515, 516, 517, 519,
+			-1
+		],
+		name = 'tch_afs_5_9',
+		description = [
+			"TCH/AFS 5.9 kbits convolutional code:",
+			"124 bits",
+			"G4/G6 = 1 + D2 + D3 + D5 + D6 / 1 + D + D2 + D3 + D4 + D6",
+			"G5/G6 = 1 + D + D4 + D6       / 1 + D + D2 + D3 + D4 + D6",
+			"G6/G6 = 1",
+			"G6/G6 = 1",
+		]
+	),
 
-def gen_c(dest, pref, code):
-	f = open(os.path.join(dest, 'conv_' + code.name + '_gen.c'), 'w')
+	# TCH_AFS_5_15 definition
+	ConvolutionalCode(
+		109,
+		[
+			( G1, G3 ),
+			( G1, G3 ),
+			( G2, G3 ),
+			(  1,  1 ),
+			(  1,  1 ),
+		],
+		puncture = [
+			  0,   4,   5,   9,  10,  14,  15,  20,  25,  30,  35,  40,
+			 50,  60,  70,  80,  90, 100, 110, 120, 130, 140, 150, 160,
+			170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280,
+			290, 300, 310, 315, 320, 325, 330, 334, 335, 340, 344, 345,
+			350, 354, 355, 360, 364, 365, 370, 374, 375, 380, 384, 385,
+			390, 394, 395, 400, 404, 405, 410, 414, 415, 420, 424, 425,
+			430, 434, 435, 440, 444, 445, 450, 454, 455, 460, 464, 465,
+			470, 474, 475, 480, 484, 485, 490, 494, 495, 500, 504, 505,
+			510, 514, 515, 520, 524, 525, 529, 530, 534, 535, 539, 540,
+			544, 545, 549, 550, 554, 555, 559, 560, 564, -1
+		],
+		name = 'tch_afs_5_15',
+		description = [
+			"TCH/AFS 5.15 kbits convolutional code:",
+			"G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4",
+			"G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4",
+			"G2/G3 = 1 + D2 + D4     / 1 + D + D2 + D3 + D4",
+			"G3/G3 = 1",
+			"G3/G3 = 1",
+		]
+	),
+
+	# TCH_AFS_4_75 definition
+	ConvolutionalCode(
+		101,
+		[
+			( G4, G6 ),
+			( G4, G6 ),
+			( G5, G6 ),
+			(  1,  1 ),
+			(  1,  1 ),
+		],
+		puncture = [
+			  0,   1,   2,   4,   5,   7,   9,  15,  25,  35,  45,  55,
+			 65,  75,  85,  95, 105, 115, 125, 135, 145, 155, 165, 175,
+			185, 195, 205, 215, 225, 235, 245, 255, 265, 275, 285, 295,
+			305, 315, 325, 335, 345, 355, 365, 375, 385, 395, 400, 405,
+			410, 415, 420, 425, 430, 435, 440, 445, 450, 455, 459, 460,
+			465, 470, 475, 479, 480, 485, 490, 495, 499, 500, 505, 509,
+			510, 515, 517, 519, 520, 522, 524, 525, 526, 527, 529, 530,
+			531, 532, 534, -1
+		],
+		name = 'tch_afs_4_75',
+		description = [
+			"TCH/AFS 4.75 kbits convolutional code:",
+			"G4/G6 = 1 + D2 + D3 + D5 + D6 / 1 + D + D2 + D3 + D4 + D6",
+			"G4/G6 = 1 + D2 + D3 + D5 + D6 / 1 + D + D2 + D3 + D4 + D6",
+			"G5/G6 = 1 + D + D4 + D6       / 1 + D + D2 + D3 + D4 + D6",
+			"G6/G6 = 1",
+			"G6/G6 = 1",
+		]
+	),
+
+	# TCH_FR definition
+	ConvolutionalCode(
+		185,
+		CCH_poly,
+		name = "tch_fr",
+		description = ["TCH/F convolutional code"]
+	),
+
+	# TCH_HR definition
+	ConvolutionalCode(
+		98,
+		[
+			( G4, 1 ),
+			( G5, 1 ),
+			( G6, 1 ),
+		],
+		puncture = [
+			  1,   4,   7,  10,  13,  16,  19,  22,  25,  28,  31,  34,
+			 37,  40,  43,  46,  49,  52,  55,  58,  61,  64,  67,  70,
+			 73,  76,  79,  82,  85,  88,  91,  94,  97, 100, 103, 106,
+			109, 112, 115, 118, 121, 124, 127, 130, 133, 136, 139, 142,
+			145, 148, 151, 154, 157, 160, 163, 166, 169, 172, 175, 178,
+			181, 184, 187, 190, 193, 196, 199, 202, 205, 208, 211, 214,
+			217, 220, 223, 226, 229, 232, 235, 238, 241, 244, 247, 250,
+			253, 256, 259, 262, 265, 268, 271, 274, 277, 280, 283, 295,
+			298, 301, 304, 307, 310, -1,
+		],
+		name = "tch_hr",
+		description = ["TCH/H convolutional code"]
+	),
+
+	# TCH_AHS_7_95 definition
+	ConvolutionalCode(
+		129,
+		[
+			(  1,  1 ),
+			( G1, G0 ),
+		],
+		puncture = [
+			  1,   3,   5,   7,  11,  15,  19,  23,  27,  31,  35,  43,
+			 47,  51,  55,  59,  63,  67,  71,  79,  83,  87,  91,  95,
+			 99, 103, 107, 115, 119, 123, 127, 131, 135, 139, 143, 151,
+			155, 159, 163, 167, 171, 175, 177, 179, 183, 185, 187, 191,
+			193, 195, 197, 199, 203, 205, 207, 211, 213, 215, 219, 221,
+			223, 227, 229, 231, 233, 235, 239, 241, 243, 247, 249, 251,
+			255, 257, 259, 261, 263, 265, -1,
+		],
+		name = "tch_ahs_7_95",
+		description = ["TCH/AHS 7.95 kbits convolutional code"]
+	),
+
+	# TCH_AHS_7_4 definition
+	ConvolutionalCode(
+		126,
+		[
+			(  1,  1 ),
+			( G1, G0 ),
+		],
+		puncture = [
+			  1,   3,   7,  11,  19,  23,  27,  35,  39,  43,  51,  55,
+			 59,  67,  71,  75,  83,  87,  91,  99, 103, 107, 115, 119,
+			123, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171,
+			175, 179, 183, 187, 191, 195, 199, 203, 207, 211, 215, 219,
+			221, 223, 227, 229, 231, 235, 237, 239, 243, 245, 247, 251,
+			253, 255, 257, 259, -1,
+		],
+		name = "tch_ahs_7_4",
+		description = ["TCH/AHS 7.4 kbits convolutional code"]
+	),
+
+	# TCH_AHS_6_7 definition
+	ConvolutionalCode(
+		116,
+		[
+			(  1,  1 ),
+			( G1, G0 ),
+		],
+		puncture = [
+			  1,   3,   9,  19,  29,  39,  49,  59,  69,  79,  89,  99,
+			109, 119, 129, 139, 149, 159, 167, 169, 177, 179, 187, 189,
+			197, 199, 203, 207, 209, 213, 217, 219, 223, 227, 229, 231,
+			233, 235, 237, 239, -1,
+		],
+		name = "tch_ahs_6_7",
+		description = ["TCH/AHS 6.7 kbits convolutional code"]
+	),
+
+	# TCH_AHS_5_9 definition
+	ConvolutionalCode(
+		108,
+		[
+			(  1,  1 ),
+			( G1, G0 ),
+		],
+		puncture = [
+			  1,  15,  71, 127, 139, 151, 163, 175, 187, 195, 203, 211,
+			215, 219, 221, 223, -1,
+		],
+		name = "tch_ahs_5_9",
+		description = ["TCH/AHS 5.9 kbits convolutional code"]
+	),
+
+	# TCH_AHS_5_15 definition
+	ConvolutionalCode(
+		97,
+		[
+			( G1, G3 ),
+			( G2, G3 ),
+			(  1,  1 ),
+		],
+		puncture = [
+			  0,   1,   3,   4,   6,   9,  12,  15,  18,  21,  27,  33,
+			 39,  45,  51,  54, 57,  63,  69,  75,  81,  87,  90,  93,
+			 99, 105, 111, 117, 123, 126, 129, 135, 141, 147, 153, 159,
+			162, 165, 168, 171, 174, 177, 180, 183, 186, 189, 192, 195,
+			198, 201, 204, 207, 210, 213, 216, 219, 222, 225, 228, 231,
+			234, 237, 240, 243, 244, 246, 249, 252, 255, 256, 258, 261,
+			264, 267, 268, 270, 273, 276, 279, 280, 282, 285, 288, 289,
+			291, 294, 295, 297, 298, 300, 301, -1,
+		],
+		name = "tch_ahs_5_15",
+		description = ["TCH/AHS 5.15 kbits convolutional code"]
+	),
+
+	# TCH_AHS_4_75 definition
+	ConvolutionalCode(
+		89,
+		[
+			(  1,  1 ),
+			( G5, G4 ),
+			( G6, G4 ),
+		],
+		puncture = [
+			  1,   2,   4,   5,   7,   8,  10,  13,  16,  22,  28,  34,
+			 40,  46,  52,  58, 64,  70,  76,  82,  88,  94, 100, 106,
+			112, 118, 124, 130, 136, 142, 148, 151, 154, 160, 163, 166,
+			172, 175, 178, 184, 187, 190, 196, 199, 202, 208, 211, 214,
+			220, 223, 226, 232, 235, 238, 241, 244, 247, 250, 253, 256,
+			259, 262, 265, 268, 271, 274, 275, 277, 278, 280, 281, 283,
+			284, -1,
+		],
+		name = "tch_ahs_4_75",
+		description = ["TCH/AHS 4.75 kbits convolutional code"]
+	),
+]
+
+if __name__ == '__main__':
+	path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
+	prefix = "gsm0503"
+
+	print >>sys.stderr, "Generating convolutional codes..."
+
+	# Open a new file for writing
+	f = open(os.path.join(path, "gsm0503_conv.c"), 'w')
 	print >>f, mod_license
 	print >>f, "#include <stdint.h>"
 	print >>f, "#include <osmocom/core/conv.h>"
-	code.gen_tables(pref, f)
 
-if __name__ == '__main__':
-	print >>sys.stderr, "Generating convolutional codes..."
-	prefix = "gsm0503"
-	path = sys.argv[1] if len(sys.argv) > 1 else os.getcwd()
-	gen_c(path, prefix, xCCH)
-	gen_c(path, prefix, CS2)
-	gen_c(path, prefix, CS3)
-	gen_c(path, prefix, TCH_AFS_12_2)
-	gen_c(path, prefix, TCH_AFS_10_2)
-	gen_c(path, prefix, TCH_AFS_7_95)
-	gen_c(path, prefix, TCH_AFS_7_4)
-	gen_c(path, prefix, TCH_AFS_6_7)
-	gen_c(path, prefix, TCH_AFS_5_9)
-	gen_c(path, prefix, TCH_AFS_5_15)
-	gen_c(path, prefix, TCH_AFS_4_75)
-	print >>sys.stderr, "\tdone."
+	# Generate the tables one by one
+	for code in conv_codes:
+		print >>sys.stderr, "Generate '%s' definition" % code.name
+		code.gen_tables(prefix, f)
+
+	print >>sys.stderr, "Generation complete."

-- 
To view, visit https://gerrit.osmocom.org/816
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I257a5d015798ee9e690fd035ca97fd971cf9f60a
Gerrit-PatchSet: 1
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Owner: Vadim Yanitskiy <axilirator at gmail.com>



More information about the gerrit-log mailing list