From 0a1da468691703071521960fc5c350922c93695f Mon Sep 17 00:00:00 2001 From: Vadim Yanitskiy Date: Thu, 1 Mar 2018 17:30:47 +0700 Subject: trxcon/scheduler: add PDTCH channel support Change-Id: I1176576f54c1d68e79cc6ac37d61a9033f7018dd --- src/host/trxcon/Makefile.am | 1 + src/host/trxcon/sched_lchan_desc.c | 10 +- src/host/trxcon/sched_lchan_pdtch.c | 204 ++++++++++++++++++++++++++++++++++++ src/host/trxcon/sched_trx.h | 3 + 4 files changed, 214 insertions(+), 4 deletions(-) create mode 100644 src/host/trxcon/sched_lchan_pdtch.c (limited to 'src') diff --git a/src/host/trxcon/Makefile.am b/src/host/trxcon/Makefile.am index 7095cb59..b51db02f 100644 --- a/src/host/trxcon/Makefile.am +++ b/src/host/trxcon/Makefile.am @@ -32,6 +32,7 @@ trxcon_SOURCES = \ # Scheduler trxcon_SOURCES += \ sched_lchan_common.c \ + sched_lchan_pdtch.c \ sched_lchan_desc.c \ sched_lchan_xcch.c \ sched_lchan_tchf.c \ diff --git a/src/host/trxcon/sched_lchan_desc.c b/src/host/trxcon/sched_lchan_desc.c index 8b2b5e10..93639a37 100644 --- a/src/host/trxcon/sched_lchan_desc.c +++ b/src/host/trxcon/sched_lchan_desc.c @@ -25,10 +25,6 @@ #include "sched_trx.h" -/* TODO: implement */ -#define tx_pdtch_fn NULL -#define rx_pdtch_fn NULL - /* Forward declaration of handlers */ int rx_data_fn(struct trx_instance *trx, struct trx_ts *ts, struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid, @@ -58,6 +54,12 @@ int rx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts, int tx_tchh_fn(struct trx_instance *trx, struct trx_ts *ts, struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid); +int rx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts, + struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid, + sbit_t *bits, int8_t rssi, int16_t toa256); + +int tx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts, + struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid); const struct trx_lchan_desc trx_lchan_desc[_TRX_CHAN_MAX] = { { diff --git a/src/host/trxcon/sched_lchan_pdtch.c b/src/host/trxcon/sched_lchan_pdtch.c new file mode 100644 index 00000000..1a8987b3 --- /dev/null +++ b/src/host/trxcon/sched_lchan_pdtch.c @@ -0,0 +1,204 @@ +/* + * OsmocomBB <-> SDR connection bridge + * TDMA scheduler: handlers for DL / UL bursts on logical channels + * + * (C) 2018 by Vadim Yanitskiy + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "l1ctl_proto.h" +#include "scheduler.h" +#include "sched_trx.h" +#include "logging.h" +#include "trx_if.h" +#include "trxcon.h" +#include "l1ctl.h" + +int rx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts, + struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid, + sbit_t *bits, int8_t rssi, int16_t toa256) +{ + const struct trx_lchan_desc *lchan_desc; + uint8_t l2[GPRS_L2_MAX_LEN], *mask; + int n_errors, n_bits_total, rc; + sbit_t *buffer, *offset; + uint32_t *first_fn; + size_t l2_len; + + /* Set up pointers */ + lchan_desc = &trx_lchan_desc[lchan->type]; + first_fn = &lchan->rx_first_fn; + mask = &lchan->rx_burst_mask; + buffer = lchan->rx_bursts; + + LOGP(DSCHD, LOGL_DEBUG, "Packet data received on %s: " + "fn=%u ts=%u bid=%u\n", lchan_desc->name, fn, ts->index, bid); + + /* Reset internal state */ + if (bid == 0) { + /* Clean up old measurements */ + memset(&lchan->meas, 0x00, sizeof(lchan->meas)); + + *first_fn = fn; + *mask = 0x0; + } + + /* Update mask */ + *mask |= (1 << bid); + + /* Update measurements */ + lchan->meas.toa256_sum += toa256; + lchan->meas.rssi_sum += rssi; + lchan->meas.toa256_num++; + lchan->meas.rssi_num++; + + /* Copy burst to buffer of 4 bursts */ + offset = buffer + bid * 116; + memcpy(offset, bits + 3, 58); + memcpy(offset + 58, bits + 87, 58); + + /* Wait until complete set of bursts */ + if (bid != 3) + return 0; + + /* Check for complete set of bursts */ + if ((*mask & 0xf) != 0xf) { + LOGP(DSCHD, LOGL_ERROR, "Received incomplete data frame at " + "fn=%u (%u/%u) for %s\n", *first_fn, + (*first_fn) % ts->mf_layout->period, + ts->mf_layout->period, + lchan_desc->name); + + return -1; + } + + /* Attempt to decode */ + rc = gsm0503_pdtch_decode(l2, buffer, + NULL, &n_errors, &n_bits_total); + if (rc < 0) { + LOGP(DSCHD, LOGL_ERROR, "Received bad packet data frame " + "at fn=%u (%u/%u) for %s\n", *first_fn, + (*first_fn) % ts->mf_layout->period, + ts->mf_layout->period, + lchan_desc->name); + } + + /* Determine L2 length */ + l2_len = rc > 0 ? rc : 0; + + /* Send a L2 frame to the higher layers */ + sched_send_dt_ind(trx, ts, lchan, + l2, l2_len, n_errors, rc < 0, true); + + return 0; +} + + +int tx_pdtch_fn(struct trx_instance *trx, struct trx_ts *ts, + struct trx_lchan_state *lchan, uint32_t fn, uint8_t bid) +{ + const struct trx_lchan_desc *lchan_desc; + ubit_t burst[GSM_BURST_LEN]; + ubit_t *buffer, *offset; + const uint8_t *tsc; + uint8_t *mask; + int rc; + + /* Set up pointers */ + lchan_desc = &trx_lchan_desc[lchan->type]; + mask = &lchan->tx_burst_mask; + buffer = lchan->tx_bursts; + + if (bid > 0) { + /* If we have encoded bursts */ + if (*mask) + goto send_burst; + else + return 0; + } + + /* Encode payload */ + rc = gsm0503_pdtch_encode(buffer, lchan->prim->payload, + lchan->prim->payload_len); + if (rc) { + LOGP(DSCHD, LOGL_ERROR, "Failed to encode L2 payload\n"); + + /* Forget this primitive */ + sched_prim_drop(lchan); + + return -EINVAL; + } + +send_burst: + /* Determine which burst should be sent */ + offset = buffer + bid * 116; + + /* Update mask */ + *mask |= (1 << bid); + + /* Choose proper TSC */ + tsc = sched_nb_training_bits[trx->tsc]; + + /* Compose a new burst */ + memset(burst, 0, 3); /* TB */ + memcpy(burst + 3, offset, 58); /* Payload 1/2 */ + memcpy(burst + 61, tsc, 26); /* TSC */ + memcpy(burst + 87, offset + 58, 58); /* Payload 2/2 */ + memset(burst + 145, 0, 3); /* TB */ + + LOGP(DSCHD, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u burst=%u\n", + lchan_desc->name, fn, ts->index, bid); + + /* Forward burst to scheduler */ + rc = sched_trx_handle_tx_burst(trx, ts, lchan, fn, burst); + if (rc) { + /* Forget this primitive */ + sched_prim_drop(lchan); + + /* Reset mask */ + *mask = 0x00; + + return rc; + } + + /* If we have sent the last (4/4) burst */ + if ((*mask & 0x0f) == 0x0f) { + /* Confirm data / traffic sending */ + sched_send_dt_conf(trx, ts, lchan, fn, true); + + /* Forget processed primitive */ + sched_prim_drop(lchan); + + /* Reset mask */ + *mask = 0x00; + } + + return 0; +} diff --git a/src/host/trxcon/sched_trx.h b/src/host/trxcon/sched_trx.h index 1f0dbc29..b7236d51 100644 --- a/src/host/trxcon/sched_trx.h +++ b/src/host/trxcon/sched_trx.h @@ -17,6 +17,9 @@ #define GPRS_BURST_LEN GSM_BURST_LEN #define EDGE_BURST_LEN 444 +#define GPRS_L2_MAX_LEN 54 +#define EDGE_L2_MAX_LEN 155 + #define TRX_CH_LID_DEDIC 0x00 #define TRX_CH_LID_SACCH 0x40 -- cgit v1.2.3