blob: bbac6e7a5b6078c1ada16d6108dfecd3ab11b8be [file] [log] [blame]
Jacob Erlbeck409f9802015-11-30 18:06:50 +01001/* gprs_coding_scheme.cpp
2 *
3 * Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
4 * Author: Jacob Erlbeck <jerlbeck@sysmocom.de>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21
22#include "gprs_coding_scheme.h"
23
Aravind Sirsikar91495522016-07-12 14:17:12 +053024/*
25 * 44.060 Table 8.1.1.1 and Table 8.1.1.2
26 * It has 3 level indexing. 0th level is ARQ type
27 * 1st level is Original MCS( index 0 corresponds to MCS1 and so on)
28 * 2nd level is MS MCS (index 0 corresponds to MCS1 and so on)
29 */
30enum GprsCodingScheme::Scheme GprsCodingScheme::egprs_mcs_retx_tbl[MAX_NUM_ARQ]
31 [MAX_NUM_MCS][MAX_NUM_MCS] = {
32 {
33 {MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1},
34 {MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2},
35 {MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3},
36 {MCS1, MCS1, MCS1, MCS4, MCS4, MCS4, MCS4, MCS4, MCS4},
37 {MCS2, MCS2, MCS2, MCS2, MCS5, MCS5, MCS7, MCS7, MCS7},
38 {MCS3, MCS3, MCS3, MCS3, MCS3, MCS6, MCS6, MCS6, MCS9},
39 {MCS2, MCS2, MCS2, MCS2, MCS5, MCS5, MCS7, MCS7, MCS7},
40 {MCS3, MCS3, MCS3, MCS3, MCS3, MCS6, MCS6, MCS8, MCS8},
41 {MCS3, MCS3, MCS3, MCS3, MCS3, MCS6, MCS6, MCS6, MCS9}
42 },
43 {
44 {MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1, MCS1},
45 {MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2, MCS2},
46 {MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3, MCS3},
47 {MCS4, MCS4, MCS4, MCS4, MCS4, MCS4, MCS4, MCS4, MCS4},
48 {MCS5, MCS5, MCS5, MCS5, MCS5, MCS5, MCS7, MCS7, MCS7},
49 {MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS9},
50 {MCS5, MCS5, MCS5, MCS5, MCS5, MCS5, MCS7, MCS7, MCS7},
51 {MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS8, MCS8},
52 {MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS6, MCS9}
53 }
54 };
55
Max807dde02019-02-26 19:59:46 +010056enum Family {
57 FAMILY_INVALID,
58 FAMILY_A,
59 FAMILY_B,
60 FAMILY_C,
61};
62
Jacob Erlbeck409f9802015-11-30 18:06:50 +010063static struct {
64 struct {
Maxb3a17d62017-12-21 12:11:33 +010065 uint8_t bytes;
66 uint8_t ext_bits;
67 uint8_t data_header_bits;
Jacob Erlbeck409f9802015-11-30 18:06:50 +010068 } uplink, downlink;
Maxb3a17d62017-12-21 12:11:33 +010069 uint8_t data_bytes;
70 uint8_t optional_padding_bits;
Jacob Erlbeck409f9802015-11-30 18:06:50 +010071 const char *name;
Jacob Erlbeck6c3dc612015-12-14 10:21:26 +010072 GprsCodingScheme::HeaderType data_hdr;
Max807dde02019-02-26 19:59:46 +010073 enum Family family;
Jacob Erlbeck409f9802015-11-30 18:06:50 +010074} mcs_info[GprsCodingScheme::NUM_SCHEMES] = {
Jacob Erlbeck215e18c2016-02-03 18:22:34 +010075 {{0, 0}, {0, 0}, 0, 0, "UNKNOWN",
Max807dde02019-02-26 19:59:46 +010076 GprsCodingScheme::HEADER_INVALID, FAMILY_INVALID},
Jacob Erlbeck215e18c2016-02-03 18:22:34 +010077 {{23, 0}, {23, 0}, 20, 0, "CS-1",
Max807dde02019-02-26 19:59:46 +010078 GprsCodingScheme::HEADER_GPRS_DATA, FAMILY_INVALID},
Jacob Erlbeck215e18c2016-02-03 18:22:34 +010079 {{33, 7}, {33, 7}, 30, 0, "CS-2",
Max807dde02019-02-26 19:59:46 +010080 GprsCodingScheme::HEADER_GPRS_DATA, FAMILY_INVALID},
Jacob Erlbeck215e18c2016-02-03 18:22:34 +010081 {{39, 3}, {39, 3}, 36, 0, "CS-3",
Max807dde02019-02-26 19:59:46 +010082 GprsCodingScheme::HEADER_GPRS_DATA, FAMILY_INVALID},
Jacob Erlbeck215e18c2016-02-03 18:22:34 +010083 {{53, 7}, {53, 7}, 50, 0, "CS-4",
Max807dde02019-02-26 19:59:46 +010084 GprsCodingScheme::HEADER_GPRS_DATA, FAMILY_INVALID},
Jacob Erlbeck409f9802015-11-30 18:06:50 +010085
Jacob Erlbeck215e18c2016-02-03 18:22:34 +010086 {{26, 1}, {26, 1}, 22, 0, "MCS-1",
Max807dde02019-02-26 19:59:46 +010087 GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3, FAMILY_C},
Jacob Erlbeck215e18c2016-02-03 18:22:34 +010088 {{32, 1}, {32, 1}, 28, 0, "MCS-2",
Max807dde02019-02-26 19:59:46 +010089 GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3, FAMILY_B},
Jacob Erlbeck215e18c2016-02-03 18:22:34 +010090 {{41, 1}, {41, 1}, 37, 48, "MCS-3",
Max807dde02019-02-26 19:59:46 +010091 GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3, FAMILY_A},
Jacob Erlbeck215e18c2016-02-03 18:22:34 +010092 {{48, 1}, {48, 1}, 44, 0, "MCS-4",
Max807dde02019-02-26 19:59:46 +010093 GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3, FAMILY_C},
Jacob Erlbeck409f9802015-11-30 18:06:50 +010094
Jacob Erlbeck215e18c2016-02-03 18:22:34 +010095 {{60, 7}, {59, 6}, 56, 0, "MCS-5",
Max807dde02019-02-26 19:59:46 +010096 GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2, FAMILY_B},
Jacob Erlbeck215e18c2016-02-03 18:22:34 +010097 {{78, 7}, {77, 6}, 74, 48, "MCS-6",
Max807dde02019-02-26 19:59:46 +010098 GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2, FAMILY_A},
Jacob Erlbeck215e18c2016-02-03 18:22:34 +010099 {{118, 2}, {117, 4}, 56, 0, "MCS-7",
Max807dde02019-02-26 19:59:46 +0100100 GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1, FAMILY_B},
Jacob Erlbeck215e18c2016-02-03 18:22:34 +0100101 {{142, 2}, {141, 4}, 68, 0, "MCS-8",
Max807dde02019-02-26 19:59:46 +0100102 GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1, FAMILY_A},
Jacob Erlbeck215e18c2016-02-03 18:22:34 +0100103 {{154, 2}, {153, 4}, 74, 0, "MCS-9",
Max807dde02019-02-26 19:59:46 +0100104 GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1, FAMILY_A},
Jacob Erlbeck409f9802015-11-30 18:06:50 +0100105};
106
Jacob Erlbeck22f80872016-01-11 10:56:50 +0100107static struct {
108 struct {
Maxb3a17d62017-12-21 12:11:33 +0100109 uint8_t data_header_bits;
Jacob Erlbeck22f80872016-01-11 10:56:50 +0100110 } uplink, downlink;
Maxb3a17d62017-12-21 12:11:33 +0100111 uint8_t data_block_header_bits;
112 uint8_t num_blocks;
Jacob Erlbeck22f80872016-01-11 10:56:50 +0100113 const char *name;
114} hdr_type_info[GprsCodingScheme::NUM_HEADER_TYPES] = {
115 {{0}, {0}, 0, 0, "INVALID"},
116 {{1*8 + 0}, {1*8 + 0}, 0, 0, "CONTROL"},
117 {{3*8 + 0}, {3*8 + 0}, 0, 1, "GPRS_DATA"},
118 {{5*8 + 6}, {5*8 + 0}, 2, 2, "EGPRS_DATA_TYPE1"},
119 {{4*8 + 5}, {3*8 + 4}, 2, 1, "EGPRS_DATA_TYPE2"},
120 {{3*8 + 7}, {3*8 + 7}, 2, 1, "EGPRS_DATA_TYPE3"},
121};
Jacob Erlbeck409f9802015-11-30 18:06:50 +0100122
123GprsCodingScheme GprsCodingScheme::getBySizeUL(unsigned size)
124{
125 switch (size) {
126 case 23: return GprsCodingScheme(CS1);
127 case 27: return GprsCodingScheme(MCS1);
128 case 33: return GprsCodingScheme(MCS2);
129 case 34: return GprsCodingScheme(CS2);
130 case 40: return GprsCodingScheme(CS3);
131 case 42: return GprsCodingScheme(MCS3);
132 case 49: return GprsCodingScheme(MCS4);
133 case 54: return GprsCodingScheme(CS4);
134 case 61: return GprsCodingScheme(MCS5);
135 case 79: return GprsCodingScheme(MCS6);
136 case 119: return GprsCodingScheme(MCS7);
137 case 143: return GprsCodingScheme(MCS8);
138 case 155: return GprsCodingScheme(MCS9);
139 }
140
141 return GprsCodingScheme(UNKNOWN);
142}
143
Maxb3a17d62017-12-21 12:11:33 +0100144uint8_t GprsCodingScheme::sizeUL() const
Jacob Erlbeck409f9802015-11-30 18:06:50 +0100145{
Jacob Erlbeckfc1b3e62016-01-11 09:58:11 +0100146 return mcs_info[m_scheme].uplink.bytes + (spareBitsUL() ? 1 : 0);
147}
148
Maxb3a17d62017-12-21 12:11:33 +0100149uint8_t GprsCodingScheme::usedSizeUL() const
Jacob Erlbeckfc1b3e62016-01-11 09:58:11 +0100150{
151 if (mcs_info[m_scheme].data_hdr == HEADER_GPRS_DATA)
152 return mcs_info[m_scheme].uplink.bytes;
153 else
154 return sizeUL();
Jacob Erlbeck409f9802015-11-30 18:06:50 +0100155}
156
Maxb3a17d62017-12-21 12:11:33 +0100157uint8_t GprsCodingScheme::maxBytesUL() const
Jacob Erlbeck409f9802015-11-30 18:06:50 +0100158{
159 return mcs_info[m_scheme].uplink.bytes;
160}
161
Maxb3a17d62017-12-21 12:11:33 +0100162uint8_t GprsCodingScheme::spareBitsUL() const
Jacob Erlbeck409f9802015-11-30 18:06:50 +0100163{
164 return mcs_info[m_scheme].uplink.ext_bits;
165}
166
Maxb3a17d62017-12-21 12:11:33 +0100167uint8_t GprsCodingScheme::sizeDL() const
Jacob Erlbeck409f9802015-11-30 18:06:50 +0100168{
Jacob Erlbeckfc1b3e62016-01-11 09:58:11 +0100169 return mcs_info[m_scheme].downlink.bytes + (spareBitsDL() ? 1 : 0);
170}
171
Maxb3a17d62017-12-21 12:11:33 +0100172uint8_t GprsCodingScheme::usedSizeDL() const
Jacob Erlbeckfc1b3e62016-01-11 09:58:11 +0100173{
174 if (mcs_info[m_scheme].data_hdr == HEADER_GPRS_DATA)
175 return mcs_info[m_scheme].downlink.bytes;
176 else
177 return sizeDL();
Jacob Erlbeck409f9802015-11-30 18:06:50 +0100178}
179
Maxb3a17d62017-12-21 12:11:33 +0100180uint8_t GprsCodingScheme::maxBytesDL() const
Jacob Erlbeck409f9802015-11-30 18:06:50 +0100181{
182 return mcs_info[m_scheme].downlink.bytes;
183}
184
Maxb3a17d62017-12-21 12:11:33 +0100185uint8_t GprsCodingScheme::spareBitsDL() const
Jacob Erlbeck409f9802015-11-30 18:06:50 +0100186{
187 return mcs_info[m_scheme].downlink.ext_bits;
188}
189
Maxb3a17d62017-12-21 12:11:33 +0100190uint8_t GprsCodingScheme::maxDataBlockBytes() const
Jacob Erlbeck392a5452015-12-14 10:38:29 +0100191{
192 return mcs_info[m_scheme].data_bytes;
193}
194
Maxb3a17d62017-12-21 12:11:33 +0100195uint8_t GprsCodingScheme::optionalPaddingBits() const
Jacob Erlbeck215e18c2016-02-03 18:22:34 +0100196{
197 return mcs_info[m_scheme].optional_padding_bits;
198}
199
Maxb3a17d62017-12-21 12:11:33 +0100200uint8_t GprsCodingScheme::numDataBlocks() const
Jacob Erlbeck392a5452015-12-14 10:38:29 +0100201{
Jacob Erlbeck22f80872016-01-11 10:56:50 +0100202 return hdr_type_info[headerTypeData()].num_blocks;
203}
204
Maxb3a17d62017-12-21 12:11:33 +0100205uint8_t GprsCodingScheme::numDataHeaderBitsUL() const
Jacob Erlbeck22f80872016-01-11 10:56:50 +0100206{
207 return hdr_type_info[headerTypeData()].uplink.data_header_bits;
208}
209
Maxb3a17d62017-12-21 12:11:33 +0100210uint8_t GprsCodingScheme::numDataHeaderBitsDL() const
Jacob Erlbeck22f80872016-01-11 10:56:50 +0100211{
212 return hdr_type_info[headerTypeData()].downlink.data_header_bits;
213}
214
Maxb3a17d62017-12-21 12:11:33 +0100215uint8_t GprsCodingScheme::numDataBlockHeaderBits() const
Jacob Erlbeck22f80872016-01-11 10:56:50 +0100216{
217 return hdr_type_info[headerTypeData()].data_block_header_bits;
Jacob Erlbeck392a5452015-12-14 10:38:29 +0100218}
219
Jacob Erlbeck409f9802015-11-30 18:06:50 +0100220const char *GprsCodingScheme::name() const
221{
222 return mcs_info[m_scheme].name;
223}
Jacob Erlbeck6c3dc612015-12-14 10:21:26 +0100224
225GprsCodingScheme::HeaderType GprsCodingScheme::headerTypeData() const
226{
227 return mcs_info[m_scheme].data_hdr;
228}
Jacob Erlbeck4c9e5492016-01-04 16:00:05 +0100229
230void GprsCodingScheme::inc(Mode mode)
231{
232 if (!isCompatible(mode))
233 /* This should not happen. TODO: Use assert? */
234 return;
235
236 Scheme new_cs(Scheme(m_scheme + 1));
237 if (!GprsCodingScheme(new_cs).isCompatible(mode))
238 /* Clipping, do not change the value */
239 return;
240
241 m_scheme = new_cs;
242}
243
244void GprsCodingScheme::dec(Mode mode)
245{
246 if (!isCompatible(mode))
247 /* This should not happen. TODO: Use assert? */
248 return;
249
250 Scheme new_cs(Scheme(m_scheme - 1));
251 if (!GprsCodingScheme(new_cs).isCompatible(mode))
252 /* Clipping, do not change the value */
253 return;
254
255 m_scheme = new_cs;
256}
257
258void GprsCodingScheme::inc()
259{
260 if (isGprs() && m_scheme == CS4)
261 return;
262
263 if (isEgprs() && m_scheme == MCS9)
264 return;
265
266 if (!isValid())
267 return;
268
269 m_scheme = Scheme(m_scheme + 1);
270}
271
272void GprsCodingScheme::dec()
273{
274 if (isGprs() && m_scheme == CS1)
275 return;
276
277 if (isEgprs() && m_scheme == MCS1)
278 return;
279
280 if (!isValid())
281 return;
282
283 m_scheme = Scheme(m_scheme - 1);
284}
Jacob Erlbeck7b579972016-01-05 15:54:24 +0100285
286const char *GprsCodingScheme::modeName(Mode mode)
287{
288 switch (mode) {
289 case GPRS: return "GPRS";
290 case EGPRS_GMSK: return "EGPRS_GMSK-only";
291 case EGPRS: return "EGPRS";
292 default: return "???";
293 }
294}
Jacob Erlbeck2305afd2016-02-03 15:25:04 +0100295
296bool GprsCodingScheme::isFamilyCompatible(GprsCodingScheme o) const
297{
298 if (*this == o)
299 return true;
300
Max807dde02019-02-26 19:59:46 +0100301 if (mcs_info[m_scheme].family == FAMILY_INVALID)
Jacob Erlbeck2305afd2016-02-03 15:25:04 +0100302 return false;
303
Max807dde02019-02-26 19:59:46 +0100304 return mcs_info[m_scheme].family == mcs_info[o.m_scheme].family;
Jacob Erlbeck2305afd2016-02-03 15:25:04 +0100305}
306
307bool GprsCodingScheme::isCombinable(GprsCodingScheme o) const
308{
309 return numDataBlocks() == o.numDataBlocks();
310}
311
312void GprsCodingScheme::decToSingleBlock(bool *needStuffing)
313{
314 switch (m_scheme) {
315 case MCS7: *needStuffing = false; m_scheme = MCS5; break;
316 case MCS8: *needStuffing = true; m_scheme = MCS6; break;
317 case MCS9: *needStuffing = false; m_scheme = MCS6; break;
318 default: *needStuffing = false; break;
319 }
320}