fixeria has submitted this change. ( https://gerrit.osmocom.org/c/osmo-trx/+/43107?usp=email )
Change subject: libosmo-trx/trxc: add SETSLOT parameter parser/builder ......................................................................
libosmo-trx/trxc: add SETSLOT parameter parser/builder
Add struct osmo_trxc_setslot plus osmo_trxc_setslot_parse()/_build() for the "<tn> <chan_comb> [C<tsc>/S<tsc_set> ...]" SETSLOT parameters, including VAMOS combinations (VFF/VHH/VFH/HVHH) with per-sub-channel TSC overrides.
Change-Id: I17a1176b1418edd0caf750d50acda0482d4ad04a --- M libosmo-trx/include/osmocom/trx/trxc.h M libosmo-trx/src/trxc.c M tests/libosmo-trx/trxc_test.c M tests/libosmo-trx/trxc_test.ok 4 files changed, 253 insertions(+), 0 deletions(-)
Approvals: laforge: Looks good to me, but someone else must approve pespin: Looks good to me, but someone else must approve fixeria: Looks good to me, approved Jenkins Builder: Verified
diff --git a/libosmo-trx/include/osmocom/trx/trxc.h b/libosmo-trx/include/osmocom/trx/trxc.h index f3a64b6..3844357 100644 --- a/libosmo-trx/include/osmocom/trx/trxc.h +++ b/libosmo-trx/include/osmocom/trx/trxc.h @@ -4,6 +4,9 @@
#include <stdint.h> #include <stddef.h> +#include <stdbool.h> + +#include <osmocom/core/utils.h>
/*! Maximum length of a command verb (incl. '\0') */ #define OSMO_TRXC_CMD_LEN_MAX 32 @@ -62,6 +65,66 @@ #define OSMO_TRXC_CMD_SETFH "SETFH" #define OSMO_TRXC_CMD_ERR "ERR" /*!< verb of a reject response */
+/* SETSLOT: "<tn> <chan_comb> [C<tsc>/S<tsc_set> ...]" */ + +/*! Classic (non-VAMOS) GSM TS 05.02 channel combinations, as used by the + * \c chan_comb parameter of SETSLOT. Numeric values match the wire format. */ +enum osmo_trxc_chan_comb { + OSMO_TRXC_CHAN_COMB_UNUSED = 0, /*!< Channel is transmitted, but unused */ + OSMO_TRXC_CHAN_COMB_TCHF = 1, + OSMO_TRXC_CHAN_COMB_TCHH_IDLE = 2, /*!< TCH/HS, idle every other slot */ + OSMO_TRXC_CHAN_COMB_TCHH = 3, + OSMO_TRXC_CHAN_COMB_BCCH = 4, /*!< DL: FCCH+SCH+CCCH+BCCH, UL: RACH */ + OSMO_TRXC_CHAN_COMB_BCCH_SDCCH4 = 5, /*!< DL: +SDCCH/4+SACCH/4, UL: +SDCCH/4 */ + OSMO_TRXC_CHAN_COMB_CCCH = 6, /*!< DL: CCCH+BCCH, UL: RACH */ + OSMO_TRXC_CHAN_COMB_SDCCH8 = 7, /*!< SDCCH/8 + SACCH/8 */ + OSMO_TRXC_CHAN_COMB_TCHF_FACCH_SACCHM = 8, + OSMO_TRXC_CHAN_COMB_TCHF_SACCHM = 9, + OSMO_TRXC_CHAN_COMB_TCHFD_SACCHMD = 10, + OSMO_TRXC_CHAN_COMB_PBCCH = 11, /*!< PBCCH+PCCCH+PDTCH+PACCH+PTCCH */ + OSMO_TRXC_CHAN_COMB_PCCCH = 12, /*!< PCCCH+PDTCH+PACCH+PTCCH */ + OSMO_TRXC_CHAN_COMB_PDTCH = 13, /*!< PDTCH+PACCH+PTCCH */ +}; + +/*! VAMOS-enabled channel combinations: the \c chan_comb parameter of SETSLOT + * is symbolic (not numeric) for these. */ +enum osmo_trxc_vamos_comb { + OSMO_TRXC_VAMOS_COMB_VFF = 1, /*!< V0(TCH/F) & V1(TCH/F) */ + OSMO_TRXC_VAMOS_COMB_VHH, /*!< V0(TCH/H0)&V1(TCH/H0) + V0(TCH/H1)&V1(TCH/H1) */ + OSMO_TRXC_VAMOS_COMB_VFH, /*!< V0(TCH/F) & V1(TCH/H0) + V0(TCH/F) & V1(TCH/H1) */ + OSMO_TRXC_VAMOS_COMB_HVHH, /*!< TCH/H0 + V0(TCH/H1) & V1(TCH/H1) (mixed) */ +}; + +extern const struct value_string osmo_trxc_vamos_comb_names[]; +static inline const char *osmo_trxc_vamos_comb_name(enum osmo_trxc_vamos_comb comb) +{ + return get_value_string(osmo_trxc_vamos_comb_names, comb); +} + +#define OSMO_TRXC_SETSLOT_TSC_MAX 3 /*!< up to 3 sub-channels (VAMOS "HVHH") */ + +/*! One "C<tsc>/S<tsc_set>" override, as used by SETSLOT for (VAMOS) + * sub-channels that don't use the endpoint-wide TSC (SETTSC). */ +struct osmo_trxc_setslot_tsc { + uint8_t tsc; + uint8_t tsc_set; +}; + +/*! Parsed SETSLOT parameters. */ +struct osmo_trxc_setslot { + uint8_t tn; + bool vamos; /*!< false: chan_comb is valid, true: vamos_comb is valid */ + union { + enum osmo_trxc_chan_comb chan_comb; + enum osmo_trxc_vamos_comb vamos_comb; + }; + unsigned int num_tsc; /*!< number of valid entries in tsc[] */ + struct osmo_trxc_setslot_tsc tsc[OSMO_TRXC_SETSLOT_TSC_MAX]; +}; + +int osmo_trxc_setslot_parse(struct osmo_trxc_setslot *ss, const struct osmo_trxc_msg *msg); +int osmo_trxc_setslot_build(char *buf, size_t buf_size, const struct osmo_trxc_setslot *ss); + /* Clock socket: "IND CLOCK <fn>" */ int osmo_trxc_clock_ind_parse(uint32_t *fn, const char *buf, size_t len); int osmo_trxc_clock_ind_build(char *buf, size_t buf_size, uint32_t fn); diff --git a/libosmo-trx/src/trxc.c b/libosmo-trx/src/trxc.c index 70d8c16..9425068 100644 --- a/libosmo-trx/src/trxc.c +++ b/libosmo-trx/src/trxc.c @@ -44,6 +44,14 @@ { 0, NULL } };
+const struct value_string osmo_trxc_vamos_comb_names[] = { + { OSMO_TRXC_VAMOS_COMB_VFF, "VFF" }, + { OSMO_TRXC_VAMOS_COMB_VHH, "VHH" }, + { OSMO_TRXC_VAMOS_COMB_VFH, "VFH" }, + { OSMO_TRXC_VAMOS_COMB_HVHH, "HVHH" }, + { 0, NULL } +}; + /*! Parse a TRXC message ("CMD <verb> [<params>]", "RSP <verb> <status> * [<params>]" or "IND <verb> <params>") from a zero-terminated buffer. * \param[out] msg parsed message @@ -170,6 +178,89 @@ return osmo_trxc_msg_build(buf, buf_size, msg) < 0 ? NULL : buf; }
+/*! Parse SETSLOT parameters ("<tn> <chan_comb> [C<tsc>/S<tsc_set> ...]") + * from an already-parsed TRXC message's msg->params. + * \returns 0 on success; negative on error */ +int osmo_trxc_setslot_parse(struct osmo_trxc_setslot *ss, const struct osmo_trxc_msg *msg) +{ + char params[OSMO_TRXC_PARAMS_LEN_MAX]; + char *saveptr, *tok; + unsigned int tn; + int comb; + + memset(ss, 0, sizeof(*ss)); + + OSMO_STRLCPY_ARRAY(params, msg->params); + + tok = strtok_r(params, " ", &saveptr); + if (tok == NULL || sscanf(tok, "%u", &tn) != 1) + return -EINVAL; + if (tn > 7) + return -ERANGE; + ss->tn = tn; + + tok = strtok_r(NULL, " ", &saveptr); + if (tok == NULL) + return -EINVAL; + comb = get_string_value(osmo_trxc_vamos_comb_names, tok); + if (comb >= 0) { + ss->vamos = true; + ss->vamos_comb = comb; + } else { + if (sscanf(tok, "%d", &comb) != 1) + return -EINVAL; + if (comb < OSMO_TRXC_CHAN_COMB_UNUSED || comb > OSMO_TRXC_CHAN_COMB_PDTCH) + return -ERANGE; + ss->vamos = false; + ss->chan_comb = comb; + } + + while ((tok = strtok_r(NULL, " ", &saveptr)) != NULL) { + unsigned int tsc, tsc_set; + + if (ss->num_tsc >= OSMO_TRXC_SETSLOT_TSC_MAX) + return -E2BIG; + if (sscanf(tok, "C%u/S%u", &tsc, &tsc_set) != 2) + return -EINVAL; + ss->tsc[ss->num_tsc].tsc = tsc; + ss->tsc[ss->num_tsc].tsc_set = tsc_set; + ss->num_tsc++; + } + + return 0; +} + +/*! Serialize SETSLOT parameters ("<tn> <chan_comb> [C<tsc>/S<tsc_set> ...]") + * into the given buffer (zero-terminated), for use as msg->params. + * \returns length of the string (excl. '\0') on success; negative on error */ +int osmo_trxc_setslot_build(char *buf, size_t buf_size, const struct osmo_trxc_setslot *ss) +{ + unsigned int i; + int rc, len; + + if (ss->tn > 7) + return -ERANGE; + + if (ss->vamos) + rc = snprintf(buf, buf_size, "%u %s", ss->tn, + osmo_trxc_vamos_comb_name(ss->vamos_comb)); + else + rc = snprintf(buf, buf_size, "%u %d", ss->tn, ss->chan_comb); + if (rc < 0 || (size_t)rc >= buf_size) + return -EMSGSIZE; + len = rc; + + for (i = 0; i < ss->num_tsc; i++) { + rc = snprintf(buf + len, buf_size - len, " C%u/S%u", + ss->tsc[i].tsc, ss->tsc[i].tsc_set); + if (rc < 0 || (size_t)rc >= buf_size - (size_t)len) + return -EMSGSIZE; + len += rc; + } + + return len; +} + /*! Parse a clock indication ("IND CLOCK <fn>"). * \param[out] fn TDMA frame number (validated to be < GSM_TDMA_HYPERFRAME) * \param[in] buf message buffer (not necessarily zero-terminated) diff --git a/tests/libosmo-trx/trxc_test.c b/tests/libosmo-trx/trxc_test.c index 93eea83..b4653cd 100644 --- a/tests/libosmo-trx/trxc_test.c +++ b/tests/libosmo-trx/trxc_test.c @@ -194,6 +194,79 @@ OSMO_ASSERT(rc < 0); }
+static void test_setslot_parse_one(const char *params) +{ + struct osmo_trxc_msg msg = { .type = OSMO_TRXC_MT_CMD, .cmd = "SETSLOT" }; + struct osmo_trxc_setslot ss; + char buf[OSMO_TRXC_MSG_BUF_SIZE]; + int rc; + + snprintf(msg.params, sizeof(msg.params), "%s", params); + + rc = osmo_trxc_setslot_parse(&ss, &msg); + if (rc < 0) { + printf("'%s' -> rc=%d\n", params, rc); + return; + } + + printf("'%s' -> tn=%u vamos=%d comb=%s num_tsc=%u", + params, ss.tn, ss.vamos, + ss.vamos ? osmo_trxc_vamos_comb_name(ss.vamos_comb) : "(numeric)", + ss.num_tsc); + if (!ss.vamos) + printf(" chan_comb=%d", ss.chan_comb); + for (unsigned int i = 0; i < ss.num_tsc; i++) + printf(" C%u/S%u", ss.tsc[i].tsc, ss.tsc[i].tsc_set); + printf("\n"); + + /* re-encode and compare against the original params */ + rc = osmo_trxc_setslot_build(buf, sizeof(buf), &ss); + OSMO_ASSERT(rc > 0 && rc == (int)strlen(buf)); + printf("\tre-encoded: '%s'\n", buf); + OSMO_ASSERT(strcmp(buf, params) == 0); +} + +static void test_setslot(void) +{ + static const char * const good[] = { + "0 0", + "7 13", + "4 1 C7/S1", /* manual example */ + "0 VFF C0/S1 C0/S2", /* manual example */ + "3 VHH C1/S3 C1/S4", /* manual example */ + "1 VFH C2/S1 C2/S4", /* manual example */ + "2 HVHH C0/S1 C0/S1 C0/S2", /* manual example */ + }; + static const char * const bad[] = { + "8 0", /* tn out of range */ + "0 14", /* chan_comb out of range */ + "0 -1", /* chan_comb out of range */ + "0", /* missing chan_comb */ + "", /* missing everything */ + "x 0", /* tn not numeric */ + "0 x", /* chan_comb not numeric, not a known VAMOS name */ + "0 0 bogus", /* trailing token not a C<tsc>/S<tsc_set> */ + "0 HVHH C0/S1 C0/S1 C0/S2 C0/S3", /* too many TSC overrides */ + }; + struct osmo_trxc_msg msg = { .type = OSMO_TRXC_MT_CMD, .cmd = "SETSLOT" }; + struct osmo_trxc_setslot ss; + int rc; + + printf("=== %s ===\n", __func__); + + for (unsigned int i = 0; i < ARRAY_SIZE(good); i++) + test_setslot_parse_one(good[i]); + for (unsigned int i = 0; i < ARRAY_SIZE(bad); i++) + test_setslot_parse_one(bad[i]); + + /* build() range check */ + memset(&ss, 0, sizeof(ss)); + ss.tn = 8; + rc = osmo_trxc_setslot_build(msg.params, sizeof(msg.params), &ss); + printf("build with out of range tn: rc=%d\n", rc); + OSMO_ASSERT(rc < 0); +} + int main(int argc, char **argv) { test_msg_parse(); @@ -201,6 +274,7 @@ test_params_scan(); test_long_params(); test_clk_ind(); + test_setslot();
printf("Done\n"); return 0; diff --git a/tests/libosmo-trx/trxc_test.ok b/tests/libosmo-trx/trxc_test.ok index 845d4da..30b47ff 100644 --- a/tests/libosmo-trx/trxc_test.ok +++ b/tests/libosmo-trx/trxc_test.ok @@ -52,4 +52,29 @@ 'IND KCOLC 123' -> rc=-22 'CMD CLOCK 123' -> rc=-22 build with out of range fn: rc=-34 +=== test_setslot === +'0 0' -> tn=0 vamos=0 comb=(numeric) num_tsc=0 chan_comb=0 + re-encoded: '0 0' +'7 13' -> tn=7 vamos=0 comb=(numeric) num_tsc=0 chan_comb=13 + re-encoded: '7 13' +'4 1 C7/S1' -> tn=4 vamos=0 comb=(numeric) num_tsc=1 chan_comb=1 C7/S1 + re-encoded: '4 1 C7/S1' +'0 VFF C0/S1 C0/S2' -> tn=0 vamos=1 comb=VFF num_tsc=2 C0/S1 C0/S2 + re-encoded: '0 VFF C0/S1 C0/S2' +'3 VHH C1/S3 C1/S4' -> tn=3 vamos=1 comb=VHH num_tsc=2 C1/S3 C1/S4 + re-encoded: '3 VHH C1/S3 C1/S4' +'1 VFH C2/S1 C2/S4' -> tn=1 vamos=1 comb=VFH num_tsc=2 C2/S1 C2/S4 + re-encoded: '1 VFH C2/S1 C2/S4' +'2 HVHH C0/S1 C0/S1 C0/S2' -> tn=2 vamos=1 comb=HVHH num_tsc=3 C0/S1 C0/S1 C0/S2 + re-encoded: '2 HVHH C0/S1 C0/S1 C0/S2' +'8 0' -> rc=-34 +'0 14' -> rc=-34 +'0 -1' -> rc=-34 +'0' -> rc=-22 +'' -> rc=-22 +'x 0' -> rc=-22 +'0 x' -> rc=-22 +'0 0 bogus' -> rc=-22 +'0 HVHH C0/S1 C0/S1 C0/S2 C0/S3' -> rc=-7 +build with out of range tn: rc=-34 Done