laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/libosmo-abis/+/41210?usp=email )

Change subject: trau_frame: add support for config frames of 3GPP Rel5+
......................................................................

trau_frame: add support for config frames of 3GPP Rel5+

3GPP Rel5 introduced Generic Config Frame format for TFO, defined
in TS 28.062 Annex H (globally interoperable interface), and also
defined equivalent Speech Codec Configuration Exchange frames on
Abis (treated mostly as vendor-private interface by this point),
added to TS 48.060 and 48.061.  These Generic Config Frames are
mandatory for AMR-WB codec, which not only requires TFO in order
to be useful (in the absence of all-IP TrFO), but also lacks the
ability to stuff TFO config parameters into regular speech frames
in the way that was specified in 3GPP Rel4 for AMR-NB.

Support for these GCFs on Abis is necessary in order to support
TFO-AMR with some vendors' E1 BTS.  Some vendors of TDM-based
GSM BSS felt no interest in TFO-AMR for its own sake, and only
implemented TFO support for AMR (both NB and WB) when forced
to do so by AMR-WB market demand; these vendors (Nokia is one known
case) skipped 3GPP Rel4 version of TFO-AMR and went directly for
Rel5 version, using Generic Config Frames on Abis for both AMR-NB
and AMR-WB.

Change-Id: Ifbde07e4a3fb80e4faa0b6a6b32938ed98371c5b
---
M include/osmocom/trau/trau_frame.h
M src/trau/trau_frame.c
2 files changed, 178 insertions(+), 14 deletions(-)

Approvals:
  keith: Looks good to me, but someone else must approve
  fixeria: Looks good to me, approved
  Jenkins Builder: Verified




diff --git a/include/osmocom/trau/trau_frame.h 
b/include/osmocom/trau/trau_frame.h
index dd14f27..9048dca 100644
--- a/include/osmocom/trau/trau_frame.h
+++ b/include/osmocom/trau/trau_frame.h
@@ -62,6 +62,7 @@
 #define TRAU_FT_EDATA          0x1f    /* 1 1 1 1 1 - 3.5.4 */
 #define TRAU_FT_IDLE_UP                0x10    /* 1 0 0 0 0 - 3.5.5 */
 #define TRAU_FT_IDLE_DOWN      0x0e    /* 0 1 1 1 0 - 3.5.5 */
+#define TRAU_FT_CONFIG_EXCH    0x1e    /* 1 1 1 1 0 - TS 48.060 5.5.1.5 */

 /* 8k sub-slot types: Bits C1..C5*/
 #define TRAU8_FT_SPEECH_UP     0x02    /* 0 0 0 1 P - TS 08.61 5.2.4.1.1 */
@@ -94,6 +95,10 @@
        OSMO_TRAU8_AMR_LOW,
        OSMO_TRAU8_AMR_6k7,
        OSMO_TRAU8_AMR_7k4,
+
+       /* new types at the end, for ABI compatibility */
+       OSMO_TRAU16_FT_CONFIG,
+       OSMO_TRAU8_CONFIG,
 };

 extern const struct value_string osmo_trau_frame_type_names[];
diff --git a/src/trau/trau_frame.c b/src/trau/trau_frame.c
index d0cf3d1..896bc20 100644
--- a/src/trau/trau_frame.c
+++ b/src/trau/trau_frame.c
@@ -61,12 +61,14 @@
        { OSMO_TRAU16_FT_D145_SYNC,     "D145_SYNC" },
        { OSMO_TRAU16_FT_DATA_HR,       "DATA_HR" },
        { OSMO_TRAU16_FT_IDLE,          "IDLE" },
+       { OSMO_TRAU16_FT_CONFIG,        "CONFIG" },
        { OSMO_TRAU8_SPEECH,            "8SPEECH" },
        { OSMO_TRAU8_DATA,              "8DATA" },
        { OSMO_TRAU8_OAM,               "8OAM" },
        { OSMO_TRAU8_AMR_LOW,           "8AMR_LOW" },
        { OSMO_TRAU8_AMR_6k7,           "8AMR_6k7" },
        { OSMO_TRAU8_AMR_7k4,           "8AMR_7k4" },
+       { OSMO_TRAU8_CONFIG,            "8CONFIG" },
        { 0, NULL }
 };

@@ -763,6 +765,57 @@
        return 40 * 8;
 }

