Get rid of class GprsCodingScheme

We have same kind of object splitted into two layers, in coding_scheme
and gprs_coding_scheme. Let's merge them together and get rid of the
class, which is not really useful because it's only a set of functions
operating on one enum value.

This change also fixes gcc 10.1.0 error about memseting a complex type
in rlc.h init().

Change-Id: Ie9ce2144ba9e8dbba9704d4e0000a2929e3e41df
changes/51/18351/4
Pau Espin 2 years ago committed by pespin
parent c10cb81593
commit 2ae8337669
  1. 2
      src/Makefile.am
  2. 2
      src/bts.h
  3. 243
      src/coding_scheme.c
  4. 45
      src/coding_scheme.h
  5. 22
      src/decoding.cpp
  6. 12
      src/decoding.h
  7. 6
      src/encoding.cpp
  8. 5
      src/encoding.h
  9. 14
      src/gprs_bssgp_pcu.cpp
  10. 231
      src/gprs_coding_scheme.cpp
  11. 163
      src/gprs_coding_scheme.h
  12. 79
      src/gprs_ms.cpp
  13. 20
      src/gprs_ms.h
  14. 2
      src/pcu_main.cpp
  15. 1
      src/pcu_vty_functions.cpp
  16. 16
      src/pdch.cpp
  17. 8
      src/pdch.h
  18. 63
      src/rlc.cpp
  19. 28
      src/rlc.h
  20. 15
      src/tbf.cpp
  21. 12
      src/tbf.h
  22. 37
      src/tbf_dl.cpp
  23. 2
      src/tbf_dl.h
  24. 5
      src/tbf_ul.cpp
  25. 162
      tests/edge/EdgeTest.cpp
  26. 32
      tests/tbf/TbfTest.cpp

@ -68,7 +68,6 @@ libgprs_la_SOURCES = \
osmobts_sock.cpp \
gprs_codel.c \
coding_scheme.c \
gprs_coding_scheme.cpp \
egprs_rlc_compression.cpp \
gprs_rlcmac_sched.cpp
@ -104,7 +103,6 @@ noinst_HEADERS = \
pcu_utils.h \
cxx_linuxlist.h \
gprs_codel.h \
gprs_coding_scheme.h \
coding_scheme.h \
egprs_rlc_compression.h \
wireshark_compat.h

