edge: Replace integer cs by GprsCodingScheme

Currently the TBF and MS object use a plain integer value
(current_cs) to manage the coding scheme. This makes it difficult to
support the MCS schemes. GprsCodingScheme supports a partial ordering
of these values (CS and MCS) and provides safe increment and
decrement methods.

Use the GprsCodingScheme type instead of integer for cs fields and
variables. Add a 'mode' to GprsMs which can be set to either GPRS,
EGPRS, or EGPRS_GMSK which also set the initial values of
current_cs_ul/dl. Select the mode based on max_mcs_ul and max_mcs_dl.

Sponsored-by: On-Waves ehf
diff --git a/src/encoding.cpp b/src/encoding.cpp
index 158625e..acd8f43 100644
--- a/src/encoding.cpp
+++ b/src/encoding.cpp
@@ -193,7 +193,7 @@
 
 	if (!use_egprs) {
 		bitvec_write_field(dest, wp,0x0,1); // Message escape
-		bitvec_write_field(dest, wp,tbf->current_cs()-1, 2); // CHANNEL_CODING_COMMAND 
+		bitvec_write_field(dest, wp,tbf->current_cs().to_num()-1, 2); // CHANNEL_CODING_COMMAND 
 		bitvec_write_field(dest, wp,0x1,1); // TLLI_BLOCK_CHANNEL_CODING 
 		bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_VALUE = on
 		bitvec_write_field(dest, wp,tbf->ta(),6); // TIMING_ADVANCE_VALUE
@@ -209,7 +209,7 @@
 		bitvec_write_field(dest, wp,0x0,2); // EGPRS message contents
 		bitvec_write_field(dest, wp,0x0,1); // No CONTENTION_RESOLUTION_TLLI
 		bitvec_write_field(dest, wp,0x0,1); // No COMPACT reduced MA
-		bitvec_write_field(dest, wp,tbf->current_cs()-1, 4); // EGPRS Modulation and Coding IE
+		bitvec_write_field(dest, wp,tbf->current_cs().to_num()-1, 4); // EGPRS Modulation and Coding IE
 		bitvec_write_field(dest, wp,0x0,1); // No RESEGMENT
 		bitvec_write_field(dest, wp,0x0,5); // EGPRS Window Size = 64
 		bitvec_write_field(dest, wp,0x0,1); // No Access Technologies Request
@@ -426,7 +426,7 @@
 	struct gprs_rlcmac_ul_tbf *tbf, bool is_final)
 {
 
-	bitvec_write_field(dest, wp, tbf->current_cs() - 1, 2); // CHANNEL_CODING_COMMAND
+	bitvec_write_field(dest, wp, tbf->current_cs().to_num() - 1, 2); // CHANNEL_CODING_COMMAND
 	write_packet_ack_nack_desc_gprs(bts, dest, wp, &tbf->m_window, is_final);
 
 	bitvec_write_field(dest, wp, 1, 1); // 1: have CONTENTION_RESOLUTION_TLLI
diff --git a/src/gprs_ms.cpp b/src/gprs_ms.cpp
index 2d48284..187132f 100644
--- a/src/gprs_ms.cpp
+++ b/src/gprs_ms.cpp
@@ -97,8 +97,6 @@
 	m_ta(0),
 	m_ms_class(0),
 	m_egprs_ms_class(0),
-	m_current_cs_ul(1),
-	m_current_cs_dl(1),
 	m_is_idle(true),
 	m_ref(0),
 	m_list(this),
@@ -107,7 +105,8 @@
 	m_reserved_dl_slots(0),
 	m_reserved_ul_slots(0),
 	m_current_trx(NULL),
-	m_codel_state(NULL)
+	m_codel_state(NULL),
+	m_mode(GprsCodingScheme::GPRS)
 {
 	int codel_interval = LLC_CODEL_USE_DEFAULT;
 
@@ -117,17 +116,11 @@
 	memset(&m_timer, 0, sizeof(m_timer));
 	m_timer.cb = GprsMs::timeout;
 	m_llc_queue.init();
-	if (m_bts) {
-		m_current_cs_ul = m_bts->bts_data()->initial_cs_ul;
-		if (m_current_cs_ul < 1)
-			m_current_cs_ul = 1;
 
-		m_current_cs_dl = m_bts->bts_data()->initial_cs_dl;
-		if (m_current_cs_dl < 1)
-			m_current_cs_dl = 1;
+	set_mode(m_mode);
 
+	if (m_bts)
 		codel_interval = m_bts->bts_data()->llc_codel_interval_msec;
-	}
 
 	if (codel_interval) {
 		if (codel_interval == LLC_CODEL_USE_DEFAULT)
@@ -215,6 +208,42 @@
 	unref();
 }
 
+void GprsMs::set_mode(GprsCodingScheme::Mode mode)
+{
+	m_mode = mode;
+
+	switch (m_mode) {
+	case GprsCodingScheme::GPRS:
+		if (m_bts) {
+			m_current_cs_ul = GprsCodingScheme::getGprsByNum(
+				m_bts->bts_data()->initial_cs_ul);
+			m_current_cs_dl = GprsCodingScheme::getGprsByNum(
+				m_bts->bts_data()->initial_cs_dl);
+		}
+		if (!m_current_cs_ul.isGprs())
+			m_current_cs_ul = GprsCodingScheme::CS1;
+		if (!m_current_cs_dl.isGprs())
+			m_current_cs_dl = GprsCodingScheme::CS1;
+
+		break;
+
+	case GprsCodingScheme::EGPRS_GMSK:
+	case GprsCodingScheme::EGPRS:
+		if (m_bts) {
+			m_current_cs_ul = GprsCodingScheme::getEgprsByNum(
+				m_bts->bts_data()->initial_mcs_ul);
+			m_current_cs_dl = GprsCodingScheme::getEgprsByNum(
+				m_bts->bts_data()->initial_mcs_dl);
+		}
+		if (!m_current_cs_ul.isEgprs())
+			m_current_cs_ul = GprsCodingScheme::MCS1;
+		if (!m_current_cs_dl.isEgprs())
+			m_current_cs_dl = GprsCodingScheme::MCS1;
+
+		break;
+	}
+}
+
 void GprsMs::attach_tbf(struct gprs_rlcmac_tbf *tbf)
 {
 	if (tbf->direction == GPRS_RLCMAC_DL_TBF)
@@ -464,9 +493,9 @@
 {
 	struct gprs_rlcmac_bts *bts_data;
 	int64_t now;
-	uint8_t max_cs_dl = 4;
+	GprsCodingScheme max_cs_dl = this->max_cs_dl();
 
-	OSMO_ASSERT(m_bts != NULL);
+	OSMO_ASSERT(max_cs_dl);
 	bts_data = m_bts->bts_data();
 
 	if (error_rate < 0)
@@ -474,32 +503,30 @@
 
 	now = now_msec();
 
-	if (bts_data->max_cs_dl)
-		max_cs_dl = bts_data->max_cs_dl;
-
 	/* TODO: Check for TBF direction */
 	/* TODO: Support different CS values for UL and DL */
 
 	m_nack_rate_dl = error_rate;
 
 	if (error_rate > bts_data->cs_adj_upper_limit) {
-		if (m_current_cs_dl > 1) {
-			m_current_cs_dl -= 1;
+		if (m_current_cs_dl.to_num() > 1) {
+			m_current_cs_dl.dec(mode());
 			LOGP(DRLCMACDL, LOGL_INFO,
 				"MS (IMSI %s): High error rate %d%%, "
-				"reducing CS level to %d\n",
-				imsi(), error_rate, m_current_cs_dl);
+				"reducing CS level to %s\n",
+				imsi(), error_rate, m_current_cs_dl.name());
 			m_last_cs_not_low = now;
 		}
 	} else if (error_rate < bts_data->cs_adj_lower_limit) {
 		if (m_current_cs_dl < max_cs_dl) {
 		       if (now - m_last_cs_not_low > 1000) {
-			       m_current_cs_dl += 1;
+			       m_current_cs_dl.inc(mode());
 
 			       LOGP(DRLCMACDL, LOGL_INFO,
 				       "MS (IMSI %s): Low error rate %d%%, "
-				       "increasing DL CS level to %d\n",
-				       imsi(), error_rate, m_current_cs_dl);
+				       "increasing DL CS level to %s\n",
+				       imsi(), error_rate,
+				       m_current_cs_dl.name());
 			       m_last_cs_not_low = now;
 		       } else {
 			       LOGP(DRLCMACDL, LOGL_DEBUG,
@@ -516,46 +543,125 @@
 	}
 }
 
-void GprsMs::update_l1_meas(const pcu_l1_meas *meas)
+GprsCodingScheme GprsMs::max_cs_ul() const
 {
 	struct gprs_rlcmac_bts *bts_data;
-	uint8_t max_cs_ul = 4;
-	unsigned i;
 
 	OSMO_ASSERT(m_bts != NULL);
 	bts_data = m_bts->bts_data();
 
-	if (bts_data->max_cs_ul)
-		max_cs_ul = bts_data->max_cs_ul;
+	if (m_current_cs_ul.isGprs()) {
+		if (!bts_data->max_cs_ul)
+			return GprsCodingScheme(GprsCodingScheme::CS4);
 
-	if (meas->have_link_qual) {
-		int old_link_qual = meas->link_qual;
-		int low  = bts_data->cs_lqual_ranges[current_cs_ul()-1].low;
-		int high  = bts_data->cs_lqual_ranges[current_cs_ul()-1].high;
-		uint8_t new_cs_ul = m_current_cs_ul;
-
-		if (m_l1_meas.have_link_qual)
-		       old_link_qual = m_l1_meas.link_qual;
-
-		if (meas->link_qual < low &&  old_link_qual < low)
-			new_cs_ul = m_current_cs_ul - 1;
-		else if (meas->link_qual > high &&  old_link_qual > high &&
-			m_current_cs_ul < max_cs_ul)
-			new_cs_ul = m_current_cs_ul + 1;
-
-		if (m_current_cs_ul != new_cs_ul) {
-			LOGP(DRLCMACDL, LOGL_INFO,
-				"MS (IMSI %s): "
-				"Link quality %ddB (%ddB) left window [%d, %d], "
-				"modifying uplink CS level: %d -> %d\n",
-				imsi(), meas->link_qual, old_link_qual,
-				low, high,
-				m_current_cs_ul, new_cs_ul);
-
-			m_current_cs_ul = new_cs_ul;
-		}
+		return GprsCodingScheme::getGprsByNum(bts_data->max_cs_ul);
 	}
 
+	if (!m_current_cs_ul.isEgprs())
+		return GprsCodingScheme(); /* UNKNOWN */
+
+	if (bts_data->max_mcs_ul)
+		return GprsCodingScheme::getEgprsByNum(bts_data->max_mcs_ul);
+	else if (bts_data->max_cs_ul)
+		return GprsCodingScheme::getEgprsByNum(bts_data->max_cs_ul);
+
+	return GprsCodingScheme(GprsCodingScheme::MCS4);
+}
+
+GprsCodingScheme GprsMs::max_cs_dl() const
+{
+	struct gprs_rlcmac_bts *bts_data;
+
+	OSMO_ASSERT(m_bts != NULL);
+	bts_data = m_bts->bts_data();
+
+	if (m_current_cs_dl.isGprs()) {
+		if (!bts_data->max_cs_dl)
+			return GprsCodingScheme(GprsCodingScheme::CS4);
+
+		return GprsCodingScheme::getGprsByNum(bts_data->max_cs_dl);
+	}
+
+	if (!m_current_cs_dl.isEgprs())
+		return GprsCodingScheme(); /* UNKNOWN */
+
+	if (bts_data->max_mcs_dl)
+		return GprsCodingScheme::getEgprsByNum(bts_data->max_mcs_dl);
+	else if (bts_data->max_cs_dl)
+		return GprsCodingScheme::getEgprsByNum(bts_data->max_cs_dl);
+
+	return GprsCodingScheme(GprsCodingScheme::MCS4);
+}
+
+void GprsMs::update_cs_ul(const pcu_l1_meas *meas)
+{
+	struct gprs_rlcmac_bts *bts_data;
+	GprsCodingScheme max_cs_ul = this->max_cs_ul();
+
+	int old_link_qual;
+	int low;
+	int high;
+	GprsCodingScheme new_cs_ul = m_current_cs_ul;
+	unsigned current_cs_num = m_current_cs_ul.to_num();
+
+	bts_data = m_bts->bts_data();
+
+	if (!max_cs_ul) {
+		LOGP(DRLCMACDL, LOGL_ERROR,
+			"max_cs_ul cannot be derived (current UL CS: %s)\n",
+			m_current_cs_ul.name());
+		return;
+	}
+
+	if (!m_current_cs_ul)
+		return;
+
+	if (!meas->have_link_qual)
+		return;
+
+	old_link_qual = meas->link_qual;
+
+	if (m_current_cs_ul.isGprs()) {
+		low  = bts_data->cs_lqual_ranges[current_cs_num-1].low;
+		high = bts_data->cs_lqual_ranges[current_cs_num-1].high;
+	} else if (m_current_cs_ul.isEgprs()) {
+		/* TODO, use separate table */
+		if (current_cs_num > 4)
+			current_cs_num = 4;
+		low  = bts_data->cs_lqual_ranges[current_cs_num-1].low;
+		high = bts_data->cs_lqual_ranges[current_cs_num-1].high;
+	} else {
+		return;
+	}
+
+	if (m_l1_meas.have_link_qual)
+		old_link_qual = m_l1_meas.link_qual;
+
+	if (meas->link_qual < low &&  old_link_qual < low)
+		new_cs_ul.dec(mode());
+	else if (meas->link_qual > high &&  old_link_qual > high &&
+		m_current_cs_ul < max_cs_ul)
+		new_cs_ul.inc(mode());
+
+	if (m_current_cs_ul != new_cs_ul) {
+		LOGP(DRLCMACDL, LOGL_INFO,
+			"MS (IMSI %s): "
+			"Link quality %ddB (%ddB) left window [%d, %d], "
+			"modifying uplink CS level: %s -> %s\n",
+			imsi(), meas->link_qual, old_link_qual,
+			low, high,
+			m_current_cs_ul.name(), new_cs_ul.name());
+
+		m_current_cs_ul = new_cs_ul;
+	}
+}
+
+void GprsMs::update_l1_meas(const pcu_l1_meas *meas)
+{
+	unsigned i;
+
+	update_cs_ul(meas);
+
 	if (meas->have_rssi)
 		m_l1_meas.set_rssi(meas->rssi);
 	if (meas->have_bto)
@@ -582,9 +688,9 @@
 	}
 }
 
-uint8_t GprsMs::current_cs_dl() const
+GprsCodingScheme GprsMs::current_cs_dl() const
 {
-	uint8_t cs = m_current_cs_dl;
+	GprsCodingScheme cs = m_current_cs_dl;
 	size_t unencoded_octets;
 
 	if (!m_bts)
@@ -605,11 +711,11 @@
 		return cs;
 
 	/* The throughput would probably be better if the CS level was reduced */
-	cs -= 1;
+	cs.dec(mode());
 
 	/* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
-	if (cs == 2)
-		cs -= 1;
+	if (cs == GprsCodingScheme(GprsCodingScheme::CS2))
+		cs.dec(mode());
 
 	return cs;
 }
diff --git a/src/gprs_ms.h b/src/gprs_ms.h
index f9b63f2..246f71e 100644
--- a/src/gprs_ms.h
+++ b/src/gprs_ms.h
@@ -74,6 +74,8 @@
 	bool check_tlli(uint32_t tlli);
 
 	void reset();
+	GprsCodingScheme::Mode mode() const;
+	void set_mode(GprsCodingScheme::Mode mode);
 
 	const char *imsi() const;
 	void set_imsi(const char *imsi);
@@ -85,8 +87,10 @@
 	void set_ms_class(uint8_t ms_class);
 	void set_egprs_ms_class(uint8_t ms_class);
 
-	uint8_t current_cs_ul() const;
-	uint8_t current_cs_dl() const;
+	GprsCodingScheme current_cs_ul() const;
+	GprsCodingScheme current_cs_dl() const;
+	GprsCodingScheme max_cs_ul() const;
+	GprsCodingScheme max_cs_dl() const;
 
 	int first_common_ts() const;
 	uint8_t dl_slots() const;
@@ -134,6 +138,7 @@
 	void unref();
 	void start_timer();
 	void stop_timer();
+	void update_cs_ul(const pcu_l1_meas*);
 
 private:
 	BTS *m_bts;
@@ -152,8 +157,8 @@
 	uint8_t m_ms_class;
 	uint8_t m_egprs_ms_class;
 	/* current coding scheme */
-	uint8_t m_current_cs_ul;
-	uint8_t m_current_cs_dl;
+	GprsCodingScheme m_current_cs_ul;
+	GprsCodingScheme m_current_cs_dl;
 
 	gprs_llc_queue m_llc_queue;
 
@@ -172,6 +177,7 @@
 	gprs_rlcmac_trx *m_current_trx;
 
 	struct gprs_codel *m_codel_state;
+	GprsCodingScheme::Mode m_mode;
 };
 
 inline bool GprsMs::is_idle() const
@@ -220,11 +226,16 @@
 	return m_egprs_ms_class;
 }
 
-inline uint8_t GprsMs::current_cs_ul() const
+inline GprsCodingScheme GprsMs::current_cs_ul() const
 {
 	return m_current_cs_ul;
 }
 
+inline GprsCodingScheme::Mode GprsMs::mode() const
+{
+	return m_mode;
+}
+
 inline void GprsMs::set_timeout(unsigned secs)
 {
 	m_delay = secs;
diff --git a/src/pcu_vty_functions.cpp b/src/pcu_vty_functions.cpp
index 7082d99..c059233 100644
--- a/src/pcu_vty_functions.cpp
+++ b/src/pcu_vty_functions.cpp
@@ -55,7 +55,8 @@
 		if (tbf->pdch[i])
 			vty_out(vty, "%d ", i);
 	}
-	vty_out(vty, " CS=%d%s%s", tbf->ms() ? tbf->ms()->current_cs_dl() : 1,
+	vty_out(vty, " CS=%s%s%s",
+		tbf->ms() ? tbf->ms()->current_cs_dl().name() : "???",
 		VTY_NEWLINE, VTY_NEWLINE);
 }
 
@@ -83,10 +84,11 @@
 	llist_for_each(ms_iter, &bts->ms_store().ms_list()) {
 		GprsMs *ms = ms_iter->entry();
 
-		vty_out(vty, "MS TLLI=%08x, TA=%d, CS-UL=%d, CS-DL=%d, LLC=%d, "
+		vty_out(vty, "MS TLLI=%08x, TA=%d, CS-UL=%s, CS-DL=%s, LLC=%d, "
 			"IMSI=%s%s",
 			ms->tlli(),
-			ms->ta(), ms->current_cs_ul(), ms->current_cs_dl(),
+			ms->ta(), ms->current_cs_ul().name(),
+			ms->current_cs_dl().name(),
 			ms->llc_queue()->size(),
 			ms->imsi(),
 			VTY_NEWLINE);
@@ -101,9 +103,9 @@
 
 	vty_out(vty, "MS TLLI=%08x, IMSI=%s%s", ms->tlli(), ms->imsi(), VTY_NEWLINE);
 	vty_out(vty, "  Timing advance (TA):    %d%s", ms->ta(), VTY_NEWLINE);
-	vty_out(vty, "  Coding scheme uplink:   CS-%d%s", ms->current_cs_ul(),
+	vty_out(vty, "  Coding scheme uplink:   %s%s", ms->current_cs_ul().name(),
 		VTY_NEWLINE);
-	vty_out(vty, "  Coding scheme downlink: CS-%d%s", ms->current_cs_dl(),
+	vty_out(vty, "  Coding scheme downlink: %s%s", ms->current_cs_dl().name(),
 		VTY_NEWLINE);
 	vty_out(vty, "  MS class:               %d%s", ms->ms_class(), VTY_NEWLINE);
 	vty_out(vty, "  EGPRS MS class:         %d%s", ms->egprs_ms_class(), VTY_NEWLINE);
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 185f0bd..0da0557 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -165,15 +165,15 @@
 	m_ms_class = ms_class_;
 }
 
-uint8_t gprs_rlcmac_tbf::current_cs() const
+GprsCodingScheme gprs_rlcmac_tbf::current_cs() const
 {
-	uint8_t cs;
+	GprsCodingScheme cs;
 	if (direction == GPRS_RLCMAC_UL_TBF)
-		cs = m_ms ? m_ms->current_cs_ul() : bts->bts_data()->initial_cs_ul;
+		cs = m_ms ? m_ms->current_cs_ul() : GprsCodingScheme();
 	else
-		cs = m_ms ? m_ms->current_cs_dl() : bts->bts_data()->initial_cs_dl;
+		cs = m_ms ? m_ms->current_cs_dl() : GprsCodingScheme();
 
-	return cs < 1 ? 1 : cs;
+	return cs;
 }
 
 gprs_llc_queue *gprs_rlcmac_tbf::llc_queue()
@@ -543,10 +543,8 @@
 
 	bts = tbf->bts->bts_data();
 
-	if (tbf->is_egprs_enabled()) {
-		/* TODO: only for 8PSK, otherwise the GPRS MS class has to be used */
+	if (ms->mode() == GprsCodingScheme::EGPRS)
 		ms_class = egprs_ms_class;
-	}
 
 	tbf->m_created_ts = time(NULL);
 	tbf->set_ms_class(ms_class);
@@ -592,6 +590,17 @@
 	return 0;
 }
 
+static void setup_egprs_mode(gprs_rlcmac_bts *bts, GprsMs *ms)
+{
+	if (GprsCodingScheme::getEgprsByNum(bts->max_mcs_ul).isEgprsGmsk() &&
+		GprsCodingScheme::getEgprsByNum(bts->max_mcs_dl).isEgprsGmsk() &&
+		ms->mode() != GprsCodingScheme::EGPRS)
+	{
+		ms->set_mode(GprsCodingScheme::EGPRS_GMSK);
+	} else {
+		ms->set_mode(GprsCodingScheme::EGPRS);
+	}
+}
 
 struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
 	GprsMs *ms, int8_t use_trx,
@@ -616,11 +625,10 @@
 		ms = bts->bts->ms_alloc(ms_class, egprs_ms_class);
 
 	if (egprs_ms_class > 0 && bts->egprs_enabled) {
-		/* TODO: only for 8PSK, otherwise the GPRS MS class has to be used */
-		ms_class = egprs_ms_class;
 		tbf->enable_egprs();
 		tbf->m_window.set_sns(RLC_EGPRS_SNS);
 		tbf->m_window.set_ws(RLC_EGPRS_MIN_WS);
+		setup_egprs_mode(bts, ms);
 	}
 
 	rc = setup_tbf(tbf, ms, use_trx, ms_class, egprs_ms_class, single_slot);
diff --git a/src/tbf.h b/src/tbf.h
index 8ba6575..b00f4d5 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -134,7 +134,7 @@
 	void set_ta(uint8_t);
 	uint8_t ms_class() const;
 	void set_ms_class(uint8_t);
-	uint8_t current_cs() const;
+	GprsCodingScheme current_cs() const;
 	gprs_llc_queue *llc_queue();
 	const gprs_llc_queue *llc_queue() const;
 
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index e805992..9e73a0e 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -425,21 +425,15 @@
 	uint16_t space, chunk;
 	gprs_rlc_data *rlc_data;
 	const uint16_t bsn = m_window.v_s();
-	uint8_t cs_n = 1;
+	GprsCodingScheme cs = current_cs();
 
 	if (m_llc.frame_length() == 0)
 		schedule_next_frame();
 
-	cs_n = current_cs();
+	LOGP(DRLCMACDL, LOGL_DEBUG, "- Sending new block at BSN %d, CS=%s\n",
+		m_window.v_s(), cs.name());
 
-	LOGP(DRLCMACDL, LOGL_DEBUG, "- Sending new block at BSN %d, CS=%d\n",
-		m_window.v_s(), cs_n);
-
-	OSMO_ASSERT(cs_n >= 1);
-	OSMO_ASSERT(cs_n <= 4);
-
-	/* TODO: Use GprsCodingScheme everywhere and remove cast */
-	GprsCodingScheme cs((GprsCodingScheme::Scheme)cs_n);
+	OSMO_ASSERT(cs.isValid());
 
 	/* total length of block, including spare bits */
 	const uint8_t block_length = cs.sizeDL();
@@ -748,8 +742,7 @@
 
 		/* Get statistics for current CS */
 
-		/* TODO: Use GprsCodingScheme everywhere and remove cast */
-		if (rlc_data->cs != GprsCodingScheme((GprsCodingScheme::Scheme)current_cs())) {
+		if (rlc_data->cs != current_cs()) {
 			/* This block has already been encoded with a different
 			 * CS, so it doesn't help us to decide, whether the
 			 * current CS is ok. Ignore it. */