aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Chemeris <Alexander.Chemeris@gmail.com>2015-04-06 00:12:02 +0300
committerHarald Welte <laforge@gnumonks.org>2015-09-22 16:41:31 +0200
commit6fceaca584aa84214ccf747257344f1fe95caeee (patch)
tree8e139d2f300c759402ec2d99f0f41d697db7c7c8
parentddc0bf14d5d5c8b3248eab0463399ae0a5bb8e3f (diff)
trx: Implement BER calculations.
A known issue with this code is that BER is not updated for lost TCH frames, because osmo-trx doesn't send any indication for them and we don't have a callback to handle this. Otherwise the code seem to work fine.
-rw-r--r--src/osmo-bts-trx/gsm0503_coding.c234
-rw-r--r--src/osmo-bts-trx/gsm0503_coding.h37
-rw-r--r--src/osmo-bts-trx/l1_if.c33
-rw-r--r--src/osmo-bts-trx/l1_if.h6
-rw-r--r--src/osmo-bts-trx/scheduler.c78
5 files changed, 208 insertions, 180 deletions
diff --git a/src/osmo-bts-trx/gsm0503_coding.c b/src/osmo-bts-trx/gsm0503_coding.c
index c3ce9e57..e98301b4 100644
--- a/src/osmo-bts-trx/gsm0503_coding.c
+++ b/src/osmo-bts-trx/gsm0503_coding.c
@@ -1,9 +1,29 @@
+/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2015 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
+#include <osmocom/core/utils.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/conv.h>
#include <osmocom/core/crcgen.h>
@@ -16,12 +36,37 @@
#include "gsm0503_tables.h"
#include "gsm0503_coding.h"
-static int _xcch_decode_cB(uint8_t *l2_data, sbit_t *cB)
+int osmo_conv_decode_ber(const struct osmo_conv_code *code,
+ const sbit_t *input, ubit_t *output,
+ int *n_errors, int *n_bits_total)
+{
+ int res, i;
+ ubit_t recoded[1024]; /* TODO: We can do smaller, I guess */
+
+ res = osmo_conv_decode(code, input, output);
+
+ *n_bits_total = osmo_conv_encode(code, output, recoded);
+ OSMO_ASSERT(sizeof(recoded)/sizeof(recoded[0]) >= *n_bits_total);
+
+ /* Count bit errors */
+ *n_errors = 0;
+ for (i=0; i< *n_bits_total; i++) {
+ if (! ((recoded[i] && input[i]<0) ||
+ (!recoded[i] && input[i]>0)) )
+ *n_errors += 1;
+ }
+
+ return res;
+}
+
+
+static int _xcch_decode_cB(uint8_t *l2_data, sbit_t *cB,
+ int *n_errors, int *n_bits_total)
{
ubit_t conv[224];
int rv;
- osmo_conv_decode(&gsm0503_conv_xcch, cB, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_xcch, cB, conv, n_errors, n_bits_total);
rv = osmo_crc64gen_check_bits(&gsm0503_fire_crc40, conv, 184, conv+184);
if (rv)
@@ -50,7 +95,8 @@ static int _xcch_encode_cB(ubit_t *cB, uint8_t *l2_data)
* GSM xCCH block transcoding
*/
-int xcch_decode(uint8_t *l2_data, sbit_t *bursts)
+int xcch_decode(uint8_t *l2_data, sbit_t *bursts,
+ int *n_errors, int *n_bits_total)
{
sbit_t iB[456], cB[456];
int i;
@@ -61,7 +107,7 @@ int xcch_decode(uint8_t *l2_data, sbit_t *bursts)
gsm0503_xcch_deinterleave(cB, iB);
- return _xcch_decode_cB(l2_data, cB);
+ return _xcch_decode_cB(l2_data, cB, n_errors, n_bits_total);
}
int xcch_encode(ubit_t *bursts, uint8_t *l2_data)
@@ -85,7 +131,8 @@ int xcch_encode(ubit_t *bursts, uint8_t *l2_data)
* GSM PDTCH block transcoding
*/
-int pdtch_decode(uint8_t *l2_data, sbit_t *bursts, uint8_t *usf_p)
+int pdtch_decode(uint8_t *l2_data, sbit_t *bursts, uint8_t *usf_p,
+ int *n_errors, int *n_bits_total)
{
sbit_t iB[456], cB[676], hl_hn[8];
ubit_t conv[456];
@@ -109,7 +156,7 @@ int pdtch_decode(uint8_t *l2_data, sbit_t *bursts, uint8_t *usf_p)
switch (cs) {
case 1:
- osmo_conv_decode(&gsm0503_conv_xcch, cB, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_xcch, cB, conv, n_errors, n_bits_total);
rv = osmo_crc64gen_check_bits(&gsm0503_fire_crc40, conv, 184,
conv+184);
@@ -126,7 +173,7 @@ int pdtch_decode(uint8_t *l2_data, sbit_t *bursts, uint8_t *usf_p)
else
cB[i] = 0;
- osmo_conv_decode(&gsm0503_conv_cs2, cB, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_cs2, cB, conv, n_errors, n_bits_total);
for (i=0; i<8; i++) {
for (j=0, k=0; j<6; j++)
@@ -159,7 +206,7 @@ int pdtch_decode(uint8_t *l2_data, sbit_t *bursts, uint8_t *usf_p)
else
cB[i] = 0;
- osmo_conv_decode(&gsm0503_conv_cs3, cB, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_cs3, cB, conv, n_errors, n_bits_total);
for (i=0; i<8; i++) {
for (j=0, k=0; j<6; j++)
@@ -207,12 +254,22 @@ int pdtch_decode(uint8_t *l2_data, sbit_t *bursts, uint8_t *usf_p)
rv = osmo_crc16gen_check_bits(&gsm0503_cs234_crc16, conv+9, 431,
conv+9+431);
- if (rv)
+ if (rv) {
+ *n_bits_total = 456-12;
+ *n_errors = *n_bits_total;
return -1;
+ }
+
+ *n_bits_total = 456-12;
+ *n_errors = 0;
osmo_ubit2pbit_ext(l2_data, 0, conv, 9, 431, 1);
return 54;
+ default:
+ *n_bits_total = 0;
+ *n_errors = 0;
+ break;
}
return -1;
@@ -608,7 +665,8 @@ static void tch_amr_unmerge(ubit_t *d, ubit_t *p, ubit_t *u, int len, int prot)
memcpy(d+prot, u+prot+6, len-prot);
}
-int tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order, int efr)
+int tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order, int efr,
+ int *n_errors, int *n_bits_total)
{
sbit_t iB[912], cB[456], h;
ubit_t conv[185], s[244], w[260], b[65], d[260], p[8];
@@ -623,14 +681,14 @@ int tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order, int efr)
gsm0503_tch_fr_deinterleave(cB, iB);
if (steal > 0) {
- rv = _xcch_decode_cB(tch_data, cB);
+ rv = _xcch_decode_cB(tch_data, cB, n_errors, n_bits_total);
if (rv)
return -1;
return 23;
}
- osmo_conv_decode(&gsm0503_conv_tch_fr, cB, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_fr, cB, conv, n_errors, n_bits_total);
tch_fr_unreorder(d, p, conv);
@@ -723,7 +781,8 @@ coding_efr_fr:
return 0;
}
-int tch_hr_decode(uint8_t *tch_data, sbit_t *bursts, int odd)
+int tch_hr_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
+ int *n_errors, int *n_bits_total)
{
sbit_t iB[912], cB[456], h;
ubit_t conv[98], b[112], d[112], p[3];
@@ -752,7 +811,7 @@ int tch_hr_decode(uint8_t *tch_data, sbit_t *bursts, int odd)
gsm0503_tch_fr_deinterleave(cB, iB);
- rv = _xcch_decode_cB(tch_data, cB);
+ rv = _xcch_decode_cB(tch_data, cB, n_errors, n_bits_total);
if (rv)
return -1;
@@ -765,7 +824,7 @@ int tch_hr_decode(uint8_t *tch_data, sbit_t *bursts, int odd)
gsm0503_tch_hr_deinterleave(cB, iB);
- osmo_conv_decode(&gsm0503_conv_tch_hr, cB, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_hr, cB, conv, n_errors, n_bits_total);
tch_hr_unreorder(d, p, conv);
@@ -834,29 +893,14 @@ int tch_hr_encode(ubit_t *bursts, uint8_t *tch_data, int len)
return 0;
}
-static float amr_calc_ber(sbit_t *orig, ubit_t *test, int len)
-{
- int i, err = 0;
-
- /* count number of wrong bits (sbits with 0-value are omitted) */
- for (i=0; i<len; i++) {
- if ((*orig) > 0 && (*test))
- err++;
- else if ((*orig) < 0 && !(*test))
- err++;
- orig++;
- test++;
- }
-
- return (float)err / (float)len;
-}
-
int tch_afs_decode(uint8_t *tch_data, sbit_t *bursts, int codec_mode_req,
- uint8_t *codec, int codecs, uint8_t *ft, uint8_t *cmr, float *ber)
+ uint8_t *codec, int codecs, uint8_t *ft, uint8_t *cmr,
+ int *n_errors, int *n_bits_total)
{
sbit_t iB[912], cB[456], h;
ubit_t test[456], d[244], p[6], conv[250];
int i, j, k, best = 0, rv, len, steal = 0, id = 0;
+ *n_errors = 0; *n_bits_total = 0;
for (i=0; i<8; i++) {
gsm0503_tch_burst_unmap(&iB[i * 114], &bursts[i * 116], &h,
@@ -867,7 +911,7 @@ int tch_afs_decode(uint8_t *tch_data, sbit_t *bursts, int codec_mode_req,
gsm0503_tch_fr_deinterleave(cB, iB);
if (steal > 0) {
- rv = _xcch_decode_cB(tch_data, cB);
+ rv = _xcch_decode_cB(tch_data, cB, n_errors, n_bits_total);
if (rv)
return -1;
@@ -892,7 +936,7 @@ int tch_afs_decode(uint8_t *tch_data, sbit_t *bursts, int codec_mode_req,
switch ((codec_mode_req) ? codec[*ft] : codec[id]) {
case 7: /* TCH/AFS12.2 */
- osmo_conv_decode(&gsm0503_conv_tch_afs_12_2, cB+8, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_afs_12_2, cB+8, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 244, 81);
@@ -904,15 +948,9 @@ int tch_afs_decode(uint8_t *tch_data, sbit_t *bursts, int codec_mode_req,
len = 31;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_afs_12_2, conv,
- test+8);
- *ber = amr_calc_ber(cB+8, test+8, 448);
- }
-
break;
case 6: /* TCH/AFS10.2 */
- osmo_conv_decode(&gsm0503_conv_tch_afs_10_2, cB+8, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_afs_10_2, cB+8, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 204, 65);
@@ -924,15 +962,9 @@ int tch_afs_decode(uint8_t *tch_data, sbit_t *bursts, int codec_mode_req,
len = 26;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_afs_10_2, conv,
- test+8);
- *ber = amr_calc_ber(cB+8, test+8, 448);
- }
-
break;
case 5: /* TCH/AFS7.95 */
- osmo_conv_decode(&gsm0503_conv_tch_afs_7_95, cB+8, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_afs_7_95, cB+8, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 159, 75);
@@ -944,15 +976,9 @@ int tch_afs_decode(uint8_t *tch_data, sbit_t *bursts, int codec_mode_req,
len = 20;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_afs_7_95, conv,
- test+8);
- *ber = amr_calc_ber(cB+8, test+8, 448);
- }
-
break;
case 4: /* TCH/AFS7.4 */
- osmo_conv_decode(&gsm0503_conv_tch_afs_7_4, cB+8, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_afs_7_4, cB+8, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 148, 61);
@@ -964,15 +990,9 @@ int tch_afs_decode(uint8_t *tch_data, sbit_t *bursts, int codec_mode_req,
len = 19;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_afs_7_4, conv,
- test+8);
- *ber = amr_calc_ber(cB+8, test+8, 448);
- }
-
break;
case 3: /* TCH/AFS6.7 */
- osmo_conv_decode(&gsm0503_conv_tch_afs_6_7, cB+8, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_afs_6_7, cB+8, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 134, 55);
@@ -984,15 +1004,9 @@ int tch_afs_decode(uint8_t *tch_data, sbit_t *bursts, int codec_mode_req,
len = 17;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_afs_6_7, conv,
- test+8);
- *ber = amr_calc_ber(cB+8, test+8, 448);
- }
-
break;
case 2: /* TCH/AFS5.9 */
- osmo_conv_decode(&gsm0503_conv_tch_afs_5_9, cB+8, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_afs_5_9, cB+8, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 118, 55);
@@ -1004,15 +1018,9 @@ int tch_afs_decode(uint8_t *tch_data, sbit_t *bursts, int codec_mode_req,
len = 15;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_afs_5_9, conv,
- test+8);
- *ber = amr_calc_ber(cB+8, test+8, 448);
- }
-
break;
case 1: /* TCH/AFS5.15 */
- osmo_conv_decode(&gsm0503_conv_tch_afs_5_15, cB+8, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_afs_5_15, cB+8, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 103, 49);
@@ -1024,15 +1032,9 @@ int tch_afs_decode(uint8_t *tch_data, sbit_t *bursts, int codec_mode_req,
len = 13;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_afs_5_15, conv,
- test+8);
- *ber = amr_calc_ber(cB+8, test+8, 448);
- }
-
break;
case 0: /* TCH/AFS4.75 */
- osmo_conv_decode(&gsm0503_conv_tch_afs_4_75, cB+8, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_afs_4_75, cB+8, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 95, 39);
@@ -1044,16 +1046,11 @@ int tch_afs_decode(uint8_t *tch_data, sbit_t *bursts, int codec_mode_req,
len = 12;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_afs_4_75, conv,
- test+8);
- *ber = amr_calc_ber(cB+8, test+8, 448);
- }
-
break;
default:
fprintf(stderr, "FIXME: FT %d not supported!\n", *ft);
-
+ *n_bits_total = 448;
+ *n_errors = *n_bits_total;
return -1;
}
@@ -1229,7 +1226,7 @@ facch:
int tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
int codec_mode_req, uint8_t *codec, int codecs, uint8_t *ft,
- uint8_t *cmr, float *ber)
+ uint8_t *cmr, int *n_errors, int *n_bits_total)
{
sbit_t iB[912], cB[456], h;
ubit_t test[456], d[244], p[6], conv[135];
@@ -1258,7 +1255,7 @@ int tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
gsm0503_tch_fr_deinterleave(cB, iB);
- rv = _xcch_decode_cB(tch_data, cB);
+ rv = _xcch_decode_cB(tch_data, cB, n_errors, n_bits_total);
if (rv)
return -1;
@@ -1289,7 +1286,7 @@ int tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
switch ((codec_mode_req) ? codec[*ft] : codec[id]) {
case 5: /* TCH/AHS7.95 */
- osmo_conv_decode(&gsm0503_conv_tch_ahs_7_95, cB+4, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_ahs_7_95, cB+4, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 123, 67);
@@ -1304,15 +1301,9 @@ int tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
len = 20;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_ahs_7_95, conv,
- test+4);
- *ber = amr_calc_ber(cB+4, test+4, 188);
- }
-
break;
case 4: /* TCH/AHS7.4 */
- osmo_conv_decode(&gsm0503_conv_tch_ahs_7_4, cB+4, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_ahs_7_4, cB+4, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 120, 61);
@@ -1327,15 +1318,9 @@ int tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
len = 19;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_ahs_7_4, conv,
- test+4);
- *ber = amr_calc_ber(cB+4, test+4, 196);
- }
-
break;
case 3: /* TCH/AHS6.7 */
- osmo_conv_decode(&gsm0503_conv_tch_ahs_6_7, cB+4, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_ahs_6_7, cB+4, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 110, 55);
@@ -1350,15 +1335,9 @@ int tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
len = 17;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_ahs_6_7, conv,
- test+4);
- *ber = amr_calc_ber(cB+4, test+4, 200);
- }
-
break;
case 2: /* TCH/AHS5.9 */
- osmo_conv_decode(&gsm0503_conv_tch_ahs_5_9, cB+4, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_ahs_5_9, cB+4, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 102, 55);
@@ -1373,15 +1352,9 @@ int tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
len = 15;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_ahs_5_9, conv,
- test+4);
- *ber = amr_calc_ber(cB+4, test+4, 208);
- }
-
break;
case 1: /* TCH/AHS5.15 */
- osmo_conv_decode(&gsm0503_conv_tch_ahs_5_15, cB+4, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_ahs_5_15, cB+4, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 91, 49);
@@ -1396,15 +1369,9 @@ int tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
len = 13;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_ahs_5_15, conv,
- test+4);
- *ber = amr_calc_ber(cB+4, test+4, 212);
- }
-
break;
case 0: /* TCH/AHS4.75 */
- osmo_conv_decode(&gsm0503_conv_tch_ahs_4_75, cB+4, conv);
+ osmo_conv_decode_ber(&gsm0503_conv_tch_ahs_4_75, cB+4, conv, n_errors, n_bits_total);
tch_amr_unmerge(d, p, conv, 83, 39);
@@ -1419,16 +1386,11 @@ int tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
len = 12;
- if (ber) {
- osmo_conv_encode(&gsm0503_conv_tch_ahs_4_75, conv,
- test+4);
- *ber = amr_calc_ber(cB+4, test+4, 212);
- }
-
break;
default:
fprintf(stderr, "FIXME: FT %d not supported!\n", *ft);
-
+ *n_bits_total = 159;
+ *n_errors = *n_bits_total;
return -1;
}
diff --git a/src/osmo-bts-trx/gsm0503_coding.h b/src/osmo-bts-trx/gsm0503_coding.h
index 33b58d3b..a454d8f4 100644
--- a/src/osmo-bts-trx/gsm0503_coding.h
+++ b/src/osmo-bts-trx/gsm0503_coding.h
@@ -1,22 +1,47 @@
+/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2015 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
#ifndef _0503_CODING_H
#define _0503_CODING_H
-int xcch_decode(uint8_t *l2_data, sbit_t *bursts);
+int xcch_decode(uint8_t *l2_data, sbit_t *bursts,
+ int *n_errors, int *n_bits_total);
int xcch_encode(ubit_t *bursts, uint8_t *l2_data);
-int pdtch_decode(uint8_t *l2_data, sbit_t *bursts, uint8_t *usf_p);
+int pdtch_decode(uint8_t *l2_data, sbit_t *bursts, uint8_t *usf_p,
+ int *n_errors, int *n_bits_total);
int pdtch_encode(ubit_t *bursts, uint8_t *l2_data, uint8_t l2_len);
-int tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order, int efr);
+int tch_fr_decode(uint8_t *tch_data, sbit_t *bursts, int net_order,
+ int efr, int *n_errors, int *n_bits_total);
int tch_fr_encode(ubit_t *bursts, uint8_t *tch_data, int len, int net_order);
-int tch_hr_decode(uint8_t *tch_data, sbit_t *bursts, int odd);
+int tch_hr_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
+ int *n_errors, int *n_bits_total);
int tch_hr_encode(ubit_t *bursts, uint8_t *tch_data, int len);
int tch_afs_decode(uint8_t *tch_data, sbit_t *bursts, int codec_mode_req,
- uint8_t *codec, int codecs, uint8_t *ft, uint8_t *cmr, float *ber);
+ uint8_t *codec, int codecs, uint8_t *ft, uint8_t *cmr,
+ int *n_errors, int *n_bits_total);
int tch_afs_encode(ubit_t *bursts, uint8_t *tch_data, int len,
int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft,
uint8_t cmr);
int tch_ahs_decode(uint8_t *tch_data, sbit_t *bursts, int odd,
int codec_mode_req, uint8_t *codec, int codecs, uint8_t *ft,
- uint8_t *cmr, float *ber);
+ uint8_t *cmr, int *n_errors, int *n_bits_total);
int tch_ahs_encode(ubit_t *bursts, uint8_t *tch_data, int len,
int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft,
uint8_t cmr);
diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c
index 3f2a565a..6f8cd845 100644
--- a/src/osmo-bts-trx/l1_if.c
+++ b/src/osmo-bts-trx/l1_if.c
@@ -2,6 +2,7 @@
* layer 1 primitive handling and interface
*
* Copyright (C) 2013 Andreas Eversberg <jolly@eversberg.eu>
+ * Copyright (C) 2015 Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
*
* All Rights Reserved
*
@@ -454,19 +455,33 @@ int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn)
return l1sap_up(bts->c0, &l1sap);
}
-int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr, float qta,
+
+void l1if_fill_meas_res(struct osmo_phsap_prim *l1sap, uint8_t chan_nr, float ta,
float ber, float rssi)
{
+ memset(l1sap, 0, sizeof(*l1sap));
+ osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_MPH_INFO,
+ PRIM_OP_INDICATION, NULL);
+ l1sap->u.info.type = PRIM_INFO_MEAS;
+ l1sap->u.info.u.meas_ind.chan_nr = chan_nr;
+ l1sap->u.info.u.meas_ind.ta_offs_qbits = (int16_t)(ta*4);
+ l1sap->u.info.u.meas_ind.ber10k = (unsigned int) (ber * 10000);
+ l1sap->u.info.u.meas_ind.inv_rssi = (uint8_t) (rssi * -1);
+}
+
+int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint8_t chan_nr,
+ int n_errors, int n_bits_total, float rssi, float toa)
+{
+ struct gsm_lchan *lchan = &trx->ts[tn].lchan[l1sap_chan2ss(chan_nr)];
struct osmo_phsap_prim l1sap;
+ float ber = (float)n_errors / (float)n_bits_total;
- memset(&l1sap, 0, sizeof(l1sap));
- osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO,
- PRIM_OP_INDICATION, NULL);
- l1sap.u.info.type = PRIM_INFO_MEAS;
- l1sap.u.info.u.meas_ind.chan_nr = chan_nr;
- l1sap.u.info.u.meas_ind.ta_offs_qbits = qta;
- l1sap.u.info.u.meas_ind.ber10k = (unsigned int) (ber * 100);
- l1sap.u.info.u.meas_ind.inv_rssi = (uint8_t) (rssi * -1);
+ LOGP(DMEAS, LOGL_DEBUG, "RX L1 frame %s fn=%u chan_nr=0x%02x MS pwr=%ddBm rssi=%.1f dBFS "
+ "ber=%.2f%% (%d/%d bits) L1_ta=%d rqd_ta=%d toa=%.2f\n",
+ gsm_lchan_name(lchan), fn, chan_nr, ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power),
+ rssi, ber*100, n_errors, n_bits_total, lchan->meas.l1_info[1], lchan->rqd_ta, toa);
+
+ l1if_fill_meas_res(&l1sap, chan_nr, lchan->rqd_ta + toa, ber, rssi);
return l1sap_up(trx, &l1sap);
}
diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h
index 5110cde1..278537e1 100644
--- a/src/osmo-bts-trx/l1_if.h
+++ b/src/osmo-bts-trx/l1_if.h
@@ -171,7 +171,9 @@ int check_transceiver_availability(struct gsm_bts *bts, int avail);
int l1if_provision_transceiver_trx(struct trx_l1h *l1h);
int l1if_provision_transceiver(struct gsm_bts *bts);
int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn);
-int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr, float qta,
- float ber, float rssi);
+void l1if_fill_meas_res(struct osmo_phsap_prim *l1sap, uint8_t chan_nr, float ta,
+ float ber, float rssi);
+int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint8_t chan_nr,
+ int n_errors, int n_bits_total, float rssi, float toa);
#endif /* L1_IF_H_TRX */
diff --git a/src/osmo-bts-trx/scheduler.c b/src/osmo-bts-trx/scheduler.c
index f4b0d9cc..23bfebc0 100644
--- a/src/osmo-bts-trx/scheduler.c
+++ b/src/osmo-bts-trx/scheduler.c
@@ -1,6 +1,7 @@
/* Scheduler for OsmoBTS-TRX */
/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2015 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
*
* All Rights Reserved
*
@@ -563,8 +564,7 @@ found_msg:
}
static int compose_ph_data_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
- enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float toa,
- float ber, float rssi)
+ enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi)
{
struct msgb *msg;
struct osmo_phsap_prim *l1sap;
@@ -589,12 +589,6 @@ static int compose_ph_data_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
/* forward primitive */
l1sap_up(l1h->trx, l1sap);
- /* process measurement */
- if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id))
- l1if_process_meas_res(l1h->trx, chan_nr,
- (l1h->trx->ts[tn].lchan[l1sap_chan2ss(chan_nr)].rqd_ta + toa) * 4,
- ber, rssi);
-
return 0;
}
@@ -668,9 +662,16 @@ got_msg:
/* handle loss detection of sacch */
if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) {
/* count and send BFI */
- if (++(l1h->chan_states[tn][chan].lost) > 1)
- compose_ph_data_ind(l1h, tn, 0, chan, NULL, 0, 0, 0,
- -110);
+ if (++(l1h->chan_states[tn][chan].lost) > 1) {
+ /* TODO: Should we pass old TOA here? Otherwise we risk
+ * unnecessary decreasing TA */
+
+ /* Send uplnk measurement information to L2 */
+ l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn,
+ 456, 456, -110, 0);
+
+ compose_ph_data_ind(l1h, tn, 0, chan, NULL, 0, -110);
+ }
}
/* alloc burst memory, if not already */
@@ -1225,6 +1226,7 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
float *toa_sum = &chan_state->toa_sum;
uint8_t *toa_num = &chan_state->toa_num;
uint8_t l2[23], l2_len;
+ int n_errors, n_bits_total;
int rc;
/* handle rach, if handover rach detection is turned on */
@@ -1290,7 +1292,7 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
*mask = 0x0;
/* decode */
- rc = xcch_decode(l2, *bursts_p);
+ rc = xcch_decode(l2, *bursts_p, &n_errors, &n_bits_total);
if (rc) {
LOGP(DL1C, LOGL_NOTICE, "Received bad data frame at fn=%u "
"(%u/%u) for %s\n", *first_fn,
@@ -1300,8 +1302,11 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
} else
l2_len = 23;
- return compose_ph_data_ind(l1h, tn, *first_fn, chan, l2, l2_len,
- *toa_sum / *toa_num, 0, *rssi_sum / *rssi_num);
+ /* Send uplnk measurement information to L2 */
+ l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn,
+ n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa_sum / *toa_num);
+
+ return compose_ph_data_ind(l1h, tn, *first_fn, chan, l2, l2_len, *rssi_sum / *rssi_num);
}
static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
@@ -1316,6 +1321,7 @@ static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
float *toa_sum = &chan_state->toa_sum;
uint8_t *toa_num = &chan_state->toa_num;
uint8_t l2[54+1];
+ int n_errors, n_bits_total;
int rc;
LOGP(DL1C, LOGL_DEBUG, "PDTCH received %s fn=%u ts=%u trx=%u bid=%u\n",
@@ -1364,7 +1370,12 @@ static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
*mask = 0x0;
/* decode */
- rc = pdtch_decode(l2 + 1, *bursts_p, NULL);
+ rc = pdtch_decode(l2 + 1, *bursts_p, NULL, &n_errors, &n_bits_total);
+
+ /* Send uplnk measurement information to L2 */
+ l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn,
+ n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa_sum / *toa_num);
+
if (rc <= 0) {
LOGP(DL1C, LOGL_NOTICE, "Received bad PDTCH block ending at "
"fn=%u (%u/%u) for %s\n", fn, fn % l1h->mf_period[tn],
@@ -1375,7 +1386,7 @@ static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
l2[0] = 7; /* valid frame */
return compose_ph_data_ind(l1h, tn, (fn + 2715648 - 3) % 2715648, chan,
- l2, rc + 1, *toa_sum / *toa_num, 0, *rssi_sum / *rssi_num);
+ l2, rc + 1, *rssi_sum / *rssi_num);
}
static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
@@ -1389,7 +1400,7 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
uint8_t tch_mode = chan_state->tch_mode;
uint8_t tch_data[128]; /* just to be safe */
int rc, amr = 0;
- float ber;
+ int n_errors, n_bits_total;
/* handle rach, if handover rach detection is turned on */
if (chan_state->ho_rach_detect == 1)
@@ -1437,10 +1448,10 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1
: tch_mode) {
case GSM48_CMODE_SPEECH_V1: /* FR */
- rc = tch_fr_decode(tch_data, *bursts_p, 1, 0);
+ rc = tch_fr_decode(tch_data, *bursts_p, 1, 0, &n_errors, &n_bits_total);
break;
case GSM48_CMODE_SPEECH_EFR: /* EFR */
- rc = tch_fr_decode(tch_data, *bursts_p, 1, 1);
+ rc = tch_fr_decode(tch_data, *bursts_p, 1, 1, &n_errors, &n_bits_total);
break;
case GSM48_CMODE_SPEECH_AMR: /* AMR */
/* the first FN 0,8,17 defines that CMI is included in frame,
@@ -1450,11 +1461,11 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
rc = tch_afs_decode(tch_data + 2, *bursts_p,
(((fn + 26 - 7) % 26) >> 2) & 1, chan_state->codec,
chan_state->codecs, &chan_state->ul_ft,
- &chan_state->ul_cmr, &ber);
+ &chan_state->ul_cmr, &n_errors, &n_bits_total);
if (rc)
trx_loop_amr_input(l1h,
trx_chan_desc[chan].chan_nr | tn, chan_state,
- ber);
+ (float)n_errors/(float)n_bits_total);
amr = 2; /* we store tch_data + 2 header bytes */
/* only good speech frames get rtp header */
if (rc != 23 && rc >= 4) {
@@ -1469,6 +1480,12 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
return -EINVAL;
}
memcpy(*bursts_p, *bursts_p + 464, 464);
+
+ /* Send uplnk measurement information to L2 */
+ l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn,
+ n_errors, n_bits_total, rssi, toa);
+
+ /* Check if the frame is bad */
if (rc < 0) {
LOGP(DL1C, LOGL_NOTICE, "Received bad TCH frame ending at "
"fn=%u for %s\n", fn, trx_chan_desc[chan].name);
@@ -1484,7 +1501,7 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
/* FACCH */
if (rc == 23) {
compose_ph_data_ind(l1h, tn, (fn + 2715648 - 7) % 2715648, chan,
- tch_data + amr, 23, 0, 0, 0);
+ tch_data + amr, 23, rssi);
bfi:
if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {
/* indicate bad frame */
@@ -1533,7 +1550,7 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
uint8_t tch_mode = chan_state->tch_mode;
uint8_t tch_data[128]; /* just to be safe */
int rc, amr = 0;
- float ber;
+ int n_errors, n_bits_total;
/* handle rach, if handover rach detection is turned on */
if (chan_state->ho_rach_detect == 1)
@@ -1594,7 +1611,8 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
* Even FN ending at: 10,11,19,20,2,3
*/
rc = tch_hr_decode(tch_data, *bursts_p,
- (((fn + 26 - 10) % 26) >> 2) & 1);
+ (((fn + 26 - 10) % 26) >> 2) & 1,
+ &n_errors, &n_bits_total);
break;
case GSM48_CMODE_SPEECH_AMR: /* AMR */
/* the first FN 0,8,17 or 1,9,18 defines that CMI is included
@@ -1605,11 +1623,11 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
(((fn + 26 - 10) % 26) >> 2) & 1,
(((fn + 26 - 10) % 26) >> 2) & 1, chan_state->codec,
chan_state->codecs, &chan_state->ul_ft,
- &chan_state->ul_cmr, &ber);
+ &chan_state->ul_cmr, &n_errors, &n_bits_total);
if (rc)
trx_loop_amr_input(l1h,
trx_chan_desc[chan].chan_nr | tn, chan_state,
- ber);
+ (float)n_errors/(float)n_bits_total);
amr = 2; /* we store tch_data + 2 two */
/* only good speech frames get rtp header */
if (rc != 23 && rc >= 4) {
@@ -1625,6 +1643,12 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
}
memcpy(*bursts_p, *bursts_p + 232, 232);
memcpy(*bursts_p + 232, *bursts_p + 464, 232);
+
+ /* Send uplnk measurement information to L2 */
+ l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn,
+ n_errors, n_bits_total, rssi, toa);
+
+ /* Check if the frame is bad */
if (rc < 0) {
LOGP(DL1C, LOGL_NOTICE, "Received bad TCH frame ending at "
"fn=%u for %s\n", fn, trx_chan_desc[chan].name);
@@ -1642,7 +1666,7 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
chan_state->ul_ongoing_facch = 1;
compose_ph_data_ind(l1h, tn,
(fn + 2715648 - 10 - ((fn % 26) >= 19)) % 2715648, chan,
- tch_data + amr, 23, 0, 0, 0);
+ tch_data + amr, 23, rssi);
bfi:
if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {
/* indicate bad frame */