summaryrefslogtreecommitdiffstats
path: root/src/host
diff options
context:
space:
mode:
authorVadim Yanitskiy <axilirator@gmail.com>2017-07-06 13:17:24 +0700
committerVadim Yanitskiy <axilirator@gmail.com>2017-11-19 17:35:07 +0700
commit228d42bc303284a9a7a1a8ad645d690b03ab7a26 (patch)
tree24e13eee47fba81d5319105887d197d3571f41c9 /src/host
parentcf5c10f92a6ba150a40a0432b7faa526a68530eb (diff)
host/trxcon/scheduler: implement xCCH decoding
Diffstat (limited to 'src/host')
-rw-r--r--src/host/trxcon/Makefile.am1
-rw-r--r--src/host/trxcon/l1ctl.c22
-rw-r--r--src/host/trxcon/l1ctl.h3
-rw-r--r--src/host/trxcon/sched_lchan_desc.c6
-rw-r--r--src/host/trxcon/sched_lchan_handlers.c161
-rw-r--r--src/host/trxcon/trxcon.c5
-rw-r--r--src/host/trxcon/trxcon.h1
7 files changed, 197 insertions, 2 deletions
diff --git a/src/host/trxcon/Makefile.am b/src/host/trxcon/Makefile.am
index 1a373f7e..b2f22fab 100644
--- a/src/host/trxcon/Makefile.am
+++ b/src/host/trxcon/Makefile.am
@@ -31,6 +31,7 @@ trxcon_SOURCES = \
# Scheduler
trxcon_SOURCES += \
+ sched_lchan_handlers.c \
sched_lchan_desc.c \
sched_mframe.c \
sched_clck.c \
diff --git a/src/host/trxcon/l1ctl.c b/src/host/trxcon/l1ctl.c
index 0bb26f72..3bcc5cb3 100644
--- a/src/host/trxcon/l1ctl.c
+++ b/src/host/trxcon/l1ctl.c
@@ -123,6 +123,28 @@ int l1ctl_tx_reset_conf(struct l1ctl_link *l1l, uint8_t type)
return l1ctl_link_send(l1l, msg);
}
+int l1ctl_tx_data_ind(struct l1ctl_link *l1l, struct l1ctl_info_dl *data)
+{
+ struct l1ctl_info_dl *dl;
+ struct msgb *msg;
+ size_t len;
+
+ msg = l1ctl_alloc_msg(L1CTL_DATA_IND);
+ if (msg == NULL)
+ return -ENOMEM;
+
+ /* We store the 23-byte payload as a flexible array member */
+ len = sizeof(struct l1ctl_info_dl) + 23;
+ dl = (struct l1ctl_info_dl *) msgb_put(msg, len);
+
+ /* Copy header and data from source message */
+ memcpy(dl, data, len);
+ talloc_free(data);
+
+ /* Put message to upper layers */
+ return l1ctl_link_send(l1l, msg);
+}
+
static int l1ctl_rx_fbsb_req(struct l1ctl_link *l1l, struct msgb *msg)
{
struct l1ctl_fbsb_req *fbsb, *fbsb_copy;
diff --git a/src/host/trxcon/l1ctl.h b/src/host/trxcon/l1ctl.h
index ffd1a81f..05a2c543 100644
--- a/src/host/trxcon/l1ctl.h
+++ b/src/host/trxcon/l1ctl.h
@@ -4,9 +4,12 @@
#include <osmocom/core/msgb.h>
#include "l1ctl_link.h"
+#include "l1ctl_proto.h"
int l1ctl_tx_pm_conf(struct l1ctl_link *l1l, uint16_t band_arfcn,
int dbm, int last);
int l1ctl_tx_reset_conf(struct l1ctl_link *l1l, uint8_t type);
int l1ctl_tx_reset_ind(struct l1ctl_link *l1l, uint8_t type);
int l1ctl_rx_cb(struct l1ctl_link *l1l, struct msgb *msg);
+
+int l1ctl_tx_data_ind(struct l1ctl_link *l1l, struct l1ctl_info_dl *ind);
diff --git a/src/host/trxcon/sched_lchan_desc.c b/src/host/trxcon/sched_lchan_desc.c
index 880c2a59..93927a63 100644
--- a/src/host/trxcon/sched_lchan_desc.c
+++ b/src/host/trxcon/sched_lchan_desc.c
@@ -35,11 +35,15 @@
#define tx_tchh_fn NULL
#define tx_rach_fn NULL
-#define rx_data_fn NULL
#define rx_pdtch_fn NULL
#define rx_tchf_fn NULL
#define rx_tchh_fn NULL
+/* Forward declaration of handlers */
+int rx_data_fn(struct trx_instance *trx, struct trx_ts *ts,
+ uint32_t fn, enum trx_lchan_type chan, uint8_t bid,
+ sbit_t *bits, uint16_t nbits, int8_t rssi, float toa);
+
const struct trx_lchan_desc trx_lchan_desc[_TRX_CHAN_MAX] = {
{
TRXC_IDLE, "IDLE",
diff --git a/src/host/trxcon/sched_lchan_handlers.c b/src/host/trxcon/sched_lchan_handlers.c
new file mode 100644
index 00000000..2c2cb6a7
--- /dev/null
+++ b/src/host/trxcon/sched_lchan_handlers.c
@@ -0,0 +1,161 @@
+/*
+ * OsmocomBB <-> SDR connection bridge
+ * TDMA scheduler: handlers for DL / UL bursts on logical channels
+ *
+ * (C) 2017 by Vadim Yanitskiy <axilirator@gmail.com>
+ *
+ * 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 <errno.h>
+#include <string.h>
+#include <talloc.h>
+#include <stdint.h>
+
+#include <arpa/inet.h>
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/bits.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/fsm.h>
+
+#include <osmocom/coding/gsm0503_coding.h>
+
+#include "l1ctl_proto.h"
+#include "scheduler.h"
+#include "sched_trx.h"
+#include "logging.h"
+#include "trx_if.h"
+#include "trxcon.h"
+
+extern struct osmo_fsm_inst *trxcon_fsm;
+
+int rx_data_fn(struct trx_instance *trx, struct trx_ts *ts,
+ uint32_t fn, enum trx_lchan_type chan, uint8_t bid,
+ sbit_t *bits, uint16_t nbits, int8_t rssi, float toa)
+{
+ int n_errors, n_bits_total, rc;
+ struct trx_lchan_state *lchan;
+ uint8_t *rssi_num, *toa_num;
+ float *rssi_sum, *toa_sum;
+ sbit_t *buffer, *offset;
+ uint8_t l2[23], *mask;
+ uint32_t *first_fn;
+
+ LOGP(DSCH, LOGL_DEBUG, "Data received on %s: fn=%u ts=%u bid=%u\n",
+ trx_lchan_desc[chan].name, fn, ts->index, bid);
+
+ /* Find required channel state */
+ lchan = sched_trx_find_lchan(ts, chan);
+ if (lchan == NULL)
+ return -EINVAL;
+
+ /* Set up pointers */
+ first_fn = &lchan->rx_first_fn;
+ mask = &lchan->rx_burst_mask;
+ buffer = lchan->rx_bursts;
+
+ rssi_sum = &lchan->rssi_sum;
+ rssi_num = &lchan->rssi_num;
+ toa_sum = &lchan->toa_sum;
+ toa_num = &lchan->toa_num;
+
+ /* Clear buffer & store frame number of first burst */
+ if (bid == 0) {
+ memset(buffer, 0, 464);
+
+ *first_fn = fn;
+ *mask = 0x0;
+
+ *rssi_sum = 0;
+ *rssi_num = 0;
+ *toa_sum = 0;
+ *toa_num = 0;
+ }
+
+ /* Update mask and RSSI */
+ *mask |= (1 << bid);
+ *rssi_sum += rssi;
+ (*rssi_num)++;
+ *toa_sum += toa;
+ (*toa_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(DSCH, LOGL_DEBUG, "Received incomplete data frame at "
+ "fn=%u (%u/%u) for %s\n", *first_fn,
+ (*first_fn) % ts->mf_layout->period,
+ ts->mf_layout->period,
+ trx_lchan_desc[chan].name);
+
+ /* We require first burst to have correct FN */
+ if (!(*mask & 0x1)) {
+ *mask = 0x0;
+ return 0;
+ }
+
+ /* FIXME: return from here? */
+ }
+
+ /* Attempt to decode */
+ rc = gsm0503_xcch_decode(l2, buffer, &n_errors, &n_bits_total);
+ if (rc) {
+ LOGP(DSCH, LOGL_DEBUG, "Received bad data frame at fn=%u "
+ "(%u/%u) for %s\n", *first_fn,
+ (*first_fn) % ts->mf_layout->period,
+ ts->mf_layout->period,
+ trx_lchan_desc[chan].name);
+ return rc;
+ }
+
+ /* Compose a message to the higher layers */
+ struct l1ctl_info_dl *data;
+ data = talloc_zero_size(ts, sizeof(struct l1ctl_info_dl) + 23);
+ if (data == NULL)
+ return -ENOMEM;
+
+ /* Fill in some downlink info */
+ data->chan_nr = trx_lchan_desc[chan].chan_nr | ts->index;
+ data->link_id = trx_lchan_desc[chan].link_id;
+ data->band_arfcn = htons(trx->band_arfcn);
+ data->frame_nr = htonl(*first_fn);
+ data->rx_level = -(*rssi_sum / *rssi_num);
+
+ /* FIXME: set proper values */
+ data->num_biterr = n_errors;
+ data->fire_crc = 0;
+ data->snr = 0;
+
+ /* Fill in decoded payload */
+ memcpy(data->payload, l2, 23);
+
+ /* Raise an event to trxcon */
+ osmo_fsm_inst_dispatch(trxcon_fsm, SCH_EVENT_DATA, data);
+
+ /* TODO: AGC, TA loops */
+ return 0;
+}
diff --git a/src/host/trxcon/trxcon.c b/src/host/trxcon/trxcon.c
index 6f50d1a2..32de2536 100644
--- a/src/host/trxcon/trxcon.c
+++ b/src/host/trxcon/trxcon.c
@@ -130,6 +130,8 @@ static void trxcon_fsm_managed_action(struct osmo_fsm_inst *fi,
case L1CTL_EVENT_FBSB_REQ:
trxcon_handle_fbsb_req((struct l1ctl_fbsb_req *) data);
break;
+ case SCH_EVENT_DATA:
+ l1ctl_tx_data_ind(app_data.l1l, (struct l1ctl_info_dl *) data);
case TRX_EVENT_RSP_ERROR:
case TRX_EVENT_OFFLINE:
case SCH_EVENT_CLCK_IND:
@@ -157,7 +159,8 @@ static struct osmo_fsm_state trxcon_fsm_states[] = {
GEN_MASK(TRX_EVENT_RSP_ERROR) |
GEN_MASK(TRX_EVENT_OFFLINE) |
GEN_MASK(SCH_EVENT_CLCK_IND) |
- GEN_MASK(SCH_EVENT_CLCK_LOSS)),
+ GEN_MASK(SCH_EVENT_CLCK_LOSS) |
+ GEN_MASK(SCH_EVENT_DATA)),
.out_state_mask = GEN_MASK(TRXCON_STATE_IDLE),
.name = "MANAGED",
.action = trxcon_fsm_managed_action,
diff --git a/src/host/trxcon/trxcon.h b/src/host/trxcon/trxcon.h
index c266eaee..da777a9d 100644
--- a/src/host/trxcon/trxcon.h
+++ b/src/host/trxcon/trxcon.h
@@ -22,4 +22,5 @@ enum trxcon_fsm_events {
/* Scheduler specific events */
SCH_EVENT_CLCK_IND,
SCH_EVENT_CLCK_LOSS,
+ SCH_EVENT_DATA,
};