summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-03-27 18:40:21 +0800
committerHarald Welte <laforge@gnumonks.org>2010-03-27 18:42:43 +0800
commit1e4d22cb5f66352e23ef05212035bd29bfb7d6e1 (patch)
treea037679bfe868ff7675433e771216216942ef68c
parent413b10e33ea9c86555e87809816fc1fbeb7f1959 (diff)
Implement L23-triggered L1 power measurement scan
Now layer23 can ask L1 to scan an entire range of ARFCN's and do power measurements. This is the first step in the cell (re)selection process.
-rw-r--r--include/l1a_l23_interface.h11
-rw-r--r--src/host/layer23/include/osmocom/l1ctl.h4
-rw-r--r--src/host/layer23/src/l1ctl.c56
-rw-r--r--src/target/firmware/include/layer1/l23_api.h1
-rw-r--r--src/target/firmware/include/layer1/sync.h13
-rw-r--r--src/target/firmware/layer1/l23_api.c38
-rw-r--r--src/target/firmware/layer1/sync.c41
7 files changed, 141 insertions, 23 deletions
diff --git a/include/l1a_l23_interface.h b/include/l1a_l23_interface.h
index 64ede925..e9def59c 100644
--- a/include/l1a_l23_interface.h
+++ b/include/l1a_l23_interface.h
@@ -32,8 +32,9 @@
#define L1CTL_DATA_REQ 7
#define L1CTL_RESET 8
#define L1CTL_PM_REQ 9 /* power measurement */
-#define L1CTL_ECHO_REQ 10
-#define L1CTL_ECHO_RESP 11
+#define L1CTL_PM_RESP 10 /* power measurement */
+#define L1CTL_ECHO_REQ 11
+#define L1CTL_ECHO_RESP 12
/*
* NOTE: struct size. We do add manual padding out of the believe
@@ -138,4 +139,10 @@ struct l1ctl_pm_req {
};
} __attribute__((packed));
+/* a single L1CTL_PM response */
+struct l1ctl_pm_resp {
+ uint16_t band_arfcn;
+ uint8_t pm[2];
+} __attribute__((packed));
+
#endif
diff --git a/src/host/layer23/include/osmocom/l1ctl.h b/src/host/layer23/include/osmocom/l1ctl.h
index e4e76c05..d0ff8867 100644
--- a/src/host/layer23/include/osmocom/l1ctl.h
+++ b/src/host/layer23/include/osmocom/l1ctl.h
@@ -21,6 +21,10 @@ int tx_ph_dm_est_req(struct osmocom_ms *ms, uint16_t band_arfcn, uint8_t chan_nr
int l1ctl_tx_echo_req(struct osmocom_ms *ms, unsigned int len);
+/* Transmit L1CTL_PM_REQ */
+int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from,
+ uint16_t arfcm_to);
+
extern int osmo_send_l1(struct osmocom_ms *ms, struct msgb *msg);
diff --git a/src/host/layer23/src/l1ctl.c b/src/host/layer23/src/l1ctl.c
index 97009cb2..ada7ec8d 100644
--- a/src/host/layer23/src/l1ctl.c
+++ b/src/host/layer23/src/l1ctl.c
@@ -212,6 +212,22 @@ int tx_ph_data_req(struct osmocom_ms *ms, struct msgb *msg,
return osmo_send_l1(ms, msg);
}
+/* Transmit NEW_CCCH_REQ */
+int l1ctl_tx_ccch_req(struct osmocom_ms *ms)
+{
+ struct msgb *msg;
+ struct l1ctl_sync_new_ccch_req *req;
+
+ msg = osmo_l1_alloc(L1CTL_NEW_CCCH_REQ);
+ if (!msg)
+ return -1;
+
+ req = (struct l1ctl_sync_new_ccch_req *) msgb_put(msg, sizeof(*req));
+ req->band_arfcn = osmo_make_band_arfcn(ms);
+
+ return osmo_send_l1(ms, msg);
+}
+
/* Transmit L1CTL_RACH_REQ */
int tx_ph_rach_req(struct osmocom_ms *ms)
{
@@ -272,23 +288,46 @@ int l1ctl_tx_echo_req(struct osmocom_ms *ms, unsigned int len)
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");
+ //return l1ctl_tx_pm_req_range(ms, 0, 124);
+ return l1ctl_tx_ccch_req(ms);
+}
+
+/* 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++) {
+ DEBUGP(DL1C, "PM MEAS: ARFCN: %4u RxLev: %3d %3d\n",
+ ntohs(pmr->band_arfcn), pmr->pm[0], pmr->pm[1]);
+ }
+ return 0;
+}
/* Receive incoming data from L1 using L1CTL format */
int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
@@ -319,6 +358,9 @@ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
case L1CTL_RESET:
rc = rx_l1_reset(ms);
break;
+ case L1CTL_PM_RESP:
+ rc = rx_l1_pm_resp(ms, msg);
+ break;
default:
fprintf(stderr, "Unknown MSG: %u\n", l1h->msg_type);
break;
diff --git a/src/target/firmware/include/layer1/l23_api.h b/src/target/firmware/include/layer1/l23_api.h
index 69d4203a..66efce5d 100644
--- a/src/target/firmware/include/layer1/l23_api.h
+++ b/src/target/firmware/include/layer1/l23_api.h
@@ -7,6 +7,7 @@
void l1a_l23api_init(void);
void l1_queue_for_l2(struct msgb *msg);
+struct msgb *l1ctl_msgb_alloc(uint8_t msg_type);
struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr, uint16_t arfcn);
#endif /* _L1_L23_API_H */
diff --git a/src/target/firmware/include/layer1/sync.h b/src/target/firmware/include/layer1/sync.h
index 6bdb57ac..f13d5a97 100644
--- a/src/target/firmware/include/layer1/sync.h
+++ b/src/target/firmware/include/layer1/sync.h
@@ -37,6 +37,19 @@ struct l1s_state {
uint32_t mf_tasks;
struct {
+ /* power measurement l1 task */
+ unsigned int mode;
+ union {
+ struct {
+ uint16_t arfcn_start;
+ uint16_t arfcn_next;
+ uint16_t arfcn_end;
+ } range;
+ };
+ struct msgb *msg;
+ } pm;
+
+ struct {
uint8_t ra;
} rach;
};
diff --git a/src/target/firmware/layer1/l23_api.c b/src/target/firmware/layer1/l23_api.c
index e1c3591c..d17c8c46 100644
--- a/src/target/firmware/layer1/l23_api.c
+++ b/src/target/firmware/layer1/l23_api.c
@@ -79,14 +79,12 @@ static enum mframe_task chan_nr2mf_task(uint8_t chan_nr)
return 0;
}
-struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
- uint16_t arfcn)
+struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
{
- struct l1ctl_hdr *l1h;
- struct l1ctl_info_dl *dl;
struct msgb *msg;
+ struct l1ctl_hdr *l1h;
- msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1_burst");
+ msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
if (!msg) {
while (1) {
puts("OOPS. Out of buffers...\n");
@@ -94,10 +92,18 @@ struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
return NULL;
}
-
l1h = (struct l1ctl_hdr *) msgb_put(msg, sizeof(*l1h));
l1h->msg_type = msg_type;
+ return msg;
+}
+
+struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
+ uint16_t arfcn)
+{
+ struct l1ctl_info_dl *dl;
+ struct msgb *msg = l1ctl_msgb_alloc(msg_type);
+
dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
dl->frame_nr = htonl(fn);
dl->snr = snr;
@@ -106,12 +112,27 @@ struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
return msg;
}
+/* receive a L1CTL_PM_REQ from L23 */
void l1ctl_rx_pm_req(struct msgb *msg)
{
struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *) l1h->data;
- /* FIXME */
+ switch (pm_req->type) {
+ case 1:
+ l1s.pm.mode = 1;
+ l1s.pm.range.arfcn_start =
+ ntohs(pm_req->range.band_arfcn_from);
+ l1s.pm.range.arfcn_next =
+ ntohs(pm_req->range.band_arfcn_from);
+ l1s.pm.range.arfcn_end =
+ ntohs(pm_req->range.band_arfcn_to);
+ printf("L1CTL_PM_REQ start=%u end=%u\n",
+ l1s.pm.range.arfcn_start, l1s.pm.range.arfcn_end);
+ break;
+ }
+
+ l1s_pm_test(1, l1s.pm.range.arfcn_next);
}
/* callback from SERCOMM when L2 sends a message to L1 */
@@ -127,7 +148,7 @@ static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
{
int i;
- puts("l1a_l23_rx_cb: ");
+ printf("l1a_l23_rx_cb (%u): ", msg->len);
for (i = 0; i < msg->len; i++)
printf("%02x ", msg->data[i]);
puts("\n");
@@ -202,7 +223,6 @@ static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
/* we have to keep the msgb, not free it! */
goto exit_nofree;
case L1CTL_PM_REQ:
- printd("L1CTL_PM_REQ\n");
l1ctl_rx_pm_req(msg);
break;
}
diff --git a/src/target/firmware/layer1/sync.c b/src/target/firmware/layer1/sync.c
index e80756a5..a6049642 100644
--- a/src/target/firmware/layer1/sync.c
+++ b/src/target/firmware/layer1/sync.c
@@ -30,6 +30,7 @@
#include <defines.h>
#include <debug.h>
#include <memory.h>
+#include <byteorder.h>
#include <osmocore/gsm_utils.h>
#include <osmocore/msgb.h>
#include <calypso/dsp_api.h>
@@ -773,8 +774,9 @@ static int l1s_pm_cmd(__unused uint8_t p1,
/* scheduler callback to read power measurement resposnse from the DSP */
static int l1s_pm_resp(__unused uint8_t p1, __unused uint8_t p2,
- __unused uint16_t p3)
+ uint16_t arfcn)
{
+ struct l1ctl_pm_resp *pmr;
uint16_t pm_level[2];
struct l1_signal sig;
@@ -782,26 +784,55 @@ static int l1s_pm_resp(__unused uint8_t p1, __unused uint8_t p2,
l1ddsp_meas_read(2, pm_level);
- printd("PM MEAS: %-4d dBm, %-4d dBm ARFCN=%u\n",
+ printf("PM MEAS: %-4d dBm, %-4d dBm ARFCN=%u\n",
agc_inp_dbm8_by_pm(pm_level[0])/8,
- agc_inp_dbm8_by_pm(pm_level[1])/8, rf_arfcn);
+ agc_inp_dbm8_by_pm(pm_level[1])/8, arfcn);
/* build and deliver signal */
sig.signum = L1_SIG_PM;
- sig.arfcn = rf_arfcn;
+ sig.arfcn = arfcn;
sig.pm.dbm8[0] = agc_inp_dbm8_by_pm(pm_level[0]);
sig.pm.dbm8[1] = agc_inp_dbm8_by_pm(pm_level[1]);
if (l1s_cb)
l1s_cb(&sig);
+ if (!l1s.pm.msg)
+ l1s.pm.msg = l1ctl_msgb_alloc(L1CTL_PM_RESP);
+
+ if (msgb_tailroom(l1s.pm.msg) < sizeof(*pmr)) {
+ /* flush current msgb */
+ l1_queue_for_l2(l1s.pm.msg);
+ /* allocate a new msgb and initialize header */
+ l1s.pm.msg = l1ctl_msgb_alloc(L1CTL_PM_RESP);
+ }
+
+ pmr = msgb_put(l1s.pm.msg, sizeof(*pmr));
+ pmr->band_arfcn = htons(arfcn);
+ /* FIXME: do this as RxLev rather than DBM8 ? */
+ pmr->pm[0] = dbm2rxlev(agc_inp_dbm8_by_pm(pm_level[0])/8);
+ pmr->pm[1] = dbm2rxlev(agc_inp_dbm8_by_pm(pm_level[1])/8);
+
+ if (l1s.pm.mode == 1) {
+ if (l1s.pm.range.arfcn_next < l1s.pm.range.arfcn_end) {
+ /* schedule PM for next ARFCN in range */
+ l1s_pm_test(1, l1s.pm.range.arfcn_next);
+ l1s.pm.range.arfcn_next++;
+ } else {
+ /* we have finished, flush the msgb to L2 */
+ l1_queue_for_l2(l1s.pm.msg);
+ l1s.pm.msg = NULL;
+ }
+ }
+
return 0;
}
void l1s_pm_test(uint8_t base_fn, uint16_t arfcn)
{
+ printf("l1s_pm_test(%u, %u)\n", base_fn, arfcn);
tdma_schedule(base_fn, &l1s_pm_cmd, 0, 0, arfcn);
- tdma_schedule(base_fn + 2, &l1s_pm_resp, 0, 0, 0);
+ tdma_schedule(base_fn + 2, &l1s_pm_resp, 0, 0, arfcn);
}
/* Normal Burst ***************************************************************/