#include <l1a_l23_interface.h>
+#include <osmocore/signal.h>
#include <osmocore/logging.h>
#include <osmocore/timer.h>
#include <osmocore/msgb.h>
#include <osmocom/l1ctl.h>
#include <osmocom/osmocom_data.h>
+#include <osmocom/l1l2_interface.h>
#include <osmocom/lapdm.h>
#include <osmocom/logging.h>
#include <osmocom/gsmtap_util.h>
}
-static int osmo_make_band_arfcn(struct osmocom_ms *ms)
+static int osmo_make_band_arfcn(struct osmocom_ms *ms, uint16_t arfcn)
{
/* TODO: Include the band */
- return ms->arfcn;
+ return arfcn;
}
-static int rx_l1_ccch_resp(struct osmocom_ms *ms, struct msgb *msg)
+static int rx_l1_fbsb_resp(struct osmocom_ms *ms, struct msgb *msg)
{
struct l1ctl_info_dl *dl;
- struct l1ctl_sync_new_ccch_resp *sb;
+ struct l1ctl_fbsb_resp *sb;
struct gsm_time tm;
- if (msgb_l3len(msg) < sizeof(*sb)) {
- LOGP(DL1C, LOGL_ERROR, "MSG too short for CCCH RESP: %u\n",
+ if (msgb_l3len(msg) < sizeof(*dl) + sizeof(*sb)) {
+ LOGP(DL1C, LOGL_ERROR, "FBSB RESP: MSG too short %u\n",
msgb_l3len(msg));
return -1;
}
dl = (struct l1ctl_info_dl *) msg->l1h;
- sb = (struct l1ctl_sync_new_ccch_resp *) dl->payload;
+ sb = (struct l1ctl_fbsb_resp *) dl->payload;
+
+ printf("snr=%04x, arfcn=%u result=%u\n", dl->snr, ntohs(dl->band_arfcn),
+ sb->result);
+
+ if (sb->result != 0) {
+ LOGP(DL1C, LOGL_ERROR, "FBSB RESP: result=%u\n", sb->result);
+ dispatch_signal(SS_L1CTL, S_L1CTL_FBSB_ERR, ms);
+ return 0;
+ }
gsm_fn2gsmtime(&tm, ntohl(dl->frame_nr));
DEBUGP(DL1C, "SCH: SNR: %u TDMA: (%.4u/%.2u/%.2u) bsic: %d\n",
dl->snr, tm.t1, tm.t2, tm.t3, sb->bsic);
+ dispatch_signal(SS_L1CTL, S_L1CTL_FBSB_RESP, ms);
return 0;
}
if (msgb_l3len(msg) < sizeof(*ccch)) {
LOGP(DL1C, LOGL_ERROR, "MSG too short Data Ind: %u\n",
msgb_l3len(msg));
+ msgb_free(msg);
return -1;
}
chan_nr2string(dl->chan_nr), tm.t1, tm.t2, tm.t3,
hexdump(ccch->data, sizeof(ccch->data)));
+ if (dl->num_biterr) {
+ LOGP(DL1C, LOGL_NOTICE, "Dropping frame with %u bit errors\n",
+ dl->num_biterr);
+ return 0;
+ }
+
/* send CCCH data via GSMTAP */
gsmtap_chan_type = chantype_rsl2gsmtap(chan_type, dl->link_id);
gsmtap_sendmsg(dl->band_arfcn, chan_ts, gsmtap_chan_type, chan_ss,
/* determine LAPDm entity based on SACCH or not */
if (dl->link_id & 0x40)
- le = &ms->lapdm_acch;
+ le = &ms->l2_entity.lapdm_acch;
else
- le = &ms->lapdm_dcch;
+ le = &ms->l2_entity.lapdm_dcch;
/* make local stack copy of l1ctl_info_dl, as LAPDm will
* overwrite skb hdr */
memcpy(&dl_cpy, dl, sizeof(dl_cpy));
return osmo_send_l1(ms, msg);
}
+/* Transmit FBSB_REQ */
+int l1ctl_tx_fbsb_req(struct osmocom_ms *ms, uint16_t arfcn,
+ uint8_t flags, uint16_t timeout, uint8_t sync_info_idx)
+{
+ struct msgb *msg;
+ struct l1ctl_fbsb_req *req;
+
+ msg = osmo_l1_alloc(L1CTL_FBSB_REQ);
+ if (!msg)
+ return -1;
+
+ req = (struct l1ctl_fbsb_req *) msgb_put(msg, sizeof(*req));
+ req->band_arfcn = htons(osmo_make_band_arfcn(ms, arfcn));
+ req->timeout = htons(timeout);
+ /* Threshold when to consider FB_MODE1: 4kHz - 1kHz */
+ req->freq_err_thresh1 = htons(4000 - 1000);
+ /* Threshold when to consider SCH: 1kHz - 200Hz */
+ req->freq_err_thresh2 = htons(1000 - 200);
+ /* not used yet! */
+ req->num_freqerr_avg = 3;
+ req->flags = flags;
+ req->sync_info_idx = sync_info_idx;
+
+ return osmo_send_l1(ms, msg);
+}
+
/* Transmit L1CTL_RACH_REQ */
int tx_ph_rach_req(struct osmocom_ms *ms)
{
ul->link_id = 0;
ul->tx_power = 0; /* FIXME: initial TX power */
req = (struct l1ctl_dm_est_req *) msgb_put(msg, sizeof(*req));
- req->band_arfcn = band_arfcn;
+ req->band_arfcn = htons(band_arfcn);
return osmo_send_l1(ms, msg);
}
return osmo_send_l1(ms, msg);
}
-/* Receive L1CTL_RESET */
-static int rx_l1_reset(struct osmocom_ms *ms)
+/* Transmit L1CTL_PM_REQ */
+int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from,
+ uint16_t arfcn_to)
{
struct msgb *msg;
- struct l1ctl_sync_new_ccch_req *req;
+ struct l1ctl_pm_req *pm;
- msg = osmo_l1_alloc(L1CTL_NEW_CCCH_REQ);
+ msg = osmo_l1_alloc(L1CTL_PM_REQ);
if (!msg)
return -1;
- LOGP(DL1C, LOGL_INFO, "Layer1 Reset.\n");
- req = (struct l1ctl_sync_new_ccch_req *) msgb_put(msg, sizeof(*req));
- req->band_arfcn = osmo_make_band_arfcn(ms);
+ printf("Tx PM Req (%u-%u)\n", arfcn_from, arfcn_to);
+ pm = (struct l1ctl_pm_req *) msgb_put(msg, sizeof(*pm));
+ pm->type = 1;
+ pm->range.band_arfcn_from = htons(arfcn_from);
+ pm->range.band_arfcn_to = htons(arfcn_to);
return osmo_send_l1(ms, msg);
}
+/* Receive L1CTL_RESET */
+static int rx_l1_reset(struct osmocom_ms *ms)
+{
+ printf("Layer1 Reset.\n");
+ dispatch_signal(SS_L1CTL, S_L1CTL_RESET, ms);
+
+ return 0;
+}
+
+/* Receive L1CTL_PM_RESP */
+static int rx_l1_pm_resp(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct l1ctl_pm_resp *pmr;
+
+ for (pmr = (struct l1ctl_pm_resp *) msg->l1h;
+ (uint8_t *) pmr < msg->tail; pmr++) {
+ struct osmobb_meas_res mr;
+ DEBUGP(DL1C, "PM MEAS: ARFCN: %4u RxLev: %3d %3d\n",
+ ntohs(pmr->band_arfcn), pmr->pm[0], pmr->pm[1]);
+ mr.band_arfcn = ntohs(pmr->band_arfcn);
+ mr.rx_lev = (pmr->pm[0] + pmr->pm[1]) / 2;
+ mr.ms = ms;
+ dispatch_signal(SS_L1CTL, S_L1CTL_PM_RES, &mr);
+ }
+ return 0;
+}
/* Receive incoming data from L1 using L1CTL format */
int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
if (msgb_l2len(msg) < sizeof(*dl)) {
LOGP(DL1C, LOGL_ERROR, "Short Layer2 message: %u\n",
msgb_l2len(msg));
+ msgb_free(msg);
return -1;
}
msg->l1h = l1h->data;
switch (l1h->msg_type) {
- case L1CTL_NEW_CCCH_RESP:
- rc = rx_l1_ccch_resp(ms, msg);
+ case L1CTL_FBSB_RESP:
+ rc = rx_l1_fbsb_resp(ms, msg);
+ msgb_free(msg);
break;
case L1CTL_DATA_IND:
rc = rx_ph_data_ind(ms, msg);
break;
case L1CTL_RESET:
rc = rx_l1_reset(ms);
+ msgb_free(msg);
+ break;
+ case L1CTL_PM_RESP:
+ rc = rx_l1_pm_resp(ms, msg);
+ msgb_free(msg);
+ if (l1h->flags & L1CTL_F_DONE)
+ dispatch_signal(SS_L1CTL, S_L1CTL_PM_DONE, ms);
break;
default:
fprintf(stderr, "Unknown MSG: %u\n", l1h->msg_type);
+ msgb_free(msg);
break;
}