+/* TS 48.060 sections 5.1.5 and 5.5.1.5: generic configuration frames */
+
+static int decode16_gcf(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
+                       enum osmo_trau_frame_direction dir)
+{
+       int i, d_idx;
+
+       /* C1 .. C5 */
+       memcpy(fr->c_bits, trau_bits + 17, 5);
+
+       /* D1 .. D10 */
+       memcpy(fr->d_bits, trau_bits + 22, 10);
+       d_idx = 10;
+       /* D11 .. D265 */
+       for (i = 32; i < 304; i += 16) {
+               memcpy(fr->d_bits + d_idx, trau_bits + i + 1, 15);
+               d_idx += 15;
+       }
+       /* D266 .. D276 */
+       memcpy(fr->d_bits + d_idx, trau_bits + 305, 11);
+
+       /* T1 .. T4 */
+       memcpy(fr->t_bits, trau_bits + 316, 4);
+
+       return 0;
+}
+
+static int encode16_gcf(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
+{
+       int i, d_idx;
+
+       encode_sync16(trau_bits);
+
+       /* C1 .. C5 */
+       memcpy(trau_bits + 17, fr->c_bits, 5);
+       /* D1 .. D10 */
+       memcpy(trau_bits + 22, fr->d_bits, 10);
+
+       /* D11 .. D276 */
+       for (i = 32, d_idx = 10; i <= 315; i += 16, d_idx += 15) {
+               trau_bits[i] = 1;
+               memcpy(trau_bits + i + 1, fr->d_bits + d_idx, 15);
+       }
+
+       /* T1 .. T4 */
+       memcpy(trau_bits + 316, fr->t_bits, 4);
+
+       /* handle timing adjustment */
+       return encode16_handle_ta(trau_bits, fr);
+}
+
 /* TS 08.61 Section 5.2.1.1 */
 static int decode8_hr(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
                      enum osmo_trau_frame_direction dir)
@@ -1229,6 +1282,70 @@
        return 20 * 8;
 }

+/* TS 48.061 section 5.2.1.3: generic configuration frames */
+
+static int decode8_gcf(struct osmo_trau_frame *fr, const ubit_t *trau_bits,
+                      enum osmo_trau_frame_direction dir)
+{
+       int i, d_idx = 0;
+
+       /* C1 .. C5 */
+       memcpy(fr->c_bits, trau_bits + 1 * 8 + 1, 5);
+       /* D1 .. D2 */
+       memcpy(fr->d_bits + d_idx, trau_bits + 1 * 8 + 6, 2);
+       d_idx += 2;
+       /* D3 .. D8 */
+       memcpy(fr->d_bits + d_idx, trau_bits + 2 * 8 + 2, 6);
+       d_idx += 6;
+       /* D9 .. D120 */
+       for (i = 3; i < 19; i++) {
+               memcpy(fr->d_bits + d_idx, trau_bits + i * 8 + 1, 7);
+               d_idx += 7;
+       }
+       /* D121 .. D125 */
+       memcpy(fr->d_bits + d_idx, trau_bits + 19 * 8 + 1, 5);
+
+       /* T1 .. T2 */
+       memcpy(fr->t_bits, trau_bits + 19 * 8 + 6, 2);
+
+       return 0;
+}
+
+static int encode8_gcf(ubit_t *trau_bits, const struct osmo_trau_frame *fr)
+{
+       int i, d_idx = 0;
+
+       /* sync pattern */
+       memset(trau_bits, 0, 8);
+       trau_bits[1 * 8 + 0] = 1;
+       trau_bits[2 * 8 + 0] = 0;
+       trau_bits[2 * 8 + 1] = 1;
+       for (i = 3; i < 20; i++)
+               trau_bits[i * 8] = 1;
+
+       /* C1 .. C5 */
+       memcpy(trau_bits + 1 * 8 + 1, fr->c_bits, 5);
+       /* D1 .. D2 */
+       memcpy(trau_bits + 1 * 8 + 6, fr->d_bits + d_idx, 2);
+       d_idx += 2;
+       /* D3 .. D8 */
+       memcpy(trau_bits + 2 * 8 + 2, fr->d_bits + d_idx, 6);
+       d_idx += 6;
+       /* D9 .. D120 */
+       for (i = 3; i < 19; i++) {
+               memcpy(trau_bits + i * 8 + 1, fr->d_bits + d_idx, 7);
+               d_idx += 7;
+       }
+       /* D121 .. D125 */
+       memcpy(trau_bits + 19 * 8 + 1, fr->d_bits + d_idx, 5);
+
+       /* T1 .. T2 */
+       memcpy(trau_bits + 19 * 8 + 6, fr->t_bits, 2);
+
+       /* handle timing adjustment */
+       return encode8_handle_ta(trau_bits, fr);
+}
+

 /*! Encode a TRAU frame from its decoded representation to a sequence of 
unpacked bits.
  *  \param[out] bits caller-allocated buffer for unpacked output bits
@@ -1250,17 +1367,18 @@
  * The following list summarizes the behavior of the present function with
  * regard to C1..C5 bits for different frame types:
  *
- * - For all TRAU-16k frame types in both UL and DL directions, and for
- *   OSMO_TRAU8_SPEECH (TRAU-8k for HRv1 speech) in UL direction, the first 5
- *   bits of fr->c_bits[] are ignored and replaced with internally supplied
- *   constant values.
+ * - For all TRAU-16k frame types in both UL and DL directions, with the
+ *   exception of newly added OSMO_TRAU16_FT_CONFIG, and for OSMO_TRAU8_SPEECH
+ *   (TRAU-8k for HRv1 speech) in UL direction, the first 5 bits of 
fr->c_bits[]
+ *   are ignored and replaced with internally supplied constant values.
  *
  * - For OSMO_TRAU8_SPEECH in DL direction, only fr->c_bits[3] is used to set
  *   C4; constant values for C1..C3 and odd parity value for C5 are fixed
  *   by the function.
  *
- * - For OSMO_TRAU8_DATA, OSMO_TRAU8_OAM and all AMR-8k frame types,
- *   user-supplied fr->c_bits[] are always used.
+ * - For OSMO_TRAU8_DATA, OSMO_TRAU8_OAM and all AMR-8k frame types, as well as
+ *   newly added OSMO_TRAU16_FT_CONFIG and OSMO_TRAU8_CONFIG, user-supplied
+ *   fr->c_bits[] are always used.
  *
  * This unfortunate manipulation applies only to C1..C5 as listed above;
  * for control bits C6 and higher (for frame types that have them),
@@ -1277,6 +1395,7 @@
        case OSMO_TRAU16_FT_HR:
        case OSMO_TRAU16_FT_AMR:
        case OSMO_TRAU16_FT_IDLE:
+       case OSMO_TRAU16_FT_CONFIG:
                /* timing alignment may happen: increased space requirement */
                if (fr->dir == OSMO_TRAU_DIR_DL && fr->dl_ta_usec > 0)
                        space_req = 2 * 40 * 8 - 1;