@ -37,7 +37,7 @@ extern "C" {
#include "sba.h"
#include "tbf.h"
#include "gprs_ms_storage.h"
#include "gprs_coding_scheme.h"
#include "coding_scheme.h"
#include <cxx_linuxlist.h>
#endif

@ -42,6 +42,56 @@ const struct value_string mcs_names[] = {
{ 0, NULL }
};
enum Family {
FAMILY_INVALID,
FAMILY_A,
FAMILY_B,
FAMILY_C,
};
static struct {
struct {
uint8_t bytes;
uint8_t ext_bits;
uint8_t data_header_bits;
} uplink, downlink;
uint8_t data_bytes;
uint8_t optional_padding_bits;
enum HeaderType data_hdr;
enum Family family;
} mcs_info[NUM_SCHEMES] = {
{{0, 0}, {0, 0}, 0, 0,
HEADER_INVALID, FAMILY_INVALID},
{{23, 0}, {23, 0}, 20, 0,
HEADER_GPRS_DATA, FAMILY_INVALID},
{{33, 7}, {33, 7}, 30, 0,
HEADER_GPRS_DATA, FAMILY_INVALID},
{{39, 3}, {39, 3}, 36, 0,
HEADER_GPRS_DATA, FAMILY_INVALID},
{{53, 7}, {53, 7}, 50, 0,
HEADER_GPRS_DATA, FAMILY_INVALID},
{{26, 1}, {26, 1}, 22, 0,
HEADER_EGPRS_DATA_TYPE_3, FAMILY_C},
{{32, 1}, {32, 1}, 28, 0,
HEADER_EGPRS_DATA_TYPE_3, FAMILY_B},
{{41, 1}, {41, 1}, 37, 48,
HEADER_EGPRS_DATA_TYPE_3, FAMILY_A},
{{48, 1}, {48, 1}, 44, 0,
HEADER_EGPRS_DATA_TYPE_3, FAMILY_C},
{{60, 7}, {59, 6}, 56, 0,
HEADER_EGPRS_DATA_TYPE_2, FAMILY_B},
{{78, 7}, {77, 6}, 74, 48,
HEADER_EGPRS_DATA_TYPE_2, FAMILY_A},
{{118, 2}, {117, 4}, 56, 0,
HEADER_EGPRS_DATA_TYPE_1, FAMILY_B},
{{142, 2}, {141, 4}, 68, 0,
HEADER_EGPRS_DATA_TYPE_1, FAMILY_A},
{{154, 2}, {153, 4}, 74, 0,
HEADER_EGPRS_DATA_TYPE_1, FAMILY_A},
};
const char *mcs_name(enum CodingScheme val) {
return get_value_string(mcs_names, val);
}
@ -77,6 +127,194 @@ uint8_t mcs_chan_code(enum CodingScheme cs)
return 0;
}
enum CodingScheme mcs_get_by_size_ul(unsigned size)
{
switch (size) {
case 23: return CS1;
case 27: return MCS1;
case 33: return MCS2;
case 34: return CS2;
case 40: return CS3;
case 42: return MCS3;
case 49: return MCS4;
case 54: return CS4;
case 61: return MCS5;
case 79: return MCS6;
case 119: return MCS7;
case 143: return MCS8;
case 155: return MCS9;
default: return UNKNOWN;
}
}
enum CodingScheme mcs_get_gprs_by_num(unsigned num)
{
if (num < 1 || num > 4)
return UNKNOWN;
return CS1 + (num - 1);
}
enum CodingScheme mcs_get_egprs_by_num(unsigned num)
{
if (num < 1 || num > 9)
return UNKNOWN;
return MCS1 + (num - 1);
}
bool mcs_is_valid(enum CodingScheme cs)
{
return UNKNOWN <= cs && cs <= MCS9;
}
bool mcs_is_compat_kind(enum CodingScheme cs, enum mcs_kind mode)
{
switch (mode) {
case GPRS: return mcs_is_gprs(cs);
case EGPRS_GMSK: return mcs_is_edge_gmsk(cs);
case EGPRS: return mcs_is_edge(cs);
}
return false;
}
bool mcs_is_compat(enum CodingScheme cs, enum CodingScheme o)
{
return (mcs_is_gprs(cs) && mcs_is_gprs(o)) || (mcs_is_edge(cs) && mcs_is_edge(o));
}
uint8_t mcs_size_ul(enum CodingScheme cs)
{
return mcs_info[cs].uplink.bytes + (mcs_spare_bits_ul(cs) ? 1 : 0);
}
uint8_t mcs_size_dl(enum CodingScheme cs)
{
return mcs_info[cs].downlink.bytes + (mcs_spare_bits_dl(cs) ? 1 : 0);
}
uint8_t mcs_used_size_ul(enum CodingScheme cs)
{
if (mcs_info[cs].data_hdr == HEADER_GPRS_DATA)
return mcs_info[cs].uplink.bytes;
else
return mcs_size_ul(cs);
}
uint8_t mcs_used_size_dl(enum CodingScheme cs)
{
if (mcs_info[cs].data_hdr == HEADER_GPRS_DATA)
return mcs_info[cs].downlink.bytes;
else
return mcs_size_dl(cs);
}
uint8_t mcs_max_bytes_ul(enum CodingScheme cs)
{
return mcs_info[cs].uplink.bytes;
}
uint8_t mcs_max_bytes_dl(enum CodingScheme cs)
{
return mcs_info[cs].downlink.bytes;
}
uint8_t mcs_spare_bits_ul(enum CodingScheme cs)
{
return mcs_info[cs].uplink.ext_bits;
}
uint8_t mcs_spare_bits_dl(enum CodingScheme cs)
{
return mcs_info[cs].downlink.ext_bits;
}
uint8_t mcs_max_data_block_bytes(enum CodingScheme cs)
{
return mcs_info[cs].data_bytes;
}
uint8_t mcs_opt_padding_bits(enum CodingScheme cs)
{
return mcs_info[cs].optional_padding_bits;
}
void mcs_inc_kind(enum CodingScheme *cs, enum mcs_kind mode)
{
if (!mcs_is_compat_kind(*cs, mode))
/* This should not happen. TODO: Use assert? */
return;
enum CodingScheme new_cs = *cs + 1;
if (!mcs_is_compat_kind(new_cs, mode))
/* Clipping, do not change the value */
return;
*cs = new_cs;
}
void mcs_dec_kind(enum CodingScheme *cs, enum mcs_kind mode)
{
if (!mcs_is_compat_kind(*cs, mode))
/* This should not happen. TODO: Use assert? */
return;
enum CodingScheme new_cs = *cs - 1;
if (!mcs_is_compat_kind(new_cs, mode))
/* Clipping, do not change the value */
return;
*cs = new_cs;
}
void mcs_inc(enum CodingScheme *cs)
{
if (mcs_is_gprs(*cs) && *cs == CS4)
return;
if (mcs_is_edge(*cs) && *cs == MCS9)
return;
if (!mcs_is_valid(*cs))
return;
*cs = *cs + 1;
}
void mcs_dec(enum CodingScheme *cs)
{
if (mcs_is_gprs(*cs) && *cs == CS1)
return;
if (mcs_is_edge(*cs) && *cs == MCS1)
return;
if (!mcs_is_valid(*cs))
return;
*cs = *cs - 1;
}
bool mcs_is_family_compat(enum CodingScheme cs, enum CodingScheme o)
{
if (cs == o)
return true;
if (mcs_info[cs].family == FAMILY_INVALID)
return false;
return mcs_info[cs].family == mcs_info[o].family;
}
void mcs_dec_to_single_block(enum CodingScheme *cs, bool *need_stuffing)
{
switch (*cs) {
case MCS7: *need_stuffing = false; *cs = MCS5; break;
case MCS8: *need_stuffing = true; *cs = MCS6; break;
case MCS9: *need_stuffing = false; *cs = MCS6; break;
default: *need_stuffing = false; break;
}
}
static struct {
struct {
uint8_t data_header_bits;
@ -93,6 +331,11 @@ static struct {
{ { 3 * 8 + 7 }, { 3 * 8 + 7 }, 2, 1, "EGPRS_DATA_TYPE3" },
};
enum HeaderType mcs_header_type(enum CodingScheme mcs)
{
return mcs_info[mcs].data_hdr;
}
uint8_t num_data_blocks(enum HeaderType ht)
{
OSMO_ASSERT(ht < NUM_HEADER_TYPES);

@ -21,6 +21,8 @@
#include <osmocom/core/utils.h>
#include <stdbool.h>
enum CodingScheme {
UNKNOWN,
/* GPRS Coding Schemes: */
@ -30,6 +32,15 @@ enum CodingScheme {
NUM_SCHEMES
};
enum mcs_kind {
GPRS,
EGPRS_GMSK,
EGPRS,
};
#define EGPRS_ARQ1 0x0
#define EGPRS_ARQ2 0x1
extern const struct value_string mcs_names[];
const char *mcs_name(enum CodingScheme val);
enum CodingScheme get_retx_mcs(enum CodingScheme initial_mcs, enum CodingScheme commanded_mcs, bool resegment_bit);
@ -40,6 +51,32 @@ bool mcs_is_edge_gmsk(enum CodingScheme cs);
uint8_t mcs_chan_code(enum CodingScheme cs);
enum CodingScheme mcs_get_by_size_ul(unsigned size);
enum CodingScheme mcs_get_gprs_by_num(unsigned num);
enum CodingScheme mcs_get_egprs_by_num(unsigned num);
bool mcs_is_valid(enum CodingScheme cs);
bool mcs_is_compat(enum CodingScheme cs, enum CodingScheme o);
bool mcs_is_compat_kind(enum CodingScheme cs, enum mcs_kind mode);
uint8_t mcs_size_ul(enum CodingScheme cs);
uint8_t mcs_size_dl(enum CodingScheme cs);
uint8_t mcs_used_size_ul(enum CodingScheme cs);
uint8_t mcs_used_size_dl(enum CodingScheme cs);
uint8_t mcs_max_bytes_ul(enum CodingScheme cs);
uint8_t mcs_max_bytes_dl(enum CodingScheme cs);
uint8_t mcs_spare_bits_ul(enum CodingScheme cs);
uint8_t mcs_spare_bits_dl(enum CodingScheme cs);
uint8_t mcs_max_data_block_bytes(enum CodingScheme cs);
uint8_t mcs_opt_padding_bits(enum CodingScheme cs);
void mcs_inc_kind(enum CodingScheme *cs, enum mcs_kind mode);
void mcs_dec_kind(enum CodingScheme *cs, enum mcs_kind mode);
void mcs_inc(enum CodingScheme *cs);
void mcs_dec(enum CodingScheme *cs);
bool mcs_is_family_compat(enum CodingScheme cs, enum CodingScheme o);
void mcs_dec_to_single_block(enum CodingScheme *cs, bool *need_stuffing);
enum HeaderType {
HEADER_INVALID,
HEADER_GPRS_CONTROL,
@ -50,17 +87,11 @@ enum HeaderType {
NUM_HEADER_TYPES
};
enum HeaderType headerTypeData(enum CodingScheme mcs);
enum HeaderType mcs_header_type(enum CodingScheme mcs);
uint8_t num_data_blocks(enum HeaderType ht);
uint8_t num_data_header_bits_UL(enum HeaderType ht);
uint8_t num_data_header_bits_DL(enum HeaderType ht);
uint8_t num_data_block_header_bits(enum HeaderType ht);
enum mcs_kind {
GPRS,
EGPRS_GMSK,
EGPRS,
};
const char *mode_name(enum mcs_kind val);

@ -189,7 +189,7 @@ static int parse_extensions_gprs(const uint8_t *data, unsigned int data_len,
}
int Decoding::rlc_data_from_ul_data(
const struct gprs_rlc_data_block_info *rdbi, GprsCodingScheme cs,
const struct gprs_rlc_data_block_info *rdbi, enum CodingScheme cs,
const uint8_t *data, RlcData *chunks, unsigned int chunks_size,
uint32_t *tlli)
{
@ -351,10 +351,10 @@ void Decoding::extract_rbb(const struct bitvec *rbb, char *show_rbb)
}
int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
const uint8_t *data, GprsCodingScheme cs)
const uint8_t *data, enum CodingScheme cs)
{
unsigned int cur_bit = 0;
switch(cs.headerTypeData()) {
switch(mcs_header_type(cs)) {
case HEADER_GPRS_DATA :
cur_bit = rlc_parse_ul_data_header_gprs(rlc, data, cs);
break;
@ -380,7 +380,7 @@ int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
int Decoding::rlc_parse_ul_data_header_egprs_type_3(
struct gprs_rlc_data_info *rlc,
const uint8_t *data,
const GprsCodingScheme &cs)
const enum CodingScheme &cs)
{
int punct, punct2, with_padding, cps;
unsigned int e_ti_header, offs, cur_bit = 0;
@ -414,7 +414,7 @@ int Decoding::rlc_parse_ul_data_header_egprs_type_3(
rlc->block_info[0].ti = !!(e_ti_header & 0x02);
cur_bit += 2;
/* skip data area */
cur_bit += cs.maxDataBlockBytes() * 8;
cur_bit += mcs_max_data_block_bytes(cs) * 8;
return cur_bit;
}
@ -422,7 +422,7 @@ int Decoding::rlc_parse_ul_data_header_egprs_type_3(
int Decoding::rlc_parse_ul_data_header_egprs_type_2(
struct gprs_rlc_data_info *rlc,
const uint8_t *data,
const GprsCodingScheme &cs)
const enum CodingScheme &cs)
{
const struct gprs_rlc_ul_header_egprs_2 *egprs2;
unsigned int e_ti_header, offs, cur_bit = 0;
@ -458,14 +458,14 @@ int Decoding::rlc_parse_ul_data_header_egprs_type_2(
cur_bit += 2;
/* skip data area */
cur_bit += cs.maxDataBlockBytes() * 8;
cur_bit += mcs_max_data_block_bytes(cs) * 8;
return cur_bit;
}
int Decoding::rlc_parse_ul_data_header_egprs_type_1(
struct gprs_rlc_data_info *rlc,
const uint8_t *data, const GprsCodingScheme &cs)
const uint8_t *data, const enum CodingScheme &cs)
{
struct gprs_rlc_ul_header_egprs_1 *egprs1;
unsigned int e_ti_header, cur_bit = 0, offs;
@ -517,13 +517,13 @@ int Decoding::rlc_parse_ul_data_header_egprs_type_1(
rlc->block_info[1].ti = !!(e_ti_header & 0x02);
cur_bit += 2;
/* skip data area */
cur_bit += cs.maxDataBlockBytes() * 8;
cur_bit += mcs_max_data_block_bytes(cs) * 8;
return cur_bit;
}
int Decoding::rlc_parse_ul_data_header_gprs(struct gprs_rlc_data_info *rlc,
const uint8_t *data, const GprsCodingScheme &cs)
const uint8_t *data, const enum CodingScheme &cs)
{
const struct rlc_ul_header *gprs;
unsigned int cur_bit = 0;
@ -547,7 +547,7 @@ int Decoding::rlc_parse_ul_data_header_gprs(struct gprs_rlc_data_info *rlc,
rlc->block_info[0].spb = 0;
cur_bit += rlc->data_offs_bits[0];
/* skip data area */
cur_bit += cs.maxDataBlockBytes() * 8;
cur_bit += mcs_max_data_block_bytes(cs) * 8;
return cur_bit;
}

@ -40,7 +40,7 @@ public:
static int rlc_data_from_ul_data(
const struct gprs_rlc_data_block_info *rdbi,
GprsCodingScheme cs, const uint8_t *data, RlcData *chunks,
enum CodingScheme cs, const uint8_t *data, RlcData *chunks,
unsigned int chunks_size, uint32_t *tlli);
static uint8_t get_ms_class_by_capability(MS_Radio_Access_capability_t *cap);
static uint8_t get_egprs_ms_class_by_capability(MS_Radio_Access_capability_t *cap);
@ -50,21 +50,21 @@ public:
static int rlc_parse_ul_data_header_egprs_type_3(
struct gprs_rlc_data_info *rlc,
const uint8_t *data,
const GprsCodingScheme &cs);
const enum CodingScheme &cs);
static int rlc_parse_ul_data_header_egprs_type_2(
struct gprs_rlc_data_info *rlc,
const uint8_t *data,
const GprsCodingScheme &cs);
const enum CodingScheme &cs);
static int rlc_parse_ul_data_header_egprs_type_1(
struct gprs_rlc_data_info *rlc,
const uint8_t *data,
const GprsCodingScheme &cs);
const enum CodingScheme &cs);
static int rlc_parse_ul_data_header_gprs(
struct gprs_rlc_data_info *rlc,
const uint8_t *data,
const GprsCodingScheme &cs);
const enum CodingScheme &cs);
static int rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
const uint8_t *data, GprsCodingScheme cs);
const uint8_t *data, enum CodingScheme cs);
static unsigned int rlc_copy_to_aligned_buffer(
const struct gprs_rlc_data_info *rlc,
unsigned int data_block_idx,

@ -1107,11 +1107,11 @@ int Encoding::rlc_write_dl_data_header(const struct gprs_rlc_data_info *rlc,
struct gprs_rlc_dl_header_egprs_3 *egprs3;
struct rlc_dl_header *gprs;
unsigned int e_fbi_header;
GprsCodingScheme cs = rlc->cs;
enum CodingScheme cs = rlc->cs;
unsigned int offs;
unsigned int bsn_delta;
switch(cs.headerTypeData()) {
switch(mcs_header_type(cs)) {
case HEADER_GPRS_DATA:
gprs = static_cast<struct rlc_dl_header *>
((void *)data);
@ -1595,7 +1595,7 @@ static Encoding::AppendResult rlc_data_to_dl_append_egprs(
* \return the state of the rlc/mac like if there is more space for another chunk
*/
Encoding::AppendResult Encoding::rlc_data_to_dl_append(
struct gprs_rlc_data_block_info *rdbi, GprsCodingScheme cs,
struct gprs_rlc_data_block_info *rdbi, enum CodingScheme cs,
gprs_llc *llc, int *offset, int *num_chunks,
uint8_t *data_block, bool is_final, int *count_payload)
{

@ -21,9 +21,10 @@
#pragma once
#include <stdint.h>
#include <gprs_coding_scheme.h>
extern "C" {
#include <osmocom/gsm/l1sap.h>
#include "coding_scheme.h"
#include "gsm_rlcmac.h"
}
@ -99,7 +100,7 @@ public:
};
static AppendResult rlc_data_to_dl_append(
struct gprs_rlc_data_block_info *rdbi, GprsCodingScheme cs,
struct gprs_rlc_data_block_info *rdbi, enum CodingScheme cs,
gprs_llc *llc, int *offset, int *num_chunks,
uint8_t *data, bool is_final, int *count_payload);
};

@ -24,7 +24,7 @@
#include <gprs_debug.h>
#include <bts.h>
#include <tbf.h>
#include <gprs_coding_scheme.h>
#include <coding_scheme.h>
#include <pdch.h>
#include <decoding.h>
@ -639,9 +639,9 @@ static unsigned count_pdch(const struct gprs_rlcmac_bts *bts)
return num_pdch;
}
static uint32_t gprs_bssgp_max_leak_rate(GprsCodingScheme cs, int num_pdch)
static uint32_t gprs_bssgp_max_leak_rate(enum CodingScheme cs, int num_pdch)
{
int bytes_per_rlc_block = cs.maxDataBlockBytes() * num_data_blocks(cs.headerTypeData());
int bytes_per_rlc_block = mcs_max_data_block_bytes(cs) * num_data_blocks(mcs_header_type(cs));
/* n byte payload per 20ms */
return bytes_per_rlc_block * (1000 / 20) * num_pdch;
@ -717,7 +717,7 @@ static int get_and_reset_measured_leak_rate(int *usage_by_1000, unsigned num_pdc
return rate;
}
static GprsCodingScheme max_coding_scheme_dl(struct gprs_rlcmac_bts *bts)
static enum CodingScheme max_coding_scheme_dl(struct gprs_rlcmac_bts *bts)
{
int num;
@ -733,7 +733,7 @@ static GprsCodingScheme max_coding_scheme_dl(struct gprs_rlcmac_bts *bts)
num = 9;
}
return GprsCodingScheme::getEgprsByNum(num);
return mcs_get_egprs_by_num(num);
}
if (!bts->cs_adj_enabled) {
@ -753,7 +753,7 @@ static GprsCodingScheme max_coding_scheme_dl(struct gprs_rlcmac_bts *bts)
num = 4;
}
return GprsCodingScheme::getGprsByNum(num);
return mcs_get_gprs_by_num(num);
}
static int gprs_bssgp_tx_fc_bvc(void)
@ -765,7 +765,7 @@ static int gprs_bssgp_tx_fc_bvc(void)
uint32_t ms_leak_rate; /* oct/s */
uint32_t avg_delay_ms;
int num_pdch = -1;
GprsCodingScheme max_cs_dl;
enum CodingScheme max_cs_dl;
if (!the_pcu.bctx) {
LOGP(DBSSGP, LOGL_ERROR, "No bctx\n");

@ -1,231 +0,0 @@
/* gprs_coding_scheme.cpp
*
* Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
*
* 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.
*/
#include "gprs_coding_scheme.h"
enum Family {
FAMILY_INVALID,
FAMILY_A,
FAMILY_B,
FAMILY_C,
};
static struct {
struct {
uint8_t bytes;
uint8_t ext_bits;
uint8_t data_header_bits;
} uplink, downlink;
uint8_t data_bytes;
uint8_t optional_padding_bits;
enum HeaderType data_hdr;
enum Family family;
} mcs_info[NUM_SCHEMES] = {
{{0, 0}, {0, 0}, 0, 0,
HEADER_INVALID, FAMILY_INVALID},
{{23, 0}, {23, 0}, 20, 0,
HEADER_GPRS_DATA, FAMILY_INVALID},
{{33, 7}, {33, 7}, 30, 0,
HEADER_GPRS_DATA, FAMILY_INVALID},
{{39, 3}, {39, 3}, 36, 0,
HEADER_GPRS_DATA, FAMILY_INVALID},
{{53, 7}, {53, 7}, 50, 0,
HEADER_GPRS_DATA, FAMILY_INVALID},
{{26, 1}, {26, 1}, 22, 0,
HEADER_EGPRS_DATA_TYPE_3, FAMILY_C},
{{32, 1}, {32, 1}, 28, 0,
HEADER_EGPRS_DATA_TYPE_3, FAMILY_B},
{{41, 1}, {41, 1}, 37, 48,
HEADER_EGPRS_DATA_TYPE_3, FAMILY_A},
{{48, 1}, {48, 1}, 44, 0,
HEADER_EGPRS_DATA_TYPE_3, FAMILY_C},
{{60, 7}, {59, 6}, 56, 0,
HEADER_EGPRS_DATA_TYPE_2, FAMILY_B},
{{78, 7}, {77, 6}, 74, 48,
HEADER_EGPRS_DATA_TYPE_2, FAMILY_A},
{{118, 2}, {117, 4}, 56, 0,
HEADER_EGPRS_DATA_TYPE_1, FAMILY_B},
{{142, 2}, {141, 4}, 68, 0,
HEADER_EGPRS_DATA_TYPE_1, FAMILY_A},
{{154, 2}, {153, 4}, 74, 0,
HEADER_EGPRS_DATA_TYPE_1, FAMILY_A},
};
GprsCodingScheme GprsCodingScheme::getBySizeUL(unsigned size)
{
switch (size) {
case 23: return GprsCodingScheme(CS1);
case 27: return GprsCodingScheme(MCS1);
case 33: return GprsCodingScheme(MCS2);
case 34: return GprsCodingScheme(CS2);
case 40: return GprsCodingScheme(CS3);
case 42: return GprsCodingScheme(MCS3);
case 49: return GprsCodingScheme(MCS4);
case 54: return GprsCodingScheme(CS4);
case 61: return GprsCodingScheme(MCS5);
case 79: return GprsCodingScheme(MCS6);
case 119: return GprsCodingScheme(MCS7);
case 143: return GprsCodingScheme(MCS8);
case 155: return GprsCodingScheme(MCS9);
}
return GprsCodingScheme(UNKNOWN);
}
uint8_t GprsCodingScheme::sizeUL() const
{
return mcs_info[m_scheme].uplink.bytes + (spareBitsUL() ? 1 : 0);
}
uint8_t GprsCodingScheme::usedSizeUL() const
{
if (mcs_info[m_scheme].data_hdr == HEADER_GPRS_DATA)
return mcs_info[m_scheme].uplink.bytes;
else
return sizeUL();
}
uint8_t GprsCodingScheme::maxBytesUL() const
{
return mcs_info[m_scheme].uplink.bytes;
}
uint8_t GprsCodingScheme::spareBitsUL() const
{
return mcs_info[m_scheme].uplink.ext_bits;
}
uint8_t GprsCodingScheme::sizeDL() const
{
return mcs_info[m_scheme].downlink.bytes + (spareBitsDL() ? 1 : 0);
}
uint8_t GprsCodingScheme::usedSizeDL() const
{
if (mcs_info[m_scheme].data_hdr == HEADER_GPRS_DATA)
return mcs_info[m_scheme].downlink.bytes;
else
return sizeDL();
}
uint8_t GprsCodingScheme::maxBytesDL() const
{
return mcs_info[m_scheme].downlink.bytes;
}
uint8_t GprsCodingScheme::spareBitsDL() const
{
return mcs_info[m_scheme].downlink.ext_bits;
}
uint8_t GprsCodingScheme::maxDataBlockBytes() const
{
return mcs_info[m_scheme].data_bytes;
}
uint8_t GprsCodingScheme::optionalPaddingBits() const
{
return mcs_info[m_scheme].optional_padding_bits;
}
enum HeaderType GprsCodingScheme::headerTypeData() const
{
return mcs_info[m_scheme].data_hdr;
}
void GprsCodingScheme::inc(enum mcs_kind mode)
{
if (!isCompatible(mode))
/* This should not happen. TODO: Use assert? */
return;
CodingScheme new_cs(CodingScheme(m_scheme + 1));
if (!GprsCodingScheme(new_cs).isCompatible(mode))
/* Clipping, do not change the value */
return;
m_scheme = new_cs;
}
void GprsCodingScheme::dec(enum mcs_kind mode)
{
if (!isCompatible(mode))
/* This should not happen. TODO: Use assert? */
return;
CodingScheme new_cs(CodingScheme(m_scheme - 1));
if (!GprsCodingScheme(new_cs).isCompatible(mode))
/* Clipping, do not change the value */
return;
m_scheme = new_cs;
}
void GprsCodingScheme::inc()
{
if (mcs_is_gprs(m_scheme) && m_scheme == CS4)
return;
if (mcs_is_edge(m_scheme) && m_scheme == MCS9)
return;
if (!isValid())
return;
m_scheme = CodingScheme(m_scheme + 1);
}
void GprsCodingScheme::dec()
{
if (mcs_is_gprs(m_scheme) && m_scheme == CS1)
return;
if (mcs_is_edge(m_scheme) && m_scheme == MCS1)
return;
if (!isValid())
return;
m_scheme = CodingScheme(m_scheme - 1);
}
bool GprsCodingScheme::isFamilyCompatible(GprsCodingScheme o) const
{
if (*this == o)
return true;
if (mcs_info[m_scheme].family == FAMILY_INVALID)
return false;
return mcs_info[m_scheme].family == mcs_info[o.m_scheme].family;
}
void GprsCodingScheme::decToSingleBlock(bool *needStuffing)
{
switch (m_scheme) {
case MCS7: *needStuffing = false; m_scheme = MCS5; break;
case MCS8: *needStuffing = true; m_scheme = MCS6; break;
case MCS9: *needStuffing = false; m_scheme = MCS6; break;
default: *needStuffing = false; break;
}
}

@ -1,163 +0,0 @@
/* gprs_coding_scheme.h
*
* Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
* Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
*
* 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 <stdint.h>
#include <stddef.h>
extern "C" {
#include <osmocom/core/utils.h>
#include "coding_scheme.h"
}
class GprsCodingScheme {
public:
#define EGPRS_ARQ1 0x0
#define EGPRS_ARQ2 0x1
GprsCodingScheme(CodingScheme s = UNKNOWN);
operator bool() const {return m_scheme != UNKNOWN;}
operator CodingScheme() const {return m_scheme;}
uint8_t to_num() const;
GprsCodingScheme& operator =(CodingScheme s);
bool operator == (CodingScheme s) const;
GprsCodingScheme& operator =(GprsCodingScheme o);
bool isValid() const {return UNKNOWN <= m_scheme && m_scheme <= MCS9;}
bool isCompatible(enum mcs_kind mode) const;
bool isCompatible(GprsCodingScheme o) const;
bool isFamilyCompatible(GprsCodingScheme o) const;
void inc(enum mcs_kind mode);
void dec(enum mcs_kind mode);
void inc();
void dec();
void decToSingleBlock(bool *needStuffing);
uint8_t sizeUL() const;
uint8_t sizeDL() const;
uint8_t usedSizeUL() const;
uint8_t usedSizeDL() const;
uint8_t maxBytesUL() const;
uint8_t maxBytesDL() const;
uint8_t spareBitsUL() const;
uint8_t spareBitsDL() const;
uint8_t maxDataBlockBytes() const;
uint8_t optionalPaddingBits() const;
enum HeaderType headerTypeData() const;
static GprsCodingScheme getBySizeUL(unsigned size);
static GprsCodingScheme getGprsByNum(unsigned num);
static GprsCodingScheme getEgprsByNum(unsigned num);
private:
GprsCodingScheme(int s); /* fail on use */
GprsCodingScheme& operator =(int s); /* fail on use */
enum CodingScheme m_scheme;
};
// FIXME: remove once < comparison operator below is no longer necessary
inline uint8_t GprsCodingScheme::to_num() const
{
if (mcs_is_gprs(m_scheme))
return (m_scheme - CS1) + 1;
if (mcs_is_edge(m_scheme))
return (m_scheme - MCS1) + 1;
return 0;
}
inline bool GprsCodingScheme::isCompatible(enum mcs_kind mode) const
{
switch (mode) {
case GPRS: return mcs_is_gprs(m_scheme);
case EGPRS_GMSK: return mcs_is_edge_gmsk(m_scheme);
case EGPRS: return mcs_is_edge(m_scheme);
}
return false;
}
inline bool GprsCodingScheme::isCompatible(GprsCodingScheme o) const
{
return (mcs_is_gprs(m_scheme) && mcs_is_gprs(o)) || (mcs_is_edge(m_scheme) && mcs_is_edge(o));
}
inline GprsCodingScheme::GprsCodingScheme(CodingScheme s)
: m_scheme(s)
{
if (!isValid())
m_scheme = UNKNOWN;
}
inline GprsCodingScheme& GprsCodingScheme::operator =(CodingScheme 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(CodingScheme(CS1 + (num - 1)));
}
inline GprsCodingScheme GprsCodingScheme::getEgprsByNum(unsigned num)
{
if (num < 1 || num > 9)
return GprsCodingScheme();
return GprsCodingScheme(CodingScheme(MCS1 + (num - 1)));
}
/* The coding schemes form a partial ordering */
inline bool GprsCodingScheme::operator == (CodingScheme 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) && a.to_num() < b.to_num();
}

@ -20,7 +20,6 @@
#include "gprs_ms.h"
#include <gprs_coding_scheme.h>
#include "bts.h"
#include "tbf.h"
#include "tbf_ul.h"
@ -103,6 +102,8 @@ GprsMs::GprsMs(BTS *bts, uint32_t tlli) :
m_ta(GSM48_TA_INVALID),
m_ms_class(0),
m_egprs_ms_class(0),
m_current_cs_ul(UNKNOWN),
m_current_cs_dl(UNKNOWN),
m_is_idle(true),
m_ref(0),
m_list(this),
@ -226,15 +227,15 @@ void GprsMs::set_mode(enum mcs_kind mode)
switch (m_mode) {
case GPRS:
if (!mcs_is_gprs(m_current_cs_ul)) {
m_current_cs_ul = GprsCodingScheme::getGprsByNum(
m_current_cs_ul = mcs_get_gprs_by_num(
m_bts->bts_data()->initial_cs_ul);
if (!m_current_cs_ul.isValid())
if (!mcs_is_valid(m_current_cs_ul))
m_current_cs_ul = CS1;
}
if (!mcs_is_gprs(m_current_cs_dl)) {
m_current_cs_dl = GprsCodingScheme::getGprsByNum(
m_current_cs_dl = mcs_get_gprs_by_num(
m_bts->bts_data()->initial_cs_dl);
if (!m_current_cs_dl.isValid())
if (!mcs_is_valid(m_current_cs_dl))
m_current_cs_dl = CS1;
}
break;
@ -242,15 +243,15 @@ void GprsMs::set_mode(enum mcs_kind mode)
case EGPRS_GMSK:
case EGPRS:
if (!mcs_is_edge(m_current_cs_ul)) {
m_current_cs_ul = GprsCodingScheme::getEgprsByNum(
m_current_cs_ul = mcs_get_egprs_by_num(
m_bts->bts_data()->initial_mcs_ul);
if (!m_current_cs_ul.isValid())
if (!mcs_is_valid(m_current_cs_ul))
m_current_cs_ul = MCS1;
}
if (!mcs_is_edge(m_current_cs_dl)) {
m_current_cs_dl = GprsCodingScheme::getEgprsByNum(
m_current_cs_dl = mcs_get_egprs_by_num(
m_bts->bts_data()->initial_mcs_dl);
if (!m_current_cs_dl.isValid())
if (!mcs_is_valid(m_current_cs_dl))
m_current_cs_dl = MCS1;
}
break;
@ -510,7 +511,7 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
{
struct gprs_rlcmac_bts *bts_data;
int64_t now;
GprsCodingScheme max_cs_dl = this->max_cs_dl();
enum CodingScheme max_cs_dl = this->max_cs_dl();
OSMO_ASSERT(max_cs_dl);
bts_data = m_bts->bts_data();
@ -527,7 +528,7 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
if (error_rate > bts_data->cs_adj_upper_limit) {
if (mcs_chan_code(m_current_cs_dl) > 0) {
m_current_cs_dl.dec(mode());
mcs_dec_kind(&m_current_cs_dl, mode());
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): High error rate %d%%, "
"reducing CS level to %s\n",
@ -537,7 +538,7 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
} 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.inc(mode());
mcs_inc_kind(&m_current_cs_dl, mode());
LOGP(DRLCMACDL, LOGL_INFO,
"MS (IMSI %s): Low error rate %d%%, "
@ -560,7 +561,7 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
}
}
GprsCodingScheme GprsMs::max_cs_ul() const
enum CodingScheme GprsMs::max_cs_ul() const
{
struct gprs_rlcmac_bts *bts_data;
@ -568,29 +569,30 @@ GprsCodingScheme GprsMs::max_cs_ul() const
bts_data = m_bts->bts_data();
if (mcs_is_gprs(m_current_cs_ul)) {
if (!bts_data->max_cs_ul)
return GprsCodingScheme(CS4);
if (!bts_data->max_cs_ul) {
return CS4;
}
return GprsCodingScheme::getGprsByNum(bts_data->max_cs_ul);
return mcs_get_gprs_by_num(bts_data->max_cs_ul);
}
if (!mcs_is_edge(m_current_cs_ul))
return GprsCodingScheme(); /* UNKNOWN */
return UNKNOWN;
if (bts_data->max_mcs_ul)
return GprsCodingScheme::getEgprsByNum(bts_data->max_mcs_ul);
return mcs_get_egprs_by_num(bts_data->max_mcs_ul);
else if (bts_data->max_cs_ul)
return GprsCodingScheme::getEgprsByNum(bts_data->max_cs_ul);
return mcs_get_egprs_by_num(bts_data->max_cs_ul);
return GprsCodingScheme(MCS4);
return MCS4;
}
void GprsMs::set_current_cs_dl(CodingScheme scheme)
void GprsMs::set_current_cs_dl(enum CodingScheme scheme)
{
m_current_cs_dl = scheme;
}
GprsCodingScheme GprsMs::max_cs_dl() const
enum CodingScheme GprsMs::max_cs_dl() const
{
struct gprs_rlcmac_bts *bts_data;
@ -598,32 +600,33 @@ GprsCodingScheme GprsMs::max_cs_dl() const
bts_data = m_bts->bts_data();
if (mcs_is_gprs(m_current_cs_dl)) {
if (!bts_data->max_cs_dl)
return GprsCodingScheme(CS4);
if (!bts_data->max_cs_dl) {
return CS4;
}
return GprsCodingScheme::getGprsByNum(bts_data->max_cs_dl);
return mcs_get_gprs_by_num(bts_data->max_cs_dl);
}
if (!mcs_is_edge(m_current_cs_dl))
return GprsCodingScheme(); /* UNKNOWN */
return UNKNOWN;
if (bts_data->max_mcs_dl)
return GprsCodingScheme::getEgprsByNum(bts_data->max_mcs_dl);
return mcs_get_egprs_by_num(bts_data->max_mcs_dl);
else if (bts_data->max_cs_dl)
return GprsCodingScheme::getEgprsByNum(bts_data->max_cs_dl);
return mcs_get_egprs_by_num(bts_data->max_cs_dl);
return GprsCodingScheme(MCS4);
return 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();
enum CodingScheme max_cs_ul = this->max_cs_ul();
int old_link_qual;
int low;
int high;
GprsCodingScheme new_cs_ul = m_current_cs_ul;
enum CodingScheme new_cs_ul = m_current_cs_ul;
uint8_t current_cs = mcs_chan_code(m_current_cs_ul);
bts_data = m_bts->bts_data();
@ -674,10 +677,10 @@ void GprsMs::update_cs_ul(const pcu_l1_meas *meas)
old_link_qual = meas->link_qual;
if (meas->link_qual < low && old_link_qual < low)
new_cs_ul.dec(mode());
mcs_dec_kind(&new_cs_ul, mode());
else if (meas->link_qual > high && old_link_qual > high &&
m_current_cs_ul < max_cs_ul)
new_cs_ul.inc(mode());
mcs_inc_kind(&new_cs_ul, mode());
if (m_current_cs_ul != new_cs_ul) {
LOGP(DRLCMACMEAS, LOGL_INFO,
@ -724,9 +727,9 @@ void GprsMs::update_l1_meas(const pcu_l1_meas *meas)
}
}
GprsCodingScheme GprsMs::current_cs_dl() const
enum CodingScheme GprsMs::current_cs_dl() const
{
GprsCodingScheme cs = m_current_cs_dl;
enum CodingScheme cs = m_current_cs_dl;
size_t unencoded_octets;
if (!m_bts)
@ -747,11 +750,11 @@ GprsCodingScheme GprsMs::current_cs_dl() const
return cs;
/* The throughput would probably be better if the CS level was reduced */
cs.dec(mode());
mcs_dec_kind(&cs, mode());
/* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
if (cs == GprsCodingScheme(CS2))
cs.dec(mode());
if (cs == CS2)
mcs_dec_kind(&cs, mode());
return cs;
}

@ -22,17 +22,17 @@
struct gprs_codel;
#include <gprs_coding_scheme.h>
#include "cxx_linuxlist.h"
#include "llc.h"
#include "tbf.h"
#include "tbf_dl.h"
#include "pcu_l1_if.h"
#include <gprs_coding_scheme.h>
extern "C" {
#include <osmocom/core/timer.h>
#include <osmocom/core/linuxlist.h>
#include "coding_scheme.h"
}
#include <stdint.h>
@ -87,12 +87,12 @@ public:
uint8_t egprs_ms_class() const;
void set_ms_class(uint8_t ms_class);
void set_egprs_ms_class(uint8_t ms_class);
void set_current_cs_dl(CodingScheme scheme);
void set_current_cs_dl(enum CodingScheme scheme);
GprsCodingScheme current_cs_ul() const;
GprsCodingScheme current_cs_dl() const;
GprsCodingScheme max_cs_ul() const;
GprsCodingScheme max_cs_dl() const;
enum CodingScheme current_cs_ul() const;
enum CodingScheme current_cs_dl() const;
enum CodingScheme max_cs_ul() const;
enum CodingScheme max_cs_dl() const;
int first_common_ts() const;
uint8_t dl_slots() const;
@ -164,8 +164,8 @@ private:
uint8_t m_ms_class;
uint8_t m_egprs_ms_class;
/* current coding scheme */
GprsCodingScheme m_current_cs_ul;
GprsCodingScheme m_current_cs_dl;
enum CodingScheme m_current_cs_ul;
enum CodingScheme m_current_cs_dl;
gprs_llc_queue m_llc_queue;
@ -235,7 +235,7 @@ inline uint8_t GprsMs::egprs_ms_class() const
return m_egprs_ms_class;
}
inline GprsCodingScheme GprsMs::current_cs_ul() const
inline enum CodingScheme GprsMs::current_cs_ul() const
{
return m_current_cs_ul;
}