edge: Add methods and operators to GprsCodingScheme

Add a few new operators and methods to support the use of
GprsCodingScheme instead of the plain integer currently used.

Sponsored-by: On-Waves ehf
diff --git a/src/gprs_coding_scheme.cpp b/src/gprs_coding_scheme.cpp
index 04eb3b6..a460103 100644
--- a/src/gprs_coding_scheme.cpp
+++ b/src/gprs_coding_scheme.cpp
@@ -120,3 +120,59 @@
 {
 	return mcs_info[m_scheme].data_hdr;
 }
+
+void GprsCodingScheme::inc(Mode mode)
+{
+	if (!isCompatible(mode))
+		/* This should not happen. TODO: Use assert? */
+		return;
+
+	Scheme new_cs(Scheme(m_scheme + 1));
+	if (!GprsCodingScheme(new_cs).isCompatible(mode))
+		/* Clipping, do not change the value */
+		return;
+
+	m_scheme = new_cs;
+}
+
+void GprsCodingScheme::dec(Mode mode)
+{
+	if (!isCompatible(mode))
+		/* This should not happen. TODO: Use assert? */
+		return;
+
+	Scheme new_cs(Scheme(m_scheme - 1));
+	if (!GprsCodingScheme(new_cs).isCompatible(mode))
+		/* Clipping, do not change the value */
+		return;
+
+	m_scheme = new_cs;
+}
+
+void GprsCodingScheme::inc()
+{
+	if (isGprs() && m_scheme == CS4)
+		return;
+
+	if (isEgprs() && m_scheme == MCS9)
+		return;
+
+	if (!isValid())
+		return;
+
+	m_scheme = Scheme(m_scheme + 1);
+}
+
+void GprsCodingScheme::dec()
+{
+	if (isGprs() && m_scheme == CS1)
+		return;
+
+	if (isEgprs() && m_scheme == MCS1)
+		return;
+
+	if (!isValid())
+		return;
+
+	m_scheme = Scheme(m_scheme - 1);
+}
diff --git a/src/gprs_coding_scheme.h b/src/gprs_coding_scheme.h
index a91d1bd..d1fc064 100644
--- a/src/gprs_coding_scheme.h
+++ b/src/gprs_coding_scheme.h
@@ -53,16 +53,23 @@
 
 	operator bool() const {return m_scheme != UNKNOWN;}
 	operator int()  const {return (int)m_scheme;}
-	void operator =(Scheme s);
-	void operator =(GprsCodingScheme o);
+	operator Scheme() const {return m_scheme;}
+	unsigned int to_num() const;
+
+	GprsCodingScheme& operator =(Scheme s);
+	GprsCodingScheme& operator =(GprsCodingScheme o);
+
 	bool isValid()   const {return UNKNOWN <= m_scheme && m_scheme <= MCS9;}
 	bool isGprs()   const {return CS1 <= m_scheme && m_scheme <= CS4;}
 	bool isEgprs()  const {return m_scheme >= MCS1;}
 	bool isEgprsGmsk()  const {return isEgprs() && m_scheme <= MCS4;}
 	bool isCompatible(Mode mode) const;
+	bool isCompatible(GprsCodingScheme o) const;
 
 	void inc(Mode mode);
 	void dec(Mode mode);
+	void inc();
+	void dec();
 
 	unsigned int sizeUL() const;
 	unsigned int sizeDL() const;
@@ -77,11 +84,24 @@
 	HeaderType headerTypeControl() const;
 
 	static GprsCodingScheme getBySizeUL(unsigned size);
+	static GprsCodingScheme getGprsByNum(unsigned num);
+	static GprsCodingScheme getEgprsByNum(unsigned num);
 
 private:
 	enum Scheme m_scheme;
 };
 
+inline unsigned int GprsCodingScheme::to_num() const
+{
+	if (isGprs())
+		return (m_scheme - CS1) + 1;
+
+	if (isEgprs())
+		return (m_scheme - MCS1) + 1;
+
+	return 0;
+}
+
 inline bool GprsCodingScheme::isCompatible(Mode mode) const
 {
 	switch (mode) {
@@ -93,32 +113,9 @@
 	return false;
 }
 
-inline void GprsCodingScheme::inc(Mode mode)
+inline bool GprsCodingScheme::isCompatible(GprsCodingScheme o) const
 {
-	if (!isCompatible(mode))
-		/* This should not happen. TODO: Use assert? */
-		return;
-
-	Scheme new_cs(Scheme(m_scheme + 1));
-	if (!GprsCodingScheme(new_cs).isCompatible(mode))
-		/* Clipping, do not change the value */
-		return;
-
-	m_scheme = new_cs;
-}
-
-inline void GprsCodingScheme::dec(Mode mode)
-{
-	if (!isCompatible(mode))
-		/* This should not happen. TODO: Use assert? */
-		return;
-
-	Scheme new_cs(Scheme(m_scheme - 1));
-	if (!GprsCodingScheme(new_cs).isCompatible(mode))
-		/* Clipping, do not change the value */
-		return;
-
-	m_scheme = new_cs;
+	return (isGprs() && o.isGprs()) || (isEgprs() && o.isEgprs());
 }
 
 inline GprsCodingScheme::HeaderType GprsCodingScheme::headerTypeControl() const
@@ -133,15 +130,66 @@
 		m_scheme = UNKNOWN;
 }
 