@@ -1294,6 +1413,7 @@
        case OSMO_TRAU8_AMR_LOW:
        case OSMO_TRAU8_AMR_6k7:
        case OSMO_TRAU8_AMR_7k4:
+       case OSMO_TRAU8_CONFIG:
                /* timing alignment may happen: increased space requirement */
                if (fr->dir == OSMO_TRAU_DIR_DL && fr->dl_ta_usec > 0)
                        space_req = 2 * 20 * 8 - 1;
@@ -1330,6 +1450,8 @@
                return encode16_d145_sync(bits, fr);
        case OSMO_TRAU16_FT_EDATA:
                return encode16_edata(bits, fr);
+       case OSMO_TRAU16_FT_CONFIG:
+               return encode16_gcf(bits, fr);
        case OSMO_TRAU8_SPEECH:
                return encode8_hr(bits, fr, false);
        case OSMO_TRAU8_DATA:
@@ -1342,6 +1464,8 @@
                return encode8_amr_67(bits, fr);
        case OSMO_TRAU8_AMR_7k4:
                return encode8_amr_74(bits, fr);
+       case OSMO_TRAU8_CONFIG:
+               return encode8_gcf(bits, fr);
        default:
                return -EINVAL;
        }
@@ -1371,6 +1495,7 @@
        case OSMO_TRAU16_FT_FR:
        case OSMO_TRAU16_FT_EFR:
        case OSMO_TRAU16_FT_AMR:
+       case OSMO_TRAU16_FT_CONFIG:
                if (n_bits < 1 * 40 * 8)
                        return -ENOSPC;
                break;
@@ -1378,6 +1503,7 @@
        case OSMO_TRAU8_AMR_LOW:
        case OSMO_TRAU8_AMR_6k7:
        case OSMO_TRAU8_AMR_7k4:
+       case OSMO_TRAU8_CONFIG:
                if (n_bits < 1 * 20 * 8)
                        return -ENOSPC;
                break;
@@ -1391,6 +1517,8 @@
                return encode16_fr(bits, fr, true);
        case OSMO_TRAU16_FT_AMR:
                return encode16_amr(bits, fr, true);
+       case OSMO_TRAU16_FT_CONFIG:
+               return encode16_gcf(bits, fr);
        case OSMO_TRAU8_SPEECH:
                return encode8_hr(bits, fr, true);
        case OSMO_TRAU8_AMR_LOW:
@@ -1399,6 +1527,8 @@
                return encode8_amr_67(bits, fr);
        case OSMO_TRAU8_AMR_7k4:
                return encode8_amr_74(bits, fr);
+       case OSMO_TRAU8_CONFIG:
+               return encode8_gcf(bits, fr);
        default:
                return -EINVAL;
        }
@@ -1455,6 +1585,9 @@
        case TRAU_FT_D145_SYNC:
                fr->type = OSMO_TRAU16_FT_D145_SYNC;
                return decode16_data(fr, bits, dir);
+       case TRAU_FT_CONFIG_EXCH:
+               fr->type = OSMO_TRAU16_FT_CONFIG;
+               return decode16_gcf(fr, bits, dir);

        default:
                return -EINVAL;
