/* * (C) 2023 by sysmocom s.f.m.c. GmbH * All Rights Reserved * * Author: Oliver Smith * * 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 Affero 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 . * */ #include #include #include #include #include static int gsm0808_data_rate_transp_to_gsm0858(enum gsm0808_data_rate_transp rate) { switch (rate) { case GSM0808_DATA_RATE_TRANSP_32k0: return RSL_CMOD_CSD_T_32k0; case GSM0808_DATA_RATE_TRANSP_28k8: return RSL_CMOD_CSD_T_29k0; case GSM0808_DATA_RATE_TRANSP_14k4: return RSL_CMOD_CSD_T_14k4; case GSM0808_DATA_RATE_TRANSP_9k6: return RSL_CMOD_CSD_T_9k6; case GSM0808_DATA_RATE_TRANSP_4k8: return RSL_CMOD_CSD_T_4k8; case GSM0808_DATA_RATE_TRANSP_2k4: return RSL_CMOD_CSD_T_2k4; case GSM0808_DATA_RATE_TRANSP_1k2: return RSL_CMOD_CSD_T_1k2; case GSM0808_DATA_RATE_TRANSP_600: return RSL_CMOD_CSD_T_600; case GSM0808_DATA_RATE_TRANSP_1200_75: return RSL_CMOD_CSD_T_1200_75; default: LOGP(DMSC, LOGL_ERROR, "Unsupported transparent data rate 0x%x\n", rate); return -1; } } static int gsm0808_data_rate_transp_to_gsm0408(enum gsm0808_data_rate_transp rate) { switch (rate) { case GSM0808_DATA_RATE_TRANSP_14k4: return GSM48_CMODE_DATA_14k5; case GSM0808_DATA_RATE_TRANSP_9k6: return GSM48_CMODE_DATA_12k0; case GSM0808_DATA_RATE_TRANSP_4k8: return GSM48_CMODE_DATA_6k0; case GSM0808_DATA_RATE_TRANSP_2k4: case GSM0808_DATA_RATE_TRANSP_1k2: case GSM0808_DATA_RATE_TRANSP_600: case GSM0808_DATA_RATE_TRANSP_1200_75: return GSM48_CMODE_DATA_3k6; default: LOGP(DMSC, LOGL_ERROR, "Unsupported transparent data rate 0x%x\n", rate); return -1; } } static int gsm0808_data_rate_non_transp_to_gsm0408(enum gsm0808_data_rate_non_transp rate, bool full_rate) { switch (rate) { case GSM0808_DATA_RATE_NON_TRANSP_12000_6000: if (full_rate) return GSM48_CMODE_DATA_12k0; return GSM48_CMODE_DATA_6k0; case GSM0808_DATA_RATE_NON_TRANSP_14k5: return GSM48_CMODE_DATA_14k5; case GSM0808_DATA_RATE_NON_TRANSP_12k0: return GSM48_CMODE_DATA_12k0; case GSM0808_DATA_RATE_NON_TRANSP_6k0: return GSM48_CMODE_DATA_6k0; default: LOGP(DMSC, LOGL_ERROR, "Unsupported non-transparent data rate 0x%x\n", rate); return -1; } } static int gsm0808_data_rate_non_transp_to_gsm0858(enum gsm0808_data_rate_non_transp rate, bool full_rate) { switch (rate) { case GSM0808_DATA_RATE_NON_TRANSP_12000_6000: if (full_rate) return RSL_CMOD_CSD_NT_12k0; return RSL_CMOD_CSD_NT_6k0; case GSM0808_DATA_RATE_NON_TRANSP_14k5: return RSL_CMOD_CSD_NT_14k5; case GSM0808_DATA_RATE_NON_TRANSP_12k0: return RSL_CMOD_CSD_NT_12k0; case GSM0808_DATA_RATE_NON_TRANSP_6k0: return RSL_CMOD_CSD_NT_6k0; case GSM0808_DATA_RATE_NON_TRANSP_43k5: return RSL_CMOD_CSD_NT_43k5; case GSM0808_DATA_RATE_NON_TRANSP_29k0: return RSL_CMOD_CSD_NT_28k8; default: LOGP(DMSC, LOGL_ERROR, "Unsupported non-transparent data rate 0x%x\n", rate); return -1; } } static enum gsm48_chan_mode match_non_transp_data_rate(const struct gsm0808_channel_type *ct, bool full_rate) { /* FIXME: Handle ct->data_rate_allowed too if it is set. Find the best * match by comparing the preferred ct->data_rate + all allowed * ct->data_rate_allowed against what's most suitable for the BTS. */ return gsm0808_data_rate_non_transp_to_gsm0858(ct->data_rate, full_rate); } /*! Match the GSM 08.08 channel type received from the MSC to suitable data for * the BTS, the GSM 04.08 channel mode, channel rate (FR/HR) and GSM 08.58 * data rate. * \param[out] ch_mode_rate resulting channel rate, channel mode and data rate * \param[in] ct GSM 08.08 channel type received from MSC. * \param[in] full_rate true means FR is preferred, false means HR * \returns 0 on success, -1 in case no match was found */ int match_data_rate_pref(struct channel_mode_and_rate *ch_mode_rate, const struct gsm0808_channel_type *ct, const bool full_rate) { int rc; *ch_mode_rate = (struct channel_mode_and_rate){}; ch_mode_rate->chan_rate = full_rate ? CH_RATE_FULL : CH_RATE_HALF; ch_mode_rate->data_transparent = ct->data_transparent; if (ct->data_transparent) { rc = gsm0808_data_rate_transp_to_gsm0858(ct->data_rate); if (rc == -1) return -1; ch_mode_rate->data_rate.t = rc; rc = gsm0808_data_rate_transp_to_gsm0408(ct->data_rate); if (rc == -1) return -1; ch_mode_rate->chan_mode = rc; } else { rc = match_non_transp_data_rate(ct, full_rate); if (rc == -1) return -1; ch_mode_rate->data_rate.nt = rc; rc = gsm0808_data_rate_non_transp_to_gsm0408(ct->data_rate, full_rate); if (rc == -1) return -1; ch_mode_rate->chan_mode = rc; } return 0; }