/* * (C) 2013 by Andreas Eversberg * (C) 2015-2017 by Harald Welte * Contributions by sysmocom - s.f.m.c. GmbH * * 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 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 #include #include #include #include #include #include /* Maximum size of a EGPRS message in bytes */ #define EGPRS_0503_MAX_BYTES 155 /*! \brief a single PDTCH burst was received by the PHY, process it */ int rx_pdtch_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi) { struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan]; sbit_t *burst, *bursts_p = chan_state->ul_bursts; uint32_t first_fn; uint32_t *mask = &chan_state->ul_mask; struct l1sched_meas_set meas_avg; uint8_t l2[EGPRS_0503_MAX_BYTES]; int n_errors = 0; int n_bursts_bits = 0; int n_bits_total = 0; uint16_t ber10k; int rc; enum osmo_ph_pres_info_type presence_info; LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received PDTCH bid=%u\n", bi->bid); /* An MS may be polled to send an ACK in form of four Access Bursts */ if (bi->flags & TRX_BI_F_ACCESS_BURST) return rx_rach_fn(l1ts, bi); /* clear burst */ if (bi->bid == 0) { memset(bursts_p, 0, GSM0503_EGPRS_BURSTS_NBITS); *mask = 0x0; } /* update mask */ *mask |= (1 << bi->bid); /* store measurements */ trx_sched_meas_push(chan_state, bi); /* copy burst to buffer of 4 bursts */ switch (bi->burst_len) { case EGPRS_BURST_LEN: burst = bursts_p + bi->bid * 348; memcpy(burst, bi->burst + 9, 174); memcpy(burst + 174, bi->burst + 261, 174); n_bursts_bits = GSM0503_EGPRS_BURSTS_NBITS; break; case GSM_BURST_LEN: burst = bursts_p + bi->bid * 116; memcpy(burst, bi->burst + 3, 58); memcpy(burst + 58, bi->burst + 87, 58); n_bursts_bits = GSM0503_GPRS_BURSTS_NBITS; break; case 0: /* NOPE.ind, assume GPRS? */ n_bursts_bits = GSM0503_GPRS_BURSTS_NBITS; } /* wait until complete set of bursts */ if (bi->bid != 3) return 0; /* average measurements of the last 4 bursts */ trx_sched_meas_avg(chan_state, &meas_avg, SCHED_MEAS_AVG_M_S4N4); /* check for complete set of bursts */ if ((*mask & 0xf) != 0xf) { LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received incomplete frame (%u/%u)\n", bi->fn % l1ts->mf_period, l1ts->mf_period); } *mask = 0x0; /* * Attempt to decode EGPRS bursts first. For 8-PSK EGPRS this is all we * do. Attempt GPRS decoding on EGPRS failure. If the burst is GPRS, * then we incur decoding overhead of 31 bits on the Type 3 EGPRS * header, which is tolerable. */ rc = gsm0503_pdtch_egprs_decode(l2, bursts_p, n_bursts_bits, NULL, &n_errors, &n_bits_total); if ((bi->burst_len == GSM_BURST_LEN) && (rc < 0)) { rc = gsm0503_pdtch_decode(l2, bursts_p, NULL, &n_errors, &n_bits_total); } if (rc > 0) { presence_info = PRES_INFO_BOTH; } else { LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, BAD_DATA_MSG_FMT "\n", BAD_DATA_MSG_ARGS); rc = 0; presence_info = PRES_INFO_INVALID; } ber10k = compute_ber10k(n_bits_total, n_errors); first_fn = GSM_TDMA_FN_SUB(bi->fn, 3); return _sched_compose_ph_data_ind(l1ts, first_fn, bi->chan, &l2[0], rc, ber10k, meas_avg.rssi, meas_avg.toa256, meas_avg.ci_cb, presence_info); } /* obtain a to-be-transmitted PDTCH (packet data) burst */ int tx_pdtch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br) { struct msgb *msg = NULL; /* make GCC happy */ struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan]; ubit_t *burst, *bursts_p = chan_state->dl_bursts; enum trx_mod_type *mod = &chan_state->dl_mod_type; uint8_t *mask = &chan_state->dl_mask; int rc = 0; /* send burst, if we already got a frame */ if (br->bid > 0) { if ((*mask & 0x01) != 0x01) return -ENOMSG; goto send_burst; } *mask = *mask << 4; /* get mac block from queue */ msg = _sched_dequeue_prim(l1ts, br); if (!msg) { /* It's totally fine to get no block here, since PCU may submit * empty blocks when there's no MS listening. The scheduler will * take care of filling C0 with dummy bursts to keep expected * power transmit levels */ return -ENODEV; } /* BURST BYPASS */ /* encode bursts */ rc = gsm0503_pdtch_egprs_encode(bursts_p, msg->l2h, msgb_l2len(msg)); if (rc < 0) rc = gsm0503_pdtch_encode(bursts_p, msg->l2h, msgb_l2len(msg)); /* check validity of message */ if (rc < 0) { LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "Prim invalid length, please FIX! " "(len=%u)\n", msgb_l2len(msg)); /* free message */ msgb_free(msg); return -EINVAL; } else if (rc == GSM0503_EGPRS_BURSTS_NBITS) { *mod = TRX_MOD_T_8PSK; } else { *mod = TRX_MOD_T_GMSK; } /* free message */ msgb_free(msg); send_burst: /* compose burst */ if (*mod == TRX_MOD_T_8PSK) { burst = bursts_p + br->bid * 348; memset(br->burst, 1, 9); memcpy(br->burst + 9, burst, 174); memcpy(br->burst + 183, TRX_8PSK_NB_TSC(br), 78); memcpy(br->burst + 261, burst + 174, 174); memset(br->burst + 435, 1, 9); br->burst_len = EGPRS_BURST_LEN; } else { burst = bursts_p + br->bid * 116; memcpy(br->burst + 3, burst, 58); memcpy(br->burst + 61, TRX_GMSK_NB_TSC(br), 26); memcpy(br->burst + 87, burst + 58, 58); br->burst_len = GSM_BURST_LEN; } *mask |= (1 << br->bid); LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting burst=%u.\n", br->bid); return 0; }