@@ -1499,6 +1632,9 @@
        case 0xB:       /* OHR_AMR */
                fr->type = OSMO_TRAU16_FT_AMR;
                return decode16_amr(fr, bits, fr->dir);
+       case TRAU_FT_CONFIG_EXCH >> 1:
+               fr->type = OSMO_TRAU16_FT_CONFIG;
+               return decode16_gcf(fr, bits, fr->dir);
        default:
                return -EINVAL;
        }
@@ -1617,6 +1753,9 @@
                        case 0x0B:
                                fr->type = OSMO_TRAU8_OAM;
                                return decode8_oam(fr, bits, dir);
+                       case 0x1F:
+                               fr->type = OSMO_TRAU8_CONFIG;
+                               return decode8_gcf(fr, bits, dir);
                        }
                } else {
                        /* Downlink */
@@ -1630,6 +1769,9 @@
                        case 2:
                                fr->type = OSMO_TRAU8_OAM;
                                return decode8_oam(fr, bits, dir);
+                       case 7:
+                               fr->type = OSMO_TRAU8_CONFIG;
+                               return decode8_gcf(fr, bits, dir);
                        }
                }
        } else if (is_amr_low(bits)) {
@@ -1665,18 +1807,31 @@
  * no need to distinguish between HRv1 and AMR-8k frames by their respective
  * sync patterns: per TS 28.062, these two TFO frame types never occur
  * in the same bit position in TFO-superimposed PCM speech octets.
- * Because HRv1 is the only TFO frame type that can occur in the configuration
- * of TS 28.062 section 5.3 (only the one lsb in each PCM speech octet is
- * overwritten), this function skips all attempts at frame type classification:
- * the TFO application is responsible for detecting the presence of valid
- * TFO frames for the negotiated codec type.
+ *
+ * Frame type bits C1..C4 are checked only to distinguish between regular
+ * HRv1 speech frames and Generic Configuration Frames of TS 28.062 Annex H:
+ * Rel5+ versions of TFO spec allow these GCFs to be used with all codecs
+ * if both ends of TFO connection implement Rel5+ version of TFO.
  */
 int osmo_trau_frame_decode_tfo_hr1(struct osmo_trau_frame *fr, const ubit_t 
*bits)
 {
-       fr->type = OSMO_TRAU8_SPEECH;
+       uint8_t cbits4 = get_bits(bits, 9, 4);
+       /* We don't look at bit C5 because it is EMBED bit in TFO frames */
+
+       fr->type = OSMO_TRAU_FT_NONE;
        fr->dir = OSMO_TRAU_DIR_UL;     /* TFO frames are modified TRAU-UL */
        fr->dl_ta_usec = 0;
-       return decode8_hr(fr, bits, fr->dir);
+
+       switch (cbits4) {
+       case 0x01:
+               fr->type = OSMO_TRAU8_SPEECH;
+               return decode8_hr(fr, bits, fr->dir);
+       case 0x0F:
+               fr->type = OSMO_TRAU8_CONFIG;
+               return decode8_gcf(fr, bits, fr->dir);
+       default:
+               return -EINVAL;
+       }
 }

 /*! Decode/parse an AMR_TFO_8+8k frame from unpacked bits to decoded format.
@@ -1690,7 +1845,8 @@
  * The second lsb extracted from PCM samples is the entity being decoded here.
  * Compared to osmo_trau_frame_decode_8k(), the present function requires
  * the direction to be TRAU-UL (as always the case in TFO) and accepts
- * only AMR-8k frame types.
+ * only AMR-8k frame types, or Generic Configuration Frames of TS 28.062
+ * Annex H that are used in Rel5+ version of TFO.
  */
 int osmo_trau_frame_decode_tfo_amr_8k(struct osmo_trau_frame *fr, const ubit_t 
*bits)
 {
@@ -1707,6 +1863,9 @@
        } else if (is_amr_74(bits)) {
                fr->type = OSMO_TRAU8_AMR_7k4;
                return decode8_amr_74(fr, bits, fr->dir);
+       } else if (is_hr(bits) && get_bits(bits, 9, 4) == 0x0F) {
+               fr->type = OSMO_TRAU8_CONFIG;
+               return decode8_gcf(fr, bits, fr->dir);
        }

        return -EINVAL;

--
To view, visit https://gerrit.osmocom.org/c/libosmo-abis/+/41210?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: merged
Gerrit-Project: libosmo-abis
Gerrit-Branch: master
Gerrit-Change-Id: Ifbde07e4a3fb80e4faa0b6a6b32938ed98371c5b
Gerrit-Change-Number: 41210
Gerrit-PatchSet: 1
Gerrit-Owner: falconia <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <[email protected]>
Gerrit-Reviewer: keith <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>

Reply via email to