-inline void GprsCodingScheme::operator =(Scheme s)
+inline GprsCodingScheme& GprsCodingScheme::operator =(Scheme s)
 {
 	m_scheme = s;
 
 	if (!isValid())
 		m_scheme = UNKNOWN;
+
+	return *this;
 }
 
-inline void GprsCodingScheme::operator =(GprsCodingScheme o)
+inline GprsCodingScheme& GprsCodingScheme::operator =(GprsCodingScheme o)
 {
 	m_scheme = o.m_scheme;
+	return *this;
 }
+
+inline GprsCodingScheme GprsCodingScheme::getGprsByNum(unsigned num)
+{
+	if (num < 1 || num > 4)
+		return GprsCodingScheme();
+
+	return GprsCodingScheme(Scheme(CS1 + (num - 1)));
+}
+
+inline GprsCodingScheme GprsCodingScheme::getEgprsByNum(unsigned num)
+{
+	if (num < 1 || num > 9)
+		return GprsCodingScheme();
+
+	return GprsCodingScheme(Scheme(MCS1 + (num - 1)));
+}
+
+/* The coding schemes form a partial ordering */
+inline bool operator ==(GprsCodingScheme a, GprsCodingScheme b)
+{
+	return int(a) == int(b);
+}
+
+inline bool operator !=(GprsCodingScheme a, GprsCodingScheme b)
+{
+	return !(a == b);
+}
+
+inline bool operator <(GprsCodingScheme a, GprsCodingScheme b)
+{
+	return a.isCompatible(b) && int(a) < int(b);
+}
+
+inline bool operator >(GprsCodingScheme a, GprsCodingScheme b)
+{
+	return a.isCompatible(b) && int(a) > int(b);
+}
+
+inline bool operator <=(GprsCodingScheme a, GprsCodingScheme b)
+{
+	return a == b || a < b;
+}
+
+inline bool operator >=(GprsCodingScheme a, GprsCodingScheme b)
+{
+	return a == b || a > b;
+}
+
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index 8bac99f..e805992 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -749,7 +749,7 @@
 		/* Get statistics for current CS */
 
 		/* TODO: Use GprsCodingScheme everywhere and remove cast */
-		if (rlc_data->cs != (GprsCodingScheme::Scheme)current_cs()) {
+		if (rlc_data->cs != GprsCodingScheme((GprsCodingScheme::Scheme)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. */
diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp
index 5756774..2195659 100644
--- a/tests/edge/EdgeTest.cpp
+++ b/tests/edge/EdgeTest.cpp
@@ -113,7 +113,8 @@
 
 	GprsCodingScheme cs;
 	OSMO_ASSERT(!cs);
-	OSMO_ASSERT(cs == GprsCodingScheme::UNKNOWN);
+	OSMO_ASSERT(GprsCodingScheme::Scheme(cs) == GprsCodingScheme::UNKNOWN);
+	OSMO_ASSERT(cs == GprsCodingScheme(GprsCodingScheme::UNKNOWN));
 	OSMO_ASSERT(!cs.isCompatible(GprsCodingScheme::GPRS));
 	OSMO_ASSERT(!cs.isCompatible(GprsCodingScheme::EGPRS_GMSK));
 	OSMO_ASSERT(!cs.isCompatible(GprsCodingScheme::EGPRS));
@@ -126,7 +127,7 @@
 		OSMO_ASSERT(current_cs.isGprs());
 		OSMO_ASSERT(!current_cs.isEgprs());
 		OSMO_ASSERT(!current_cs.isEgprsGmsk());
-		OSMO_ASSERT(current_cs == gprs_schemes[i]);
+		OSMO_ASSERT(GprsCodingScheme::Scheme(current_cs) == gprs_schemes[i]);
 		OSMO_ASSERT(current_cs == GprsCodingScheme(gprs_schemes[i]));
 
 		/* Check strong monotonicity */
@@ -153,7 +154,7 @@
 		OSMO_ASSERT(!current_cs.isGprs());
 		OSMO_ASSERT(current_cs.isEgprs());
 		OSMO_ASSERT(!!current_cs.isEgprsGmsk() == !!egprs_schemes[i].is_gmsk);
-		OSMO_ASSERT(current_cs == egprs_schemes[i].s);
+		OSMO_ASSERT(GprsCodingScheme::Scheme(current_cs) == egprs_schemes[i].s);
 		OSMO_ASSERT(current_cs == GprsCodingScheme(egprs_schemes[i].s));
 
 		/* Check strong monotonicity */