/* gprs_coding_scheme.h * * Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH * Author: Jacob Erlbeck * * 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 2 * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #pragma once #include #include class GprsCodingScheme { public: #define MAX_NUM_ARQ 2 /* max. number of ARQ */ #define MAX_NUM_MCS 9 /* max. number of MCS */ #define EGPRS_ARQ1 0x0 #define EGPRS_ARQ2 0x1 enum Scheme { UNKNOWN, CS1, CS2, CS3, CS4, MCS1, MCS2, MCS3, MCS4, MCS5, MCS6, MCS7, MCS8, MCS9, NUM_SCHEMES }; enum Mode { GPRS, EGPRS_GMSK, EGPRS, }; enum HeaderType { HEADER_INVALID, HEADER_GPRS_CONTROL, HEADER_GPRS_DATA, HEADER_EGPRS_DATA_TYPE_1, HEADER_EGPRS_DATA_TYPE_2, HEADER_EGPRS_DATA_TYPE_3, NUM_HEADER_TYPES }; enum Family { FAMILY_INVALID, FAMILY_A, FAMILY_B, FAMILY_C, }; GprsCodingScheme(Scheme s = UNKNOWN); operator bool() const {return m_scheme != UNKNOWN;} operator Scheme() const {return m_scheme;} unsigned int to_num() const; GprsCodingScheme& operator =(Scheme s); bool operator == (Scheme s) const; 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; bool isFamilyCompatible(GprsCodingScheme o) const; bool isCombinable(GprsCodingScheme o) const; void inc(Mode mode); void dec(Mode mode); void inc(); void dec(); void decToSingleBlock(bool *needStuffing); unsigned int sizeUL() const; unsigned int sizeDL() const; unsigned int usedSizeUL() const; unsigned int usedSizeDL() const; unsigned int maxBytesUL() const; unsigned int maxBytesDL() const; unsigned int spareBitsUL() const; unsigned int spareBitsDL() const; unsigned int maxDataBlockBytes() const; unsigned int numDataBlocks() const; unsigned int numDataHeaderBitsUL() const; unsigned int numDataHeaderBitsDL() const; unsigned int numDataBlockHeaderBits() const; unsigned int optionalPaddingBits() const; const char *name() const; HeaderType headerTypeData() const; HeaderType headerTypeControl() const; Family family() const; static GprsCodingScheme getBySizeUL(unsigned size); static GprsCodingScheme getGprsByNum(unsigned num); static GprsCodingScheme getEgprsByNum(unsigned num); static const char *modeName(Mode mode); static Scheme get_retx_mcs(const GprsCodingScheme mcs, const GprsCodingScheme retx_mcs, const unsigned arq_type); static enum Scheme egprs_mcs_retx_tbl[MAX_NUM_ARQ] [MAX_NUM_MCS][MAX_NUM_MCS]; private: GprsCodingScheme(int s); /* fail on use */ GprsCodingScheme& operator =(int s); /* fail on use */ 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) { case GPRS: return isGprs(); case EGPRS_GMSK: return isEgprsGmsk(); case EGPRS: return isEgprs(); } return false; } inline bool GprsCodingScheme::isCompatible(GprsCodingScheme o) const { return (isGprs() && o.isGprs()) || (isEgprs() && o.isEgprs()); } inline GprsCodingScheme::HeaderType GprsCodingScheme::headerTypeControl() const { return HEADER_GPRS_CONTROL; } inline GprsCodingScheme::GprsCodingScheme(Scheme s) : m_scheme(s) { if (!isValid()) m_scheme = UNKNOWN; } inline GprsCodingScheme& GprsCodingScheme::operator =(Scheme s) { m_scheme = s; if (!isValid()) m_scheme = UNKNOWN; return *this; } 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 GprsCodingScheme::Scheme(a) == GprsCodingScheme::Scheme(b); } inline bool GprsCodingScheme::operator == (Scheme scheme) const { return this->m_scheme == scheme; } inline bool operator !=(GprsCodingScheme a, GprsCodingScheme b) { return !(a == b); } inline bool operator <(GprsCodingScheme a, GprsCodingScheme b) { return a.isCompatible(b) && GprsCodingScheme::Scheme(a) < GprsCodingScheme::Scheme(b); } inline bool operator >(GprsCodingScheme a, GprsCodingScheme b) { return b < a; } inline bool operator <=(GprsCodingScheme a, GprsCodingScheme b) { return a == b || a < b; } inline bool operator >=(GprsCodingScheme a, GprsCodingScheme b) { return a == b || a > b; } inline GprsCodingScheme::Scheme GprsCodingScheme::get_retx_mcs( const GprsCodingScheme mcs, const GprsCodingScheme demanded_mcs, const unsigned arq_type) { return egprs_mcs_retx_tbl[arq_type][mcs.to_num() - 1] [demanded_mcs.to_num() - 1]; }