diff options
author | Alexander Chemeris <Alexander.Chemeris@gmail.com> | 2015-04-06 00:12:02 +0300 |
---|---|---|
committer | Alexander Chemeris <Alexander.Chemeris@gmail.com> | 2015-04-23 21:42:54 -0400 |
commit | e510c8486082c9434b981358866f93878c0f7258 (patch) | |
tree | 7ec58b655ca0f6c5a9f9d8b40c79c990bf611892 | |
parent | 9b7e7f76220410be755d27c05486ee3ddfc49bb8 (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.c | 234 | ||||
-rw-r--r-- | src/osmo-bts-trx/gsm0503_coding.h | 37 | ||||
-rw-r--r-- | src/osmo-bts-trx/l1_if.c | 33 | ||||
-rw-r--r-- | src/osmo-bts-trx/l1_if.h | 6 | ||||
-rw-r--r-- | src/osmo-bts-trx/scheduler.c | 78 |
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 82f50912..e9d98a3e 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 * @@ -457,19 +458,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 